diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-09-21 14:32:26 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-09-21 14:32:26 -0700 |
commit | a5b5cabc91c38710adbe5c8a2b53882abe994441 (patch) | |
tree | 66b099a6ebc2076ef353afa90d9703824d023812 /gcc | |
parent | a0791d0ed4f147ef347e83f4aedc7ad03f1a2008 (diff) | |
parent | 09e18d113b3c3dae896ac1a8ad1e0087adbb153b (diff) | |
download | gcc-a5b5cabc91c38710adbe5c8a2b53882abe994441.zip gcc-a5b5cabc91c38710adbe5c8a2b53882abe994441.tar.gz gcc-a5b5cabc91c38710adbe5c8a2b53882abe994441.tar.bz2 |
Merge from trunk revision 09e18d113b3c3dae896ac1a8ad1e0087adbb153b.
Diffstat (limited to 'gcc')
342 files changed, 19825 insertions, 7021 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bb5576a..acbbb71 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,1105 @@ +2021-09-20 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-fold.cc (fold_using_range::range_of_phi): Ignore + undefined edges, apply an equivalence if appropriate. + * gimple-range-gori.cc (gori_compute::outgoing_edge_range_p): Return + UNDEFINED if EDGE_EXECUTABLE is not set. + * gimple-range.cc (gimple_ranger::gimple_ranger): Set all edges + as EXECUTABLE upon startup. + (gimple_ranger::range_on_edge): Return UNDEFINED for edges without + EDGE_EXECUTABLE set. + * vr-values.c (set_and_propagate_unexecutable): New. + (simplify_using_ranges::fold_cond): Call set_and_propagate. + (simplify_using_ranges::simplify_switch_using_ranges): Ditto. + * vr-values.h: Add prototype. + +2021-09-20 Andrew MacLeod <amacleod@redhat.com> + + * value-relation.cc (equiv_oracle::register_initial_def): New. + (equiv_oracle::register_relation): Call register_initial_def. + (equiv_oracle::add_equiv_to_block): New. Split register_relation. + (relation_oracle::register_stmt): Check def block of PHI arguments. + * value-relation.h (equiv_oracle): Add new prototypes. + +2021-09-20 Matthias Kretz <m.kretz@gsi.de> + + * cppbuiltin.c (define_builtin_macros_for_compilation_flags): + Define __RECIPROCAL_MATH__, __NO_SIGNED_ZEROS__, + __NO_TRAPPING_MATH__, __ASSOCIATIVE_MATH__, and + __ROUNDING_MATH__ according to their corresponding flags. + * doc/cpp.texi: Document __RECIPROCAL_MATH__, + __NO_SIGNED_ZEROS__, __NO_TRAPPING_MATH__, __ASSOCIATIVE_MATH__, + and __ROUNDING_MATH__. + +2021-09-20 Richard Biener <rguenther@suse.de> + + * tree-vect-stmts.c (vectorizable_load): Use the vectype + from the SLP node. + +2021-09-20 Richard Biener <rguenther@suse.de> + + * tree-vect-data-refs.c (vect_duplicate_ssa_name_ptr_info): + Do not compute alignment of the vectorized access here. + +2021-09-20 Richard Biener <rguenther@suse.de> + + * tree-vect-data-refs.c (vect_enhance_data_refs_alignment): + Store -1 for runtime alias peeling iterations. + +2021-09-20 Richard Biener <rguenther@suse.de> + + * config.gcc: Obsolete hppa[12]*-*-hpux10* and hppa[12]*-*-hpux11*. + +2021-09-20 Thomas Schwinge <thomas@codesourcery.com> + + * input.c (string_concat_db::record_string_concatenation) + (string_concat_db::get_string_concatenation): Skip for + 'RESERVED_LOCATION_P'. + +2021-09-20 Richard Biener <rguenther@suse.de> + + PR tree-optimization/65206 + * tree-data-ref.h (struct data_reference): Add alt_indices, + order it last. + * tree-data-ref.c (free_data_ref): Release alt_indices. + (dr_analyze_indices): Work on struct indices and get DR_REF as tree. + (create_data_ref): Adjust. + (initialize_data_dependence_relation): Split into head + and tail. When the base objects fail to match up try + again with pointer-based analysis of indices. + * tree-vectorizer.c (vec_info_shared::check_datarefs): Do + not compare the lazily computed alternate set of indices. + +2021-09-20 Iain Sandoe <iain@sandoe.co.uk> + + * gcc.c: Test for execute OK when we find the + programs for assembler linker and dsymutil and those + were specified at configure-time. + +2021-09-19 Martin Sebor <msebor@redhat.com> + + PR middle-end/102403 + * gimple-predicate-analysis.cc (predicate::init_from_control_deps): + Correct a function pre/postcondition. + +2021-09-19 Martin Sebor <msebor@redhat.com> + + PR middle-end/102243 + * tree-ssa-strlen.c (get_range): Handle null cfun. + +2021-09-19 Iain Sandoe <iain@sandoe.co.uk> + + * config/darwin.h (LINK_COMMAND_SPEC_A): Use Darwin10 + unwinder shim as a convenience library. + +2021-09-19 Andrew Pinski <apinski@marvell.com> + + * doc/install.texi: Add note about + binutils 2.35 is required for LTO usage. + +2021-09-19 Aldy Hernandez <aldyh@redhat.com> + + * tree-ssa-threadbackward.c + (back_threader_registry::register_path): Use push_edge. + * tree-ssa-threadedge.c + (jump_threader::thread_around_empty_blocks): Same. + (jump_threader::thread_through_normal_block): Same. + (jump_threader::thread_across_edge): Same. Also, use auto_bitmap. + Tidy up code. + * tree-ssa-threadupdate.c + (jt_path_registry::allocate_thread_edge): Remove. + (jt_path_registry::push_edge): New. + (dump_jump_thread_path): Make static. + * tree-ssa-threadupdate.h (allocate_thread_edge): Remove. + (push_edge): New. + +2021-09-19 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-path.cc (path_range_query::path_range_query): Add + header. + (path_range_query::dump): Remove extern declaration of dump_ranger. + * gimple-range-trace.cc (dump_ranger): Add DEBUG_FUNCTION marker. + * gimple-range-trace.h (dump_ranger): Add prototype. + +2021-09-19 John Ericson <git@JohnEricson.me> + + * gcc.c (find_a_program): New function, factored out of... + (find_a_file): Here. + (execute): Use find_a_program when looking for programs rather + than find_a_file. + +2021-09-19 Matwey V. Kornilov <matwey.kornilov@gmail.com> + + * config/avr/avr-mcus.def: Add atmega324pb. + * doc/avr-mmcu.texi: Corresponding changes. + +2021-09-19 Roger Sayle <roger@nextmovesoftware.com> + + PR middle-end/88173 + * match.pd (cmp @0 REAL_CST@1): When @0 is also REAL_CST, apply + the same transformations as to @1. For comparisons against NaN, + don't check HONOR_SNANS but confirm that neither operand is a + signaling NaN. + +2021-09-19 Benjamin Peterson <benjamin@locrian.net> + + * attribs.c (make_unique_name): Delete. + * attribs.h (make_unique_name): Delete. + +2021-09-19 Andrew Pinski <apinski@marvell.com> + + * lra-constraints.c (check_and_process_move): Assert + that dclass and sclass are greater than or equal to NO_REGS. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * tree.h (OMP_CLAUSE_ORDER_UNCONSTRAINED): Define. + * tree-pretty-print.c (dump_omp_clause): Print unconstrained: + for OMP_CLAUSE_ORDER_UNCONSTRAINED. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * config/i386/i386-features.c (remove_partial_avx_dependency): + Restrict TARGET_USE_VECTOR_FP_CONVERTS and + TARGET_USE_VECTOR_CONVERTS to conversion instructions only. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * gimplify.c (omp_default_clause): For C/C++ default({,first}private), + if file/namespace scope variable doesn't have predetermined sharing, + treat it as if there was default(none). + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm_fmadd_sh): + New intrinsic. + (_mm_mask_fmadd_sh): Likewise. + (_mm_mask3_fmadd_sh): Likewise. + (_mm_maskz_fmadd_sh): Likewise. + (_mm_fmadd_round_sh): Likewise. + (_mm_mask_fmadd_round_sh): Likewise. + (_mm_mask3_fmadd_round_sh): Likewise. + (_mm_maskz_fmadd_round_sh): Likewise. + (_mm_fnmadd_sh): Likewise. + (_mm_mask_fnmadd_sh): Likewise. + (_mm_mask3_fnmadd_sh): Likewise. + (_mm_maskz_fnmadd_sh): Likewise. + (_mm_fnmadd_round_sh): Likewise. + (_mm_mask_fnmadd_round_sh): Likewise. + (_mm_mask3_fnmadd_round_sh): Likewise. + (_mm_maskz_fnmadd_round_sh): Likewise. + (_mm_fmsub_sh): Likewise. + (_mm_mask_fmsub_sh): Likewise. + (_mm_mask3_fmsub_sh): Likewise. + (_mm_maskz_fmsub_sh): Likewise. + (_mm_fmsub_round_sh): Likewise. + (_mm_mask_fmsub_round_sh): Likewise. + (_mm_mask3_fmsub_round_sh): Likewise. + (_mm_maskz_fmsub_round_sh): Likewise. + (_mm_fnmsub_sh): Likewise. + (_mm_mask_fnmsub_sh): Likewise. + (_mm_mask3_fnmsub_sh): Likewise. + (_mm_maskz_fnmsub_sh): Likewise. + (_mm_fnmsub_round_sh): Likewise. + (_mm_mask_fnmsub_round_sh): Likewise. + (_mm_mask3_fnmsub_round_sh): Likewise. + (_mm_maskz_fnmsub_round_sh): Likewise. + * config/i386/i386-builtin-types.def + (V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT): New builtin type. + * config/i386/i386-builtin.def: Add new builtins. + * config/i386/i386-expand.c: Handle new builtin type. + * config/i386/sse.md (fmai_vmfmadd_<mode><round_name>): + Ajdust to support FP16. + (fmai_vmfmsub_<mode><round_name>): Ditto. + (fmai_vmfnmadd_<mode><round_name>): Ditto. + (fmai_vmfnmsub_<mode><round_name>): Ditto. + (*fmai_fmadd_<mode>): Ditto. + (*fmai_fmsub_<mode>): Ditto. + (*fmai_fnmadd_<mode><round_name>): Ditto. + (*fmai_fnmsub_<mode><round_name>): Ditto. + (avx512f_vmfmadd_<mode>_mask<round_name>): Ditto. + (avx512f_vmfmadd_<mode>_mask3<round_name>): Ditto. + (avx512f_vmfmadd_<mode>_maskz<round_expand_name>): Ditto. + (avx512f_vmfmadd_<mode>_maskz_1<round_name>): Ditto. + (*avx512f_vmfmsub_<mode>_mask<round_name>): Ditto. + (avx512f_vmfmsub_<mode>_mask3<round_name>): Ditto. + (*avx512f_vmfmsub_<mode>_maskz_1<round_name>): Ditto. + (*avx512f_vmfnmsub_<mode>_mask<round_name>): Ditto. + (*avx512f_vmfnmsub_<mode>_mask3<round_name>): Ditto. + (*avx512f_vmfnmsub_<mode>_mask<round_name>): Ditto. + (*avx512f_vmfnmadd_<mode>_mask<round_name>): Renamed to ... + (avx512f_vmfnmadd_<mode>_mask<round_name>) ... this, and + adjust to support FP16. + (avx512f_vmfnmadd_<mode>_mask3<round_name>): Ditto. + (avx512f_vmfnmadd_<mode>_maskz_1<round_name>): Ditto. + (avx512f_vmfnmadd_<mode>_maskz<round_expand_name>): New + expander. + +2021-09-18 H.J. Lu <hjl.tools@gmail.com> + + * config/i386/sse.md (avx512fmaskmodelower): Extend to support + HF modes. + (maskload<mode><avx512fmaskmodelower>): Ditto. + (maskstore<mode><avx512fmaskmodelower>): Ditto. + +2021-09-18 H.J. Lu <hjl.tools@gmail.com> + + * config/i386/i386-expand.c (ix86_expand_fp_absneg_operator): + Handle HFmode. + (ix86_expand_copysign): Ditto. + (ix86_expand_xorsign): Ditto. + * config/i386/i386.c (ix86_build_const_vector): Handle HF vector + modes. + (ix86_build_signbit_mask): Ditto. + (ix86_can_change_mode_class): Ditto. + * config/i386/i386.md + (SSEMODEF): Add HFmode. + (ssevecmodef): Ditto. + (<code>hf2): New define_expand. + (*<code>hf2_1): New define_insn_and_split. + (copysign<mode>): Extend to support HFmode under AVX512FP16. + (xorsign<mode>): Ditto. + * config/i386/sse.md (VFB): New mode iterator. + (VFB_128_256): Ditto. + (VFB_512): Ditto. + (sseintvecmode2): Support HF vector mode. + (<code><mode>2): Use new mode iterator. + (*<code><mode>2): Ditto. + (copysign<mode>3): Ditto. + (xorsign<mode>3): Ditto. + (<code><mode>3<mask_name>): Ditto. + (<code><mode>3<mask_name>): Ditto. + (<sse>_andnot<mode>3<mask_name>): Adjust for HF vector mode. + (<sse>_andnot<mode>3<mask_name>): Ditto. + (*<code><mode>3<mask_name>): Ditto. + (*<code><mode>3<mask_name>): Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm512_mask_fmadd_ph): + New intrinsic. + (_mm512_mask3_fmadd_ph): Likewise. + (_mm512_maskz_fmadd_ph): Likewise. + (_mm512_fmadd_round_ph): Likewise. + (_mm512_mask_fmadd_round_ph): Likewise. + (_mm512_mask3_fmadd_round_ph): Likewise. + (_mm512_maskz_fmadd_round_ph): Likewise. + (_mm512_fnmadd_ph): Likewise. + (_mm512_mask_fnmadd_ph): Likewise. + (_mm512_mask3_fnmadd_ph): Likewise. + (_mm512_maskz_fnmadd_ph): Likewise. + (_mm512_fnmadd_round_ph): Likewise. + (_mm512_mask_fnmadd_round_ph): Likewise. + (_mm512_mask3_fnmadd_round_ph): Likewise. + (_mm512_maskz_fnmadd_round_ph): Likewise. + (_mm512_fmsub_ph): Likewise. + (_mm512_mask_fmsub_ph): Likewise. + (_mm512_mask3_fmsub_ph): Likewise. + (_mm512_maskz_fmsub_ph): Likewise. + (_mm512_fmsub_round_ph): Likewise. + (_mm512_mask_fmsub_round_ph): Likewise. + (_mm512_mask3_fmsub_round_ph): Likewise. + (_mm512_maskz_fmsub_round_ph): Likewise. + (_mm512_fnmsub_ph): Likewise. + (_mm512_mask_fnmsub_ph): Likewise. + (_mm512_mask3_fnmsub_ph): Likewise. + (_mm512_maskz_fnmsub_ph): Likewise. + (_mm512_fnmsub_round_ph): Likewise. + (_mm512_mask_fnmsub_round_ph): Likewise. + (_mm512_mask3_fnmsub_round_ph): Likewise. + (_mm512_maskz_fnmsub_round_ph): Likewise. + * config/i386/avx512fp16vlintrin.h (_mm256_fmadd_ph): + New intrinsic. + (_mm256_mask_fmadd_ph): Likewise. + (_mm256_mask3_fmadd_ph): Likewise. + (_mm256_maskz_fmadd_ph): Likewise. + (_mm_fmadd_ph): Likewise. + (_mm_mask_fmadd_ph): Likewise. + (_mm_mask3_fmadd_ph): Likewise. + (_mm_maskz_fmadd_ph): Likewise. + (_mm256_fnmadd_ph): Likewise. + (_mm256_mask_fnmadd_ph): Likewise. + (_mm256_mask3_fnmadd_ph): Likewise. + (_mm256_maskz_fnmadd_ph): Likewise. + (_mm_fnmadd_ph): Likewise. + (_mm_mask_fnmadd_ph): Likewise. + (_mm_mask3_fnmadd_ph): Likewise. + (_mm_maskz_fnmadd_ph): Likewise. + (_mm256_fmsub_ph): Likewise. + (_mm256_mask_fmsub_ph): Likewise. + (_mm256_mask3_fmsub_ph): Likewise. + (_mm256_maskz_fmsub_ph): Likewise. + (_mm_fmsub_ph): Likewise. + (_mm_mask_fmsub_ph): Likewise. + (_mm_mask3_fmsub_ph): Likewise. + (_mm_maskz_fmsub_ph): Likewise. + (_mm256_fnmsub_ph): Likewise. + (_mm256_mask_fnmsub_ph): Likewise. + (_mm256_mask3_fnmsub_ph): Likewise. + (_mm256_maskz_fnmsub_ph): Likewise. + (_mm_fnmsub_ph): Likewise. + (_mm_mask_fnmsub_ph): Likewise. + (_mm_mask3_fnmsub_ph): Likewise. + (_mm_maskz_fnmsub_ph): Likewise. + * config/i386/i386-builtin.def: Add corresponding new builtins. + * config/i386/sse.md + (<avx512>_fmadd_<mode>_maskz<round_expand_name>): Adjust to + support HF vector modes. + (<sd_mask_codefor>fma_fmadd_<mode><sd_maskz_name><round_name>): + Ditto. + (*<sd_mask_codefor>fma_fmadd_<mode><sd_maskz_name>_bcst_1): Ditto. + (*<sd_mask_codefor>fma_fmadd_<mode><sd_maskz_name>_bcst_2): Ditto. + (*<sd_mask_codefor>fma_fmadd_<mode><sd_maskz_name>_bcst_3): Ditto. + (<avx512>_fmadd_<mode>_mask<round_name>): Ditto. + (<avx512>_fmadd_<mode>_mask3<round_name>): Ditto. + (<avx512>_fmsub_<mode>_maskz<round_expand_name>): Ditto. + (<sd_mask_codefor>fma_fmsub_<mode><sd_maskz_name><round_name>): + Ditto. + (*<sd_mask_codefor>fma_fmsub_<mode><sd_maskz_name>_bcst_1): Ditto. + (*<sd_mask_codefor>fma_fmsub_<mode><sd_maskz_name>_bcst_2): Ditto. + (*<sd_mask_codefor>fma_fmsub_<mode><sd_maskz_name>_bcst_3): Ditto. + (<avx512>_fmsub_<mode>_mask<round_name>): Ditto. + (<avx512>_fmsub_<mode>_mask3<round_name>): Ditto. + (<sd_mask_codefor>fma_fnmadd_<mode><sd_maskz_name><round_name>): + Ditto. + (*<sd_mask_codefor>fma_fnmadd_<mode><sd_maskz_name>_bcst_1): Ditto. + (*<sd_mask_codefor>fma_fnmadd_<mode><sd_maskz_name>_bcst_2): Ditto. + (*<sd_mask_codefor>fma_fnmadd_<mode><sd_maskz_name>_bcst_3): Ditto. + (<avx512>_fnmadd_<mode>_mask<round_name>): Ditto. + (<avx512>_fnmadd_<mode>_mask3<round_name>): Ditto. + (<avx512>_fnmsub_<mode>_maskz<round_expand_name>): Ditto. + (<sd_mask_codefor>fma_fnmsub_<mode><sd_maskz_name><round_name>): + Ditto. + (*<sd_mask_codefor>fma_fnmsub_<mode><sd_maskz_name>_bcst_1): Ditto. + (*<sd_mask_codefor>fma_fnmsub_<mode><sd_maskz_name>_bcst_2): Ditto. + (*<sd_mask_codefor>fma_fnmsub_<mode><sd_maskz_name>_bcst_3): Ditto. + (<avx512>_fnmsub_<mode>_mask<round_name>): Ditto. + (<avx512>_fnmsub_<mode>_mask3<round_name>): Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm512_fmaddsub_ph): + New intrinsic. + (_mm512_mask_fmaddsub_ph): Likewise. + (_mm512_mask3_fmaddsub_ph): Likewise. + (_mm512_maskz_fmaddsub_ph): Likewise. + (_mm512_fmaddsub_round_ph): Likewise. + (_mm512_mask_fmaddsub_round_ph): Likewise. + (_mm512_mask3_fmaddsub_round_ph): Likewise. + (_mm512_maskz_fmaddsub_round_ph): Likewise. + (_mm512_mask_fmsubadd_ph): Likewise. + (_mm512_mask3_fmsubadd_ph): Likewise. + (_mm512_maskz_fmsubadd_ph): Likewise. + (_mm512_fmsubadd_round_ph): Likewise. + (_mm512_mask_fmsubadd_round_ph): Likewise. + (_mm512_mask3_fmsubadd_round_ph): Likewise. + (_mm512_maskz_fmsubadd_round_ph): Likewise. + * config/i386/avx512fp16vlintrin.h (_mm256_fmaddsub_ph): + New intrinsic. + (_mm256_mask_fmaddsub_ph): Likewise. + (_mm256_mask3_fmaddsub_ph): Likewise. + (_mm256_maskz_fmaddsub_ph): Likewise. + (_mm_fmaddsub_ph): Likewise. + (_mm_mask_fmaddsub_ph): Likewise. + (_mm_mask3_fmaddsub_ph): Likewise. + (_mm_maskz_fmaddsub_ph): Likewise. + (_mm256_fmsubadd_ph): Likewise. + (_mm256_mask_fmsubadd_ph): Likewise. + (_mm256_mask3_fmsubadd_ph): Likewise. + (_mm256_maskz_fmsubadd_ph): Likewise. + (_mm_fmsubadd_ph): Likewise. + (_mm_mask_fmsubadd_ph): Likewise. + (_mm_mask3_fmsubadd_ph): Likewise. + (_mm_maskz_fmsubadd_ph): Likewise. + * config/i386/i386-builtin.def: Add corresponding new builtins. + * config/i386/sse.md (VFH_SF_AVX512VL): New mode iterator. + * (<avx512>_fmsubadd_<mode>_maskz<round_expand_name>): New expander. + * (<avx512>_fmaddsub_<mode>_maskz<round_expand_name>): Use + VFH_SF_AVX512VL. + * (<sd_mask_codefor>fma_fmaddsub_<mode><sd_maskz_name><round_name>): + Ditto. + * (<avx512>_fmaddsub_<mode>_mask<round_name>): Ditto. + * (<avx512>_fmaddsub_<mode>_mask3<round_name>): Ditto. + * (<sd_mask_codefor>fma_fmsubadd_<mode><sd_maskz_name><round_name>): + Ditto. + * (<avx512>_fmsubadd_<mode>_mask<round_name>): Ditto. + * (<avx512>_fmsubadd_<mode>_mask3<round_name>): Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + PR target/87767 + * config/i386/i386.c (ix86_print_operand): Handle + V8HF/V16HF/V32HFmode. + * config/i386/i386.h (VALID_BCST_MODE_P): Add HFmode. + * config/i386/sse.md (avx512bcst): Remove. + +2021-09-17 Martin Sebor <msebor@redhat.com> + + * Makefile.in (OBJS): Add gimple-predicate-analysis.o. + * tree-ssa-uninit.c (max_phi_args): Move to gimple-predicate-analysis. + (MASK_SET_BIT, MASK_TEST_BIT, MASK_EMPTY): Same. + (check_defs): Add comment. + (can_skip_redundant_opnd): Update comment. + (compute_uninit_opnds_pos): Adjust to namespace change. + (find_pdom): Move to gimple-predicate-analysis.cc. + (find_dom): Same. + (struct uninit_undef_val_t): New. + (is_non_loop_exit_postdominating): Move to gimple-predicate-analysis.cc. + (find_control_equiv_block): Same. + (MAX_NUM_CHAINS, MAX_CHAIN_LEN, MAX_POSTDOM_CHECK): Same. + (MAX_SWITCH_CASES): Same. + (compute_control_dep_chain): Same. + (find_uninit_use): Use predicate analyzer. + (struct pred_info): Move to gimple-predicate-analysis. + (convert_control_dep_chain_into_preds): Same. + (find_predicates): Same. + (collect_phi_def_edges): Same. + (warn_uninitialized_phi): Use predicate analyzer. + (find_def_preds): Move to gimple-predicate-analysis. + (dump_pred_info): Same. + (dump_pred_chain): Same. + (dump_predicates): Same. + (destroy_predicate_vecs): Remove. + (execute_late_warn_uninitialized): New. + (get_cmp_code): Move to gimple-predicate-analysis. + (is_value_included_in): Same. + (value_sat_pred_p): Same. + (find_matching_predicate_in_rest_chains): Same. + (is_use_properly_guarded): Same. + (prune_uninit_phi_opnds): Same. + (find_var_cmp_const): Same. + (use_pred_not_overlap_with_undef_path_pred): Same. + (pred_equal_p): Same. + (is_neq_relop_p): Same. + (is_neq_zero_form_p): Same. + (pred_expr_equal_p): Same. + (is_pred_expr_subset_of): Same. + (is_pred_chain_subset_of): Same. + (is_included_in): Same. + (is_superset_of): Same. + (pred_neg_p): Same. + (simplify_pred): Same. + (simplify_preds_2): Same. + (simplify_preds_3): Same. + (simplify_preds_4): Same. + (simplify_preds): Same. + (push_pred): Same. + (push_to_worklist): Same. + (get_pred_info_from_cmp): Same. + (is_degenerated_phi): Same. + (normalize_one_pred_1): Same. + (normalize_one_pred): Same. + (normalize_one_pred_chain): Same. + (normalize_preds): Same. + (can_one_predicate_be_invalidated_p): Same. + (can_chain_union_be_invalidated_p): Same. + (uninit_uses_cannot_happen): Same. + (pass_late_warn_uninitialized::execute): Define. + * gimple-predicate-analysis.cc: New file. + * gimple-predicate-analysis.h: New file. + +2021-09-17 Julian Brown <julian@codesourcery.com> + + * config/gcn/gcn.c (gimple.h): Include. + (gcn_fork_join): Emit barrier for worker-level joins. + * omp-oacc-neuter-broadcast.cc (find_local_vars_to_propagate): Add + writes_gang_private bitmap parameter. Set bit for blocks + containing gang-private variable writes. + (worker_single_simple): Don't emit barrier after predicated block. + (worker_single_copy): Don't emit barrier if we're not broadcasting + anything and the block contains no gang-private writes. + (neuter_worker_single): Don't predicate blocks that only contain + NOPs or internal marker functions. Pass has_gang_private_write + argument to worker_single_copy. + (oacc_do_neutering): Add writes_gang_private bitmap handling. + +2021-09-17 Julian Brown <julian@codesourcery.com> + + * config/gcn/gcn-protos.h + (gcn_goacc_create_worker_broadcast_record): Update prototype. + * config/gcn/gcn-tree.c (gcn_goacc_get_worker_red_decl): Use + preallocated block of LDS memory. Do not cache/share decls for + reduction temporaries between invocations. + (gcn_goacc_reduction_teardown): Unshare VAR on second use. + (gcn_goacc_create_worker_broadcast_record): Add OFFSET parameter + and return temporary LDS space at that offset. Return pointer in + "sender" case. + * config/gcn/gcn.c (acc_lds_size, gang_private_hwm, lds_allocs): + New global vars. + (ACC_LDS_SIZE): Define as acc_lds_size. + (gcn_init_machine_status): Don't initialise lds_allocated, + lds_allocs, reduc_decls fields of machine function struct. + (gcn_option_override): Handle default size for gang-private + variables and -mgang-private-size option. + (gcn_expand_prologue): Use LDS_SIZE instead of LDS_SIZE-1 when + initialising M0_REG. + (gcn_shared_mem_layout): New function. + (gcn_print_lds_decl): Update comment. Use global lds_allocs map and + gang_private_hwm variable. + (TARGET_GOACC_SHARED_MEM_LAYOUT): Define target hook. + * config/gcn/gcn.h (machine_function): Remove lds_allocated, + lds_allocs, reduc_decls. Add reduction_base, reduction_limit. + * config/gcn/gcn.opt (gang_private_size_opt): New global. + (mgang-private-size=): New option. + * doc/tm.texi.in (TARGET_GOACC_SHARED_MEM_LAYOUT): Place + documentation hook. + * doc/tm.texi: Regenerate. + * omp-oacc-neuter-broadcast.cc (targhooks.h, diagnostic-core.h): + Add includes. + (build_sender_ref): Handle sender_decl being pointer. + (worker_single_copy): Add PLACEMENT and ISOLATE_BROADCASTS + parameters. Pass placement argument to + create_worker_broadcast_record hook invocations. Handle + sender_decl being pointer and isolate_broadcasts inserting extra + barriers. + (blk_offset_map_t): Add typedef. + (neuter_worker_single): Add BLK_OFFSET_MAP parameter. Pass + preallocated range to worker_single_copy call. + (dfs_broadcast_reachable_1): New function. + (idx_decl_pair_t, used_range_vec_t): New typedefs. + (sort_size_descending): New function. + (addr_range): New class. + (splay_tree_compare_addr_range, splay_tree_free_key) + (first_fit_range, merge_ranges_1, merge_ranges): New functions. + (execute_omp_oacc_neuter_broadcast): Rename to... + (oacc_do_neutering): ... this. Add BOUNDS_LO, BOUNDS_HI + parameters. Arrange layout of shared memory for broadcast + operations. + (execute_omp_oacc_neuter_broadcast): New function. + (pass_omp_oacc_neuter_broadcast::gate): Remove num_workers==1 + handling from here. Enable pass for all OpenACC routines in order + to call shared memory-layout hook. + * target.def (create_worker_broadcast_record): Add OFFSET + parameter. + (shared_mem_layout): New hook. + +2021-09-17 Julian Brown <julian@codesourcery.com> + Thomas Schwinge <thomas@codesourcery.com> + + * omp-oacc-neuter-broadcast.cc + (pass_omp_oacc_neuter_broadcast::gate): Disable if num_workers is + 1. + (execute_omp_oacc_neuter_broadcast): Adjust. + +2021-09-17 Andrew MacLeod <amacleod@redhat.com> + + * value-relation.cc (class equiv_chain): Move to header file. + (path_oracle::path_oracle): New. + (path_oracle::~path_oracle): New. + (path_oracle::register_relation): New. + (path_oracle::query_relation): New. + (path_oracle::reset_path): New. + (path_oracle::dump): New. + * value-relation.h (class equiv_chain): Move to here. + (class path_oracle): New. + +2021-09-17 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-cache.cc (ranger_cache::ranger_cache): Create a DOM + based oracle. + * gimple-range-fold.cc (fur_depend::register_relation): Use + register_stmt/edge routines. + * value-relation.cc (equiv_chain::find): Relocate from equiv_oracle. + (equiv_oracle::equiv_oracle): Create self equivalence cache. + (equiv_oracle::~equiv_oracle): Release same. + (equiv_oracle::equiv_set): Return entry from self equiv cache if there + are no equivalences. + (equiv_oracle::find_equiv_block): Move list find to equiv_chain. + (equiv_oracle::register_relation): Rename from register_equiv. + (relation_chain_head::find_relation): Relocate from dom_oracle. + (relation_oracle::register_stmt): New. + (relation_oracle::register_edge): New. + (dom_oracle::*): Rename from relation_oracle. + (dom_oracle::register_relation): Adjust to call equiv_oracle. + (dom_oracle::set_one_relation): Split from register_relation. + (dom_oracle::register_transitives): Consolidate 2 methods. + (dom_oracle::find_relation_block): Move core to relation_chain. + (dom_oracle::query_relation): Rename from find_relation_dom and adjust. + * value-relation.h (class relation_oracle): New pure virtual base. + (class equiv_oracle): Inherit from relation_oracle and adjust. + (class dom_oracle): Rename from old relation_oracle and adjust. + +2021-09-17 Martin Sebor <msebor@redhat.com> + + PR middle-end/102200 + * pointer-query.cc (access_ref::inform_access): Handle MIN/MAX_EXPR. + (handle_min_max_size): Change argument. Store original SSA_NAME for + operands to potentially distinct (sub)objects. + (compute_objsize_r): Adjust call to the above. + +2021-09-17 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000.c (rs6000-builtins.h): New include. + (rs6000_new_builtin_vectorized_function): New function. + (rs6000_new_builtin_md_vectorized_function): Likewise. + (rs6000_builtin_vectorized_function): Call + rs6000_new_builtin_vectorized_function. + (rs6000_builtin_md_vectorized_function): Call + rs6000_new_builtin_md_vectorized_function. + +2021-09-17 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000-builtin-new.def (ASSEMBLE_ACC): Add mmaint flag. + (ASSEMBLE_PAIR): Likewise. + (BUILD_ACC): Likewise. + (DISASSEMBLE_ACC): Likewise. + (DISASSEMBLE_PAIR): Likewise. + (PMXVBF16GER2): Likewise. + (PMXVBF16GER2NN): Likewise. + (PMXVBF16GER2NP): Likewise. + (PMXVBF16GER2PN): Likewise. + (PMXVBF16GER2PP): Likewise. + (PMXVF16GER2): Likewise. + (PMXVF16GER2NN): Likewise. + (PMXVF16GER2NP): Likewise. + (PMXVF16GER2PN): Likewise. + (PMXVF16GER2PP): Likewise. + (PMXVF32GER): Likewise. + (PMXVF32GERNN): Likewise. + (PMXVF32GERNP): Likewise. + (PMXVF32GERPN): Likewise. + (PMXVF32GERPP): Likewise. + (PMXVF64GER): Likewise. + (PMXVF64GERNN): Likewise. + (PMXVF64GERNP): Likewise. + (PMXVF64GERPN): Likewise. + (PMXVF64GERPP): Likewise. + (PMXVI16GER2): Likewise. + (PMXVI16GER2PP): Likewise. + (PMXVI16GER2S): Likewise. + (PMXVI16GER2SPP): Likewise. + (PMXVI4GER8): Likewise. + (PMXVI4GER8PP): Likewise. + (PMXVI8GER4): Likewise. + (PMXVI8GER4PP): Likewise. + (PMXVI8GER4SPP): Likewise. + (XVBF16GER2): Likewise. + (XVBF16GER2NN): Likewise. + (XVBF16GER2NP): Likewise. + (XVBF16GER2PN): Likewise. + (XVBF16GER2PP): Likewise. + (XVF16GER2): Likewise. + (XVF16GER2NN): Likewise. + (XVF16GER2NP): Likewise. + (XVF16GER2PN): Likewise. + (XVF16GER2PP): Likewise. + (XVF32GER): Likewise. + (XVF32GERNN): Likewise. + (XVF32GERNP): Likewise. + (XVF32GERPN): Likewise. + (XVF32GERPP): Likewise. + (XVF64GER): Likewise. + (XVF64GERNN): Likewise. + (XVF64GERNP): Likewise. + (XVF64GERPN): Likewise. + (XVF64GERPP): Likewise. + (XVI16GER2): Likewise. + (XVI16GER2PP): Likewise. + (XVI16GER2S): Likewise. + (XVI16GER2SPP): Likewise. + (XVI4GER8): Likewise. + (XVI4GER8PP): Likewise. + (XVI8GER4): Likewise. + (XVI8GER4PP): Likewise. + (XVI8GER4SPP): Likewise. + (XXMFACC): Likewise. + (XXMTACC): Likewise. + (XXSETACCZ): Likewise. + (ASSEMBLE_PAIR_V): Likewise. + (BUILD_PAIR): Likewise. + (DISASSEMBLE_PAIR_V): Likewise. + (LXVP): New. + (STXVP): New. + * config/rs6000/rs6000-call.c (rs6000_gimple_fold_new_mma_builtin): + Handle RS6000_BIF_LXVP and RS6000_BIF_STXVP. + * config/rs6000/rs6000-gen-builtins.c (attrinfo): Add ismmaint. + (parse_bif_attrs): Handle ismmaint. + (write_decls): Add bif_mmaint_bit and bif_is_mmaint. + (write_bif_static_init): Handle ismmaint. + +2021-09-17 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000-call.c (rs6000_gimple_fold_new_builtin): New + forward decl. + (rs6000_gimple_fold_builtin): Call rs6000_gimple_fold_new_builtin. + (rs6000_new_builtin_valid_without_lhs): New function. + (rs6000_gimple_fold_new_mma_builtin): Likewise. + (rs6000_gimple_fold_new_builtin): Likewise. + +2021-09-17 Thomas Schwinge <thomas@codesourcery.com> + + * hash-table.h (hash_table<Descriptor, Lazy, Allocator>::expand): + Destruct stale Value objects. + * hash-map-tests.c (test_map_of_type_with_ctor_and_dtor_expand): + Update. + +2021-09-17 Roger Sayle <roger@nextmovesoftware.com> + + PR c/102245 + * match.pd (shift optimizations): Disable recent sign-changing + optimization for shifts by zero, these will be folded later. + +2021-09-17 Bill Schmidt <wschmidt@linux.ibm.com> + + * config/rs6000/rs6000-builtin-new.def (__builtin_mffsl): Move from + [power9] to [always]. + +2021-09-17 Richard Biener <rguenther@suse.de> + + * tree-vect-stmts.c (vectorizable_load): Do not frob + stmt_info for SLP. + +2021-09-17 H.J. Lu <hjl.tools@gmail.com> + + * config/i386/i386-features.c (remove_partial_avx_dependency): + Also check TARGET_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY and + and TARGET_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY before generating + vxorps. + * config/i386/i386.h (TARGET_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY): + New. + (TARGET_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY): Likewise. + * config/i386/i386.md (SSE FP to FP splitters): Replace + TARGET_SSE_PARTIAL_REG_DEPENDENCY with + TARGET_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY. + (SSE INT to FP splitter): Replace TARGET_SSE_PARTIAL_REG_DEPENDENCY + with TARGET_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY. + * config/i386/x86-tune.def + (X86_TUNE_SSE_PARTIAL_REG_FP_CONVERTS_DEPENDENCY): New. + (X86_TUNE_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY): Likewise. + +2021-09-17 H.J. Lu <hjl.tools@gmail.com> + + PR target/101900 + * config/i386/i386-features.c (remove_partial_avx_dependency): + Check TARGET_USE_VECTOR_FP_CONVERTS and TARGET_USE_VECTOR_CONVERTS + before generating vxorps. + +2021-09-17 H.J. Lu <hjl.tools@gmail.com> + + * config/i386/i386-options.c (processor_cost_table): Use + tremont_cost for Tremont. + * config/i386/x86-tune-costs.h (tremont_memcpy): New. + (tremont_memset): Likewise. + (tremont_cost): Likewise. + * config/i386/x86-tune.def (X86_TUNE_PREFER_KNOWN_REP_MOVSB_STOSB): + Enable for Tremont. + +2021-09-17 H.J. Lu <hjl.tools@gmail.com> + + * common/config/i386/i386-common.c: Use Haswell scheduling model + for Tremont. + * config/i386/i386.c (ix86_sched_init_global): Prepare for Tremont + scheduling pass. + * config/i386/x86-tune-sched.c (ix86_issue_rate): Change Tremont + issue rate to 4. + (ix86_adjust_cost): Handle Tremont. + * config/i386/x86-tune.def (X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY): + Enable for Tremont. + (X86_TUNE_USE_LEAVE): Likewise. + (X86_TUNE_PUSH_MEMORY): Likewise. + (X86_TUNE_MISALIGNED_MOVE_STRING_PRO_EPILOGUES): Likewise. + (X86_TUNE_USE_CLTD): Likewise. + (X86_TUNE_AVOID_FALSE_DEP_FOR_BMI): Likewise. + (X86_TUNE_AVOID_MFENCE): Likewise. + (X86_TUNE_SSE_TYPELESS_STORES): Likewise. + (X86_TUNE_SSE_LOAD0_BY_PXOR): Likewise. + (X86_TUNE_ACCUMULATE_OUTGOING_ARGS): Disable for Tremont. + (X86_TUNE_FOUR_JUMP_LIMIT): Likewise. + (X86_TUNE_OPT_AGU): Likewise. + (X86_TUNE_AVOID_LEA_FOR_ADDR): Likewise. + (X86_TUNE_AVOID_MEM_OPND_FOR_CMOVE): Likewise. + (X86_TUNE_EXPAND_ABS): Likewise. + (X86_TUNE_SPLIT_MEM_OPND_FOR_FP_CONVERTS): Likewise. + (X86_TUNE_SLOW_PSHUFB): Likewise. + +2021-09-17 Eric Botcazou <ebotcazou@adacore.com> + + PR rtl-optimization/102306 + * combine.c (try_combine): Abort the combination if we are about to + duplicate volatile references. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm_undefined_ph): + New intrinsic. + (_mm256_undefined_ph): Likewise. + (_mm512_undefined_ph): Likewise. + (_mm_cvtsh_h): Likewise. + (_mm256_cvtsh_h): Likewise. + (_mm512_cvtsh_h): Likewise. + (_mm512_castph_ps): Likewise. + (_mm512_castph_pd): Likewise. + (_mm512_castph_si512): Likewise. + (_mm512_castph512_ph128): Likewise. + (_mm512_castph512_ph256): Likewise. + (_mm512_castph128_ph512): Likewise. + (_mm512_castph256_ph512): Likewise. + (_mm512_zextph128_ph512): Likewise. + (_mm512_zextph256_ph512): Likewise. + (_mm512_castps_ph): Likewise. + (_mm512_castpd_ph): Likewise. + (_mm512_castsi512_ph): Likewise. + * config/i386/avx512fp16vlintrin.h (_mm_castph_ps): + New intrinsic. + (_mm256_castph_ps): Likewise. + (_mm_castph_pd): Likewise. + (_mm256_castph_pd): Likewise. + (_mm_castph_si128): Likewise. + (_mm256_castph_si256): Likewise. + (_mm_castps_ph): Likewise. + (_mm256_castps_ph): Likewise. + (_mm_castpd_ph): Likewise. + (_mm256_castpd_ph): Likewise. + (_mm_castsi128_ph): Likewise. + (_mm256_castsi256_ph): Likewise. + (_mm256_castph256_ph128): Likewise. + (_mm256_castph128_ph256): Likewise. + (_mm256_zextph128_ph256): Likewise. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm_cvtsh_ss): + New intrinsic. + (_mm_mask_cvtsh_ss): Likewise. + (_mm_maskz_cvtsh_ss): Likewise. + (_mm_cvtsh_sd): Likewise. + (_mm_mask_cvtsh_sd): Likewise. + (_mm_maskz_cvtsh_sd): Likewise. + (_mm_cvt_roundsh_ss): Likewise. + (_mm_mask_cvt_roundsh_ss): Likewise. + (_mm_maskz_cvt_roundsh_ss): Likewise. + (_mm_cvt_roundsh_sd): Likewise. + (_mm_mask_cvt_roundsh_sd): Likewise. + (_mm_maskz_cvt_roundsh_sd): Likewise. + (_mm_cvtss_sh): Likewise. + (_mm_mask_cvtss_sh): Likewise. + (_mm_maskz_cvtss_sh): Likewise. + (_mm_cvtsd_sh): Likewise. + (_mm_mask_cvtsd_sh): Likewise. + (_mm_maskz_cvtsd_sh): Likewise. + (_mm_cvt_roundss_sh): Likewise. + (_mm_mask_cvt_roundss_sh): Likewise. + (_mm_maskz_cvt_roundss_sh): Likewise. + (_mm_cvt_roundsd_sh): Likewise. + (_mm_mask_cvt_roundsd_sh): Likewise. + (_mm_maskz_cvt_roundsd_sh): Likewise. + * config/i386/i386-builtin-types.def + (V8HF_FTYPE_V2DF_V8HF_V8HF_UQI_INT, + V8HF_FTYPE_V4SF_V8HF_V8HF_UQI_INT, + V2DF_FTYPE_V8HF_V2DF_V2DF_UQI_INT, + V4SF_FTYPE_V8HF_V4SF_V4SF_UQI_INT): Add new builtin types. + * config/i386/i386-builtin.def: Add corrresponding new builtins. + * config/i386/i386-expand.c: Handle new builtin types. + * config/i386/sse.md (VF48_128): New mode iterator. + (avx512fp16_vcvtsh2<ssescalarmodesuffix><mask_scalar_name><round_saeonly_scalar_name>): + New. + (avx512fp16_vcvt<ssescalarmodesuffix>2sh<mask_scalar_name><round_scalar_name>): + Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm512_cvtph_pd): + New intrinsic. + (_mm512_mask_cvtph_pd): Likewise. + (_mm512_maskz_cvtph_pd): Likewise. + (_mm512_cvt_roundph_pd): Likewise. + (_mm512_mask_cvt_roundph_pd): Likewise. + (_mm512_maskz_cvt_roundph_pd): Likewise. + (_mm512_cvtxph_ps): Likewise. + (_mm512_mask_cvtxph_ps): Likewise. + (_mm512_maskz_cvtxph_ps): Likewise. + (_mm512_cvtx_roundph_ps): Likewise. + (_mm512_mask_cvtx_roundph_ps): Likewise. + (_mm512_maskz_cvtx_roundph_ps): Likewise. + (_mm512_cvtxps_ph): Likewise. + (_mm512_mask_cvtxps_ph): Likewise. + (_mm512_maskz_cvtxps_ph): Likewise. + (_mm512_cvtx_roundps_ph): Likewise. + (_mm512_mask_cvtx_roundps_ph): Likewise. + (_mm512_maskz_cvtx_roundps_ph): Likewise. + (_mm512_cvtpd_ph): Likewise. + (_mm512_mask_cvtpd_ph): Likewise. + (_mm512_maskz_cvtpd_ph): Likewise. + (_mm512_cvt_roundpd_ph): Likewise. + (_mm512_mask_cvt_roundpd_ph): Likewise. + (_mm512_maskz_cvt_roundpd_ph): Likewise. + * config/i386/avx512fp16vlintrin.h (_mm_cvtph_pd): + New intrinsic. + (_mm_mask_cvtph_pd): Likewise. + (_mm_maskz_cvtph_pd): Likewise. + (_mm256_cvtph_pd): Likewise. + (_mm256_mask_cvtph_pd): Likewise. + (_mm256_maskz_cvtph_pd): Likewise. + (_mm_cvtxph_ps): Likewise. + (_mm_mask_cvtxph_ps): Likewise. + (_mm_maskz_cvtxph_ps): Likewise. + (_mm256_cvtxph_ps): Likewise. + (_mm256_mask_cvtxph_ps): Likewise. + (_mm256_maskz_cvtxph_ps): Likewise. + (_mm_cvtxps_ph): Likewise. + (_mm_mask_cvtxps_ph): Likewise. + (_mm_maskz_cvtxps_ph): Likewise. + (_mm256_cvtxps_ph): Likewise. + (_mm256_mask_cvtxps_ph): Likewise. + (_mm256_maskz_cvtxps_ph): Likewise. + (_mm_cvtpd_ph): Likewise. + (_mm_mask_cvtpd_ph): Likewise. + (_mm_maskz_cvtpd_ph): Likewise. + (_mm256_cvtpd_ph): Likewise. + (_mm256_mask_cvtpd_ph): Likewise. + (_mm256_maskz_cvtpd_ph): Likewise. + * config/i386/i386-builtin.def: Add corresponding new builtins. + * config/i386/i386-builtin-types.def: Add corresponding builtin types. + * config/i386/i386-expand.c: Handle new builtin types. + * config/i386/sse.md + (VF4_128_8_256): New. + (VF48H_AVX512VL): Ditto. + (ssePHmode): Add HF vector modes. + (castmode): Add new convertable modes. + (qq2phsuff): Ditto. + (ph2pssuffix): New. + (avx512fp16_vcvt<castmode>2ph_<mode><mask_name><round_name>): Ditto. + (avx512fp16_vcvt<castmode>2ph_<mode>): Ditto. + (*avx512fp16_vcvt<castmode>2ph_<mode>): Ditto. + (avx512fp16_vcvt<castmode>2ph_<mode>_mask): Ditto. + (*avx512fp16_vcvt<castmode>2ph_<mode>_mask): Ditto. + (*avx512fp16_vcvt<castmode>2ph_<mode>_mask_1): Ditto. + (avx512fp16_float_extend_ph<mode>2<mask_name><round_saeonly_name>): + Ditto. + (avx512fp16_float_extend_ph<mode>2<mask_name>): Ditto. + (*avx512fp16_float_extend_ph<mode>2_load<mask_name>): Ditto. + (avx512fp16_float_extend_phv2df2<mask_name>): Ditto. + (*avx512fp16_float_extend_phv2df2_load<mask_name>): Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm_cvttsh_i32): + New intrinsic. + (_mm_cvttsh_u32): Likewise. + (_mm_cvtt_roundsh_i32): Likewise. + (_mm_cvtt_roundsh_u32): Likewise. + (_mm_cvttsh_i64): Likewise. + (_mm_cvttsh_u64): Likewise. + (_mm_cvtt_roundsh_i64): Likewise. + (_mm_cvtt_roundsh_u64): Likewise. + * config/i386/i386-builtin.def: Add corresponding new builtins. + * config/i386/sse.md + (avx512fp16_fix<fixunssuffix>_trunc<mode>2<round_saeonly_name>): + New. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm512_cvttph_epi32): + New intrinsic. + (_mm512_mask_cvttph_epi32): Likewise. + (_mm512_maskz_cvttph_epi32): Likewise. + (_mm512_cvtt_roundph_epi32): Likewise. + (_mm512_mask_cvtt_roundph_epi32): Likewise. + (_mm512_maskz_cvtt_roundph_epi32): Likewise. + (_mm512_cvttph_epu32): Likewise. + (_mm512_mask_cvttph_epu32): Likewise. + (_mm512_maskz_cvttph_epu32): Likewise. + (_mm512_cvtt_roundph_epu32): Likewise. + (_mm512_mask_cvtt_roundph_epu32): Likewise. + (_mm512_maskz_cvtt_roundph_epu32): Likewise. + (_mm512_cvttph_epi64): Likewise. + (_mm512_mask_cvttph_epi64): Likewise. + (_mm512_maskz_cvttph_epi64): Likewise. + (_mm512_cvtt_roundph_epi64): Likewise. + (_mm512_mask_cvtt_roundph_epi64): Likewise. + (_mm512_maskz_cvtt_roundph_epi64): Likewise. + (_mm512_cvttph_epu64): Likewise. + (_mm512_mask_cvttph_epu64): Likewise. + (_mm512_maskz_cvttph_epu64): Likewise. + (_mm512_cvtt_roundph_epu64): Likewise. + (_mm512_mask_cvtt_roundph_epu64): Likewise. + (_mm512_maskz_cvtt_roundph_epu64): Likewise. + (_mm512_cvttph_epi16): Likewise. + (_mm512_mask_cvttph_epi16): Likewise. + (_mm512_maskz_cvttph_epi16): Likewise. + (_mm512_cvtt_roundph_epi16): Likewise. + (_mm512_mask_cvtt_roundph_epi16): Likewise. + (_mm512_maskz_cvtt_roundph_epi16): Likewise. + (_mm512_cvttph_epu16): Likewise. + (_mm512_mask_cvttph_epu16): Likewise. + (_mm512_maskz_cvttph_epu16): Likewise. + (_mm512_cvtt_roundph_epu16): Likewise. + (_mm512_mask_cvtt_roundph_epu16): Likewise. + (_mm512_maskz_cvtt_roundph_epu16): Likewise. + * config/i386/avx512fp16vlintrin.h (_mm_cvttph_epi32): + New intirnsic. + (_mm_mask_cvttph_epi32): Likewise. + (_mm_maskz_cvttph_epi32): Likewise. + (_mm256_cvttph_epi32): Likewise. + (_mm256_mask_cvttph_epi32): Likewise. + (_mm256_maskz_cvttph_epi32): Likewise. + (_mm_cvttph_epu32): Likewise. + (_mm_mask_cvttph_epu32): Likewise. + (_mm_maskz_cvttph_epu32): Likewise. + (_mm256_cvttph_epu32): Likewise. + (_mm256_mask_cvttph_epu32): Likewise. + (_mm256_maskz_cvttph_epu32): Likewise. + (_mm_cvttph_epi64): Likewise. + (_mm_mask_cvttph_epi64): Likewise. + (_mm_maskz_cvttph_epi64): Likewise. + (_mm256_cvttph_epi64): Likewise. + (_mm256_mask_cvttph_epi64): Likewise. + (_mm256_maskz_cvttph_epi64): Likewise. + (_mm_cvttph_epu64): Likewise. + (_mm_mask_cvttph_epu64): Likewise. + (_mm_maskz_cvttph_epu64): Likewise. + (_mm256_cvttph_epu64): Likewise. + (_mm256_mask_cvttph_epu64): Likewise. + (_mm256_maskz_cvttph_epu64): Likewise. + (_mm_cvttph_epi16): Likewise. + (_mm_mask_cvttph_epi16): Likewise. + (_mm_maskz_cvttph_epi16): Likewise. + (_mm256_cvttph_epi16): Likewise. + (_mm256_mask_cvttph_epi16): Likewise. + (_mm256_maskz_cvttph_epi16): Likewise. + (_mm_cvttph_epu16): Likewise. + (_mm_mask_cvttph_epu16): Likewise. + (_mm_maskz_cvttph_epu16): Likewise. + (_mm256_cvttph_epu16): Likewise. + (_mm256_mask_cvttph_epu16): Likewise. + (_mm256_maskz_cvttph_epu16): Likewise. + * config/i386/i386-builtin.def: Add new builtins. + * config/i386/sse.md + (avx512fp16_fix<fixunssuffix>_trunc<mode>2<mask_name><round_saeonly_name>): + New. + (avx512fp16_fix<fixunssuffix>_trunc<mode>2<mask_name>): Ditto. + (*avx512fp16_fix<fixunssuffix>_trunc<mode>2_load<mask_name>): Ditto. + (avx512fp16_fix<fixunssuffix>_truncv2di2<mask_name>): Ditto. + (avx512fp16_fix<fixunssuffix>_truncv2di2_load<mask_name>): Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * config/i386/avx512fp16intrin.h (_mm_cvtsh_i32): New intrinsic. + (_mm_cvtsh_u32): Likewise. + (_mm_cvt_roundsh_i32): Likewise. + (_mm_cvt_roundsh_u32): Likewise. + (_mm_cvtsh_i64): Likewise. + (_mm_cvtsh_u64): Likewise. + (_mm_cvt_roundsh_i64): Likewise. + (_mm_cvt_roundsh_u64): Likewise. + (_mm_cvti32_sh): Likewise. + (_mm_cvtu32_sh): Likewise. + (_mm_cvt_roundi32_sh): Likewise. + (_mm_cvt_roundu32_sh): Likewise. + (_mm_cvti64_sh): Likewise. + (_mm_cvtu64_sh): Likewise. + (_mm_cvt_roundi64_sh): Likewise. + (_mm_cvt_roundu64_sh): Likewise. + * config/i386/i386-builtin-types.def: Add corresponding builtin types. + * config/i386/i386-builtin.def: Add corresponding new builtins. + * config/i386/i386-expand.c (ix86_expand_round_builtin): + Handle new builtin types. + * config/i386/sse.md + (avx512fp16_vcvtsh2<sseintconvertsignprefix>si<rex64namesuffix><round_name>): + New define_insn. + (avx512fp16_vcvtsh2<sseintconvertsignprefix>si<rex64namesuffix>_2): Likewise. + (avx512fp16_vcvt<floatsuffix>si2sh<rex64namesuffix><round_name>): Likewise. + 2021-09-16 Bill Schmidt <wschmidt@linux.ibm.com> * config/rs6000/rs6000-c.c (rs6000-builtins.h): New include. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 62910e5..ed865cb 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210917 +20210921 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index b8229ad..f36ffa4 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1394,6 +1394,7 @@ OBJS = \ gimple-loop-jam.o \ gimple-loop-versioning.o \ gimple-low.o \ + gimple-predicate-analysis.o \ gimple-pretty-print.o \ gimple-range.o \ gimple-range-cache.o \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 70aaabf..56d9baf 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,339 @@ +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * inline.adb (Has_Excluded_Declaration): Remove redundant guard; + the guarded code will call First on a No_List, which is + well-defined and gives Empty. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * inline.adb (Has_Excluded_Declaration): Rename and reduce scope + of a local variable. + +2021-09-20 Bob Duff <duff@adacore.com> + + * uintp.ads, uintp.adb (Present, No): New functions for + comparing with No_Uint. + * checks.adb, einfo-utils.adb, exp_aggr.adb, exp_attr.adb, + exp_ch3.adb, exp_ch4.adb, exp_dbug.adb, exp_disp.adb, + exp_util.adb, repinfo.adb, repinfo-input.adb, scn.adb, + sem_attr.adb, sem_ch13.adb, sem_eval.adb, sem_util.adb, + sinfo-utils.adb, treepr.adb: Use Present (...) instead of "... + /= No_Uint", and No (...) instead of "... = No_Uint". + +2021-09-20 Claire Dross <dross@adacore.com> + + * libgnat/s-ficobl.ads: The entire package has a SPARK_Mode => + Off aspect. + +2021-09-20 Doug Rupp <rupp@adacore.com> + + * libgnat/a-calend.adb: Remove time_t, replace with OS_Time. + * libgnat/s-os_lib.ads: Fix comments regarding time_t conversion + functions to reflect the use of To_Ada in in Ada.Calendar + package body. + * sysdep.c (__gnat_localtime_tzoff): Use OS_Time instead of + time_t. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * sem_res.adb (Resolve_Actual): Remove + +2021-09-20 Bob Duff <duff@adacore.com> + + * einfo-utils.ads, einfo-utils.adb, fe.h, einfo.ads, + gen_il-fields.ads: Remove unused and no-longer-used routines. + Move related routines together. Rewrite incorrect + documentation, and documentation that will be incorrect when + e.g. Esize-related routines are fixed. Remove unused field + Normalized_Position_Max. + * cstand.adb, exp_pakd.adb, freeze.adb, + gen_il-gen-gen_entities.adb, itypes.adb, layout.adb, + sem_ch10.adb, sem_ch12.adb, sem_ch13.adb, sem_ch3.adb, + sem_ch7.adb, sem_ch8.adb, sem_ch9.adb, sem_prag.adb, + sem_util.adb, ttypes.ads: Update calls to routines removed from + or renamed in Einfo.Utils. + * uintp.ads (Upos): Fix this subtype, which was unintentionally + declared to include Uint_0. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * exp_ch7.adb (Expand_N_Package_Declaration): Fix wording in + comment. + * exp_disp.adb (Mark_DT): Remove unnecessary initialization of + I_Depth. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * contracts.adb (Add_Contract_Item): Accept volatile-related + properties on constants. + (Analyze_Object_Contract): Check external properties on + constants; accept volatile constants. + (Check_Type_Or_Object_External_Properties): Replace "variable" + with "object" in error messages; replace Decl_Kind with a local + constant. + * sem_prag.adb (Analyze_Pragma): Accept volatile-related + properties on constants. + +2021-09-20 Pierre-Alexandre Bazin <bazin@adacore.com> + + * libgnat/a-strfix.adb ("*"): Added loop invariants and lemmas + for proof. + (Delete): Added assertions for proof, and conditions to avoid + overflow. + (Head): Added loop invariant. + (Insert): Same as Delete. + (Move): Declared with SPARK_Mode Off. + (Overwrite): Added assertions for proof, and conditions to avoid + overflow. + (Replace_Slice): Added assertions for proof, and conditions to + avoid overflow. + (Tail): Added loop invariant and avoided overflows. + (Translate): Added loop invariants. + (Trim): Ensured empty strings returned start at 1. + * libgnat/a-strfix.ads (Index): Rewrote contract cases for + easier proof. + (Index_Non_Blank): Separated the null string case. + (Count): Specified Mapping shouldn't be null. + (Find_Token): Specified Source'First should be Positive when no + From is given. + (Translate): Specified Mapping shouldn't be null. + ("*"): Rewrote postcondition for easier proof. + * libgnat/a-strsea.adb (Belongs): Added postcondition. + (Count): Rewrote loops and added loop invariants to avoid + overflows. + (Find_Token): Added loop invariants. + (Index): Rewrote loops to avoid overflows and added loop + invariants for proof. + (Index_Non_Blank): Added loop invariants. + (Is_Identity): New function isolated without SPARK_Mode. + * libgnat/a-strsea.ads: Fix starting comment as package is no + longer private. + (Match): Declared ghost expression function Match. + (Is_Identity): Described identity in the postcondition. + (Index, Index_Non_Blank, Count, Find_Token): Added contract from + a-strfix.ads. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * sem_ch13.adb (Resolve_Aspect_Aggregate): Move comments after + specs; fix typo in header box; cleanup whitespace. + +2021-09-20 Eric Botcazou <ebotcazou@adacore.com> + + * libgnat/s-objrea.adb (Get_Load_Address): Return 0 for ELF. + +2021-09-20 Eric Botcazou <ebotcazou@adacore.com> + + * adaint.c (__gnat_get_executable_load_address): Add Win32 support. + * libgnat/s-objrea.ads (Get_Xcode_Bounds): Fix typo in comment. + (Object_File): Minor reformatting. + (ELF_Object_File): Uncomment predicate. + (PECOFF_Object_File): Likewise. + (XCOFF32_Object_File): Likewise. + * libgnat/s-objrea.adb: Minor reformatting throughout. + (Get_Load_Address): Implement for PE-COFF. + * libgnat/s-dwalin.ads: Remove clause for System.Storage_Elements + and use consistent wording in comments. + (Dwarf_Context): Set type of Low, High and Load_Address to Address. + * libgnat/s-dwalin.adb (Get_Load_Displacement): New function. + (Is_Inside): Call Get_Load_Displacement. + (Low_Address): Likewise. + (Open): Adjust to type change. + (Aranges_Lookup): Change type of Addr to Address. + (Read_Aranges_Entry): Likewise for Start and adjust. + (Enable_Cach): Adjust to type change. + (Symbolic_Address): Change type of Addr to Address. + (Symbolic_Traceback): Call Get_Load_Displacement. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * exp_disp.adb (Make_DT): Move call to Set_Has_Dispatch_Table, + so it is executed regardless of the Generate_SCIL mode. + +2021-09-20 Ed Schonberg <schonberg@adacore.com> + + * exp_util.ads (Force_Evaluation): Add formal parameter + Discr_Number, to indicate discriminant expression for which an + external name must be created. + (Remove_Side_Effects): Ditto. + * exp_util.adb (Force_Evaluation): Call Remove_Side_Effects with + added parameter. + (Remove_Side_Effects, Build_Temporary): If Discr_Number is + positive, create an external name with suffix DISCR and the + given discriminant number, analogous to what is done for + temporaries for array type bounds. + * sem_ch3.adb (Process_Discriminant_Expressions): If the + constraint is for an object or component declaration and the + corresponding entity may be visible in another unit, invoke + Force_Evaluation with the new parameter. + +2021-09-20 Arnaud Charlet <charlet@adacore.com> + + * gen_il-internals.ads (Invalid_Val): Remove, unused and + generates warnings. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * exp_aggr.adb, exp_ch4.adb, exp_ch5.adb, sprint.adb: Refine + types of local constants. + +2021-09-20 Gary Dismukes <dismukes@adacore.com> + + * exp_attr.adb (Expand_N_Attribute_Reference): Fold + Preelaborable_Initialization attribute in cases where it hasn't + been folded by the analyzer. + * exp_disp.adb (Original_View_In_Visible_Part): This function is + removed and moved to sem_util.adb. + * sem_attr.adb (Attribute_22): Add + Attribute_Preelaborable_Initialization as an Ada 2022 attribute. + (Analyze_Attribute, Attribute_Preelaborable_Initialization): + Check that the prefix of the attribute is either a formal + private or derived type, or a composite type declared within the + visible part of a package or generic package. + (Eval_Attribute): Perform folding of + Preelaborable_Initialization attribute based on + Has_Preelaborable_Initialization applied to the prefix type. + * sem_ch3.adb (Resolve_Aspects): Add specialized code for + Preelaborable_Initialization used at the end of a package + visible part for setting Known_To_Have_Preelab_Init on types + that are specified with True or that have a conjunction of one + or more P_I attributes applied to formal types. + * sem_ch7.adb (Analyze_Package_Specification): On call to + Has_Preelaborable_Initialization, pass True for new formal + Formal_Types_Have_Preelab_Init, so that error checking treats + subcomponents that are declared within types in generics as + having preelaborable initialization when the subcomponents are + of formal types. + * sem_ch13.adb (Analyze_Aspects_At_Freeze_Point): Add test for + P_I to prevent calling Make_Pragma_From_Boolean_Aspect, since + this aspect is handled specially and the + Known_To_Have_Preelab_Init flag will get set on types that have + the aspect by other means. + (Analyze_Aspect_Specifications.Analyze_One_Aspect): Add test for + Aspect_Preelaborable_Initialization for allowing the aspect to + be specified on formal type declarations. + (Is_Operational_Item): Treat Attribute_Put_Image as an + operational attribute. The need for this was encountered while + working on these changes. + * sem_util.ads (Has_Preelaborable_Initialization): Add + Formal_Types_Have_Preelab_Init as a new formal parameter that + defaults to False. + (Is_Conjunction_Of_Formal_Preelab_Init_Attributes): New + function. + (Original_View_In_Visible_Part): Moved here from exp_disp.adb, + so it can be called by Analyze_Attribute. + * sem_util.adb (Has_Preelaborable_Initialization): Return True + for formal private and derived types when new formal + Formal_Types_Have_Preelab_Init is True, and pass along the + Formal_Types_Have_Preelab_Init flag in the array component case. + (Check_Components): Pass along Formal_Types_Have_Preelab_Init + flag on call to Has_Preelaborable_Initialization. + (Is_Conjunction_Of_Formal_Preelab_Init_Attributes): New function + that returns True when passed an expression that includes one or + more attributes for Preelaborable_Initialization applied to + prefixes that denote formal types. + (Is_Formal_Preelab_Init_Attribute): New utility function nested + within Is_Conjunction_Of_Formal_Preelab_Init_Attributes that + determines whether a node is a P_I attribute applied to a + generic formal type. + (Original_View_In_Visible_Part): Moved here from exp_util.adb, + so it can be called by Analyze_Attribute. + * snames.ads-tmpl: Add note near the start of spec giving + details about what needs to be done when adding a name that + corresponds to both an attribute and a pragma. Delete existing + occurrence of Name_Preelaborable_Initialization, and add a note + comment in the list of Name_* constants at that place, + indicating that it's included in type Pragma_Id, etc., echoing + other such comments for names that are both an attribute and a + pragma. Insert Name_Preelaborable_Initialization in the + alphabetized set of Name_* constants corresponding to + attributes (between First_Attribute_Name and + Last_Attribute_Name). + (type Attribute_Id): Add new literal + Attribute_Preelaborable_Initialization. + (type Pragma_Id): Move Pragma_Preelaborable_Initialization from + its current position to the end of the type, in the special set + of pragma literals that have corresponding atttributes. Add to + accompanying comment, indicating that functions Get_Pragma_Id + and Is_Pragma_Name need to be updated when adding a pragma + literal to the special set. + * snames.adb-tmpl (Get_Pragma_Id): Add case alternative for + Pragma_Preelaborable_Initialization. + (Is_Pragma_Name): Add test for + Name_Preelaborable_Initialization. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_ch4.adb (Finc_Non_Universal_Interpretations): Fix check. + +2021-09-20 Piotr Trojanek <trojanek@adacore.com> + + * sem_ch3.adb (Build_Discriminant_Constraints): Exit once a + first discriminant is found and the Discrim_Present flag is set. + +2021-09-20 Bob Duff <duff@adacore.com> + + * gnat1drv.adb (Gnat1drv): Avoid calling List_Rep_Info in + Generate_SCIL and GNATprove_Mode. + * repinfo.adb (List_Common_Type_Info): Fix comment. + +2021-09-20 Eric Botcazou <ebotcazou@adacore.com> + + * libgnat/s-dwalin.ads: Remove clause for Ada.Exceptions.Traceback, + add clause for System.Traceback_Entries and alphabetize. + (AET): Delete. + (STE): New package renaming. + (Symbolic_Traceback): Adjust. + * libgnat/s-dwalin.adb: Remove clauses for Ada.Exceptions.Traceback + and System.Traceback_Entries. + (Symbolic_Traceback): Adjust. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_ch4.adb (Find_Non_Universal_Interpretations): Check if + types are compatible before adding interpretation. + +2021-09-20 Justin Squirek <squirek@adacore.com> + + * exp_ch4.adb (Expand_N_Type_Conversion): Add guard to protect + against calculating accessibility levels against internal + compiler-generated types. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_dim.adb (Dimensions_Msg_Of): Capitalize comment. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * adabkend.adb (Scan_Back_End_Switches): Replace switch-scanning + logic with call to Backend_Utils.Scan_Common_Back_End_Switches. + * back_end.adb (Scan_Back_End_Switches): Replace switch-scanning + logic with call to Backend_Utils.Scan_Common_Back_End_Switches. + * backend_utils.adb: New file. + * backend_utils.ads: New file. + * gcc-interface/Make-lang.in: Add ada/backend_utils.o. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * atree.adb (Get_32_Bit_Field): Declare result before returning. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * exp_ch7.adb (Expand_N_Package_Body): Replace + Build_And_Insert_Cuda_Initialization with Expand_CUDA_Package. + * gnat_cuda.adb (Expand_CUDA_Package): New procedure. + (Build_And_Insert_Cuda_Initialization): Make internal. + * gnat_cuda.ads (Expand_CUDA_Package): New procedure. + (Build_And_Insert_Cuda_Initialization): Remove from spec. + +2021-09-20 Ghjuvan Lacambre <lacambre@adacore.com> + + * usage.adb (Usage): Update -gnatw.c messages. + +2021-09-20 Eric Botcazou <ebotcazou@adacore.com> + + * sem_aux.adb (Is_By_Reference_Type): Do not test Error_Posted. + 2021-09-15 Alexandre Oliva <oliva@adacore.com> * gcc-interface/utils.c: Include opts.h. diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl index fb851a6..db21f01 100644 --- a/gcc/ada/Makefile.rtl +++ b/gcc/ada/Makefile.rtl @@ -162,6 +162,7 @@ GNATRTL_NONTASKING_OBJS= \ a-coormu$(objext) \ a-coorse$(objext) \ a-coprnu$(objext) \ + a-costso$(objext) \ a-coteio$(objext) \ a-crbltr$(objext) \ a-crbtgk$(objext) \ @@ -1195,136 +1196,6 @@ ifeq ($(strip $(filter-out powerpc% wrs vxworks vxworksspe vxworks7% vxworks7spe endif endif -# PowerPC and e500v2 VxWorks 653 -ifeq ($(strip $(filter-out powerpc% wrs vxworksae vxworksaespe,$(target_cpu) $(target_vendor) $(target_os))),) - - ifeq ($(strip $(filter-out e500%, $(target_alias))),) - ARCH_STR=e500 - # gcc config translates the target e500v2-wrs-vxworks to - # powerpc-wrs-vxworksspe. Let's keep the original alias here when - # generating s-oscons.ads. - target=$(target_alias) - else - ARCH_STR=ppc - endif - - # target pairs for vthreads runtime - LIBGNAT_TARGET_PAIRS = \ - a-elchha.adb<libgnat/a-elchha__vxworks-ppc-full.adb \ - a-intnam.ads<libgnarl/a-intnam__vxworks.ads \ - a-naliop.ads<libgnat/a-naliop__nolibm.ads \ - a-nuaufl.ads<libgnat/a-nuaufl__wraplf.ads \ - a-nashfl.ads<libgnat/a-nashfl__wraplf.ads \ - g-io.adb<hie/g-io__vxworks-cert.adb \ - s-dorepr.adb<libgnat/s-dorepr__fma.adb \ - s-inmaop.adb<libgnarl/s-inmaop__vxworks.adb \ - s-interr.adb<libgnarl/s-interr__vxworks.adb \ - s-intman.ads<libgnarl/s-intman__vxworks.ads \ - s-intman.adb<libgnarl/s-intman__vxworks.adb \ - s-osinte.adb<libgnarl/s-osinte__vxworks.adb \ - s-osinte.ads<libgnarl/s-osinte__vxworks.ads \ - s-osprim.adb<libgnat/s-osprim__vxworks.adb \ - s-parame.ads<libgnat/s-parame__ae653.ads \ - s-parame.adb<libgnat/s-parame__vxworks.adb \ - s-taprop.adb<libgnarl/s-taprop__vxworks.adb \ - s-tasinf.ads<libgnarl/s-tasinf__vxworks.ads \ - s-taspri.ads<libgnarl/s-taspri__vxworks.ads \ - s-tpopsp.adb<libgnarl/s-tpopsp__vxworks.adb \ - s-vxwext.adb<libgnarl/s-vxwext__noints.adb \ - s-vxwext.ads<libgnarl/s-vxwext__vthreads.ads \ - s-vxwork.ads<libgnarl/s-vxwork__ppc.ads \ - $(ATOMICS_TARGET_PAIRS) \ - $(ATOMICS_BUILTINS_TARGET_PAIRS) \ - system.ads<libgnat/system-vxworks-$(ARCH_STR)-vthread.ads - - EH_MECHANISM=-gcc - - TOOLS_TARGET_PAIRS=indepsw.adb<indepsw-gnu.adb - - EXTRA_GNATRTL_NONTASKING_OBJS=i-vxwork.o i-vxwoio.o - EXTRA_GNATRTL_TASKING_OBJS=i-vxinco.o s-vxwork.o s-vxwext.o - - EXTRA_LIBGNAT_OBJS+=sigtramp-vxworks.o - EXTRA_LIBGNAT_SRCS+=$(VX_SIGTRAMP_EXTRA_SRCS) - - # Extra pairs for the vthreads runtime - ifeq ($(strip $(filter-out vthreads,$(THREAD_KIND))),) - LIBGNAT_TARGET_PAIRS += \ - s-thread.adb<libgnat/s-thread__ae653.adb \ - s-osvers.ads<libgnat/s-osvers__vxworks-653.ads \ - $(DUMMY_SOCKETS_TARGET_PAIRS) - - GNATRTL_SOCKETS_OBJS = - EXTRA_GNATRTL_NONTASKING_OBJS += s-thread.o s-osvers.o - else - LIBGNAT_TARGET_PAIRS += \ - g-socthi.ads<libgnat/g-socthi__vxworks.ads \ - g-socthi.adb<libgnat/g-socthi__vxworks.adb \ - g-sopowa.adb<libgnat/g-sopowa__posix.adb \ - g-stsifd.adb<libgnat/g-stsifd__sockets.adb - endif - -endif - -# VxWorksae / VxWorks 653 for x86 (vxsim) - ?? VxWorks mils not implemented -ifeq ($(strip $(filter-out %86 wrs vxworksae,$(target_cpu) $(target_vendor) $(target_os))),) - # target pairs for kernel + vthreads runtime - LIBGNAT_TARGET_PAIRS = \ - a-elchha.adb<libgnat/a-elchha__vxworks-ppc-full.adb \ - a-intnam.ads<libgnarl/a-intnam__vxworks.ads \ - a-naliop.ads<libgnat/a-naliop__nolibm.ads \ - a-nuaufl.ads<libgnat/a-nuaufl__wraplf.ads \ - a-nashfl.ads<libgnat/a-nashfl__wraplf.ads \ - g-io.adb<hie/g-io__vxworks-cert.adb \ - s-inmaop.adb<libgnarl/s-inmaop__vxworks.adb \ - s-interr.adb<libgnarl/s-interr__vxworks.adb \ - s-intman.ads<libgnarl/s-intman__vxworks.ads \ - s-intman.adb<libgnarl/s-intman__vxworks.adb \ - s-osinte.adb<libgnarl/s-osinte__vxworks.adb \ - s-osinte.ads<libgnarl/s-osinte__vxworks.ads \ - s-osprim.adb<libgnat/s-osprim__vxworks.adb \ - s-parame.ads<libgnat/s-parame__ae653.ads \ - s-parame.adb<libgnat/s-parame__vxworks.adb \ - s-taprop.adb<libgnarl/s-taprop__vxworks.adb \ - s-tasinf.ads<libgnarl/s-tasinf__vxworks.ads \ - s-taspri.ads<libgnarl/s-taspri__vxworks.ads \ - s-tpopsp.adb<libgnarl/s-tpopsp__vxworks.adb \ - s-vxwext.adb<libgnarl/s-vxwext__noints.adb \ - s-vxwext.ads<libgnarl/s-vxwext__vthreads.ads \ - s-vxwork.ads<libgnarl/s-vxwork__x86.ads \ - system.ads<libgnat/system-vxworks-x86-vthread.ads \ - $(ATOMICS_TARGET_PAIRS) \ - $(ATOMICS_BUILTINS_TARGET_PAIRS) - - EH_MECHANISM=-gcc - - TOOLS_TARGET_PAIRS=indepsw.adb<indepsw-gnu.adb - - EXTRA_GNATRTL_NONTASKING_OBJS=i-vxwork.o i-vxwoio.o s-thread.o - EXTRA_GNATRTL_TASKING_OBJS=i-vxinco.o s-vxwork.o s-vxwext.o - - EXTRA_LIBGNAT_OBJS+=vx_stack_info.o - GNATRTL_SOCKETS_OBJS = - - # Extra pairs for the vthreads runtime - ifeq ($(strip $(filter-out vthreads,$(THREAD_KIND))),) - LIBGNAT_TARGET_PAIRS += \ - s-thread.adb<libgnat/s-thread__ae653.adb \ - s-osvers.ads<libgnat/s-osvers__vxworks-653.ads \ - $(DUMMY_SOCKETS_TARGET_PAIRS) - - GNATRTL_SOCKETS_OBJS = - EXTRA_GNATRTL_NONTASKING_OBJS += s-thread.o s-osvers.o - else - LIBGNAT_TARGET_PAIRS += \ - g-socthi.ads<libgnat/g-socthi__vxworks.ads \ - g-socthi.adb<libgnat/g-socthi__vxworks.adb \ - g-sopowa.adb<libgnat/g-sopowa__posix.adb \ - g-stsifd.adb<libgnat/g-stsifd__sockets.adb - endif - -endif - # x86/x86_64 VxWorks ifeq ($(strip $(filter-out %86 x86_64 wrs vxworks vxworks7%,$(target_cpu) $(target_vendor) $(target_os))),) @@ -2195,6 +2066,11 @@ ifeq ($(strip $(filter-out rtems%,$(target_os))),) EH_MECHANISM=-gcc endif + ifeq ($(strip $(filter-out aarch64%,$(target_cpu))),) + LIBGNAT_TARGET_PAIRS += $(GNATRTL_128BIT_PAIRS) + EXTRA_GNATRTL_NONTASKING_OBJS += $(GNATRTL_128BIT_OBJS) + endif + ifeq ($(strip $(filter-out aarch64% riscv%,$(target_cpu))),) LIBGNAT_TARGET_PAIRS += a-nallfl.ads<libgnat/a-nallfl__wraplf.ads endif diff --git a/gcc/ada/adabkend.adb b/gcc/ada/adabkend.adb index 2ad58ef..118ca95 100644 --- a/gcc/ada/adabkend.adb +++ b/gcc/ada/adabkend.adb @@ -22,15 +22,16 @@ -- This is the version of the Back_End package for back ends written in Ada -with Atree; use Atree; +with Atree; use Atree; +with Backend_Utils; use Backend_Utils; with Debug; with Lib; -with Opt; use Opt; -with Output; use Output; -with Osint; use Osint; -with Osint.C; use Osint.C; -with Switch.C; use Switch.C; -with Types; use Types; +with Opt; use Opt; +with Output; use Output; +with Osint; use Osint; +with Osint.C; use Osint.C; +with Switch.C; use Switch.C; +with Types; use Types; with System.OS_Lib; use System.OS_Lib; @@ -182,48 +183,11 @@ package body Adabkend is return; - -- Special check, the back-end switch -fno-inline also sets the - -- front end flags to entirely inhibit all inlining. So we store it - -- and set the appropriate flags. - - elsif Switch_Chars (First .. Last) = "fno-inline" then - Lib.Store_Compilation_Switch (Switch_Chars); - Opt.Disable_FE_Inline := True; - return; - - -- Similar processing for -fpreserve-control-flow - - elsif Switch_Chars (First .. Last) = "fpreserve-control-flow" then - Lib.Store_Compilation_Switch (Switch_Chars); - Opt.Suppress_Control_Flow_Optimizations := True; - return; - - -- Recognize -gxxx switches - - elsif Switch_Chars (First) = 'g' then - Debugger_Level := 2; - - if First < Last then - case Switch_Chars (First + 1) is - when '0' => - Debugger_Level := 0; - when '1' => - Debugger_Level := 1; - when '2' => - Debugger_Level := 2; - when '3' => - Debugger_Level := 3; - when others => - null; - end case; - end if; - - elsif Switch_Chars (First .. Last) = "S" then - Generate_Asm := True; - -- Ignore all other back-end switches - elsif Is_Back_End_Switch (Switch_Chars) then + elsif Scan_Common_Back_End_Switch (Switch_Chars) + or else Is_Back_End_Switch (Switch_Chars) + then null; -- Give error for junk switch diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c index 06a4895..d4445f0 100644 --- a/gcc/ada/adaint.c +++ b/gcc/ada/adaint.c @@ -3542,6 +3542,9 @@ __gnat_get_executable_load_address (void) return (const void *)map->l_addr; +#elif defined (_WIN32) + return GetModuleHandle (NULL); + #else return NULL; #endif diff --git a/gcc/ada/atree.adb b/gcc/ada/atree.adb index c7e295b..540d4ff 100644 --- a/gcc/ada/atree.adb +++ b/gcc/ada/atree.adb @@ -513,8 +513,13 @@ package body Atree is function Cast is new Unchecked_Conversion (Field_Size_32_Bit, Field_Type); + + Result : constant Field_Type := Cast (Get_32_Bit_Val (N, Offset)); + -- Note: declaring Result here instead of directly returning + -- Cast (...) helps CodePeer understand that there are no issues + -- around uninitialized variables. begin - return Cast (Get_32_Bit_Val (N, Offset)); + return Result; end Get_32_Bit_Field; function Get_32_Bit_Field_With_Default @@ -1823,7 +1828,7 @@ package body Atree is function Parent (N : Node_Or_Entity_Id) return Node_Or_Entity_Id is begin - pragma Assert (Atree.Present (N)); + pragma Assert (Present (N)); if Is_List_Member (N) then return Parent (List_Containing (N)); @@ -2146,7 +2151,7 @@ package body Atree is procedure Set_Parent (N : Node_Or_Entity_Id; Val : Node_Or_Entity_Id) is begin - pragma Assert (Atree.Present (N)); + pragma Assert (Present (N)); pragma Assert (not In_List (N)); Set_Link (N, Union_Id (Val)); end Set_Parent; diff --git a/gcc/ada/back_end.adb b/gcc/ada/back_end.adb index 42d837d..abbd5ed 100644 --- a/gcc/ada/back_end.adb +++ b/gcc/ada/back_end.adb @@ -25,23 +25,24 @@ -- This is the version of the Back_End package for GCC back ends -with Atree; use Atree; -with Debug; use Debug; -with Elists; use Elists; -with Errout; use Errout; -with Lib; use Lib; -with Osint; use Osint; -with Opt; use Opt; -with Osint.C; use Osint.C; -with Namet; use Namet; -with Nlists; use Nlists; -with Stand; use Stand; -with Sinput; use Sinput; -with Stringt; use Stringt; -with Switch; use Switch; -with Switch.C; use Switch.C; -with System; use System; -with Types; use Types; +with Atree; use Atree; +with Backend_Utils; use Backend_Utils; +with Debug; use Debug; +with Elists; use Elists; +with Errout; use Errout; +with Lib; use Lib; +with Osint; use Osint; +with Opt; use Opt; +with Osint.C; use Osint.C; +with Namet; use Namet; +with Nlists; use Nlists; +with Stand; use Stand; +with Sinput; use Sinput; +with Stringt; use Stringt; +with Switch; use Switch; +with Switch.C; use Switch.C; +with System; use System; +with Types; use Types; with System.OS_Lib; use System.OS_Lib; @@ -266,52 +267,20 @@ package body Back_End is -- specific switches that the Ada front-end knows about. else - Store_Compilation_Switch (Switch_Chars); - - -- For gcc back ends, -fno-inline disables Inline pragmas only, - -- not Inline_Always to remain consistent with the always_inline - -- attribute behavior. - - if Switch_Chars (First .. Last) = "fno-inline" then - Opt.Disable_FE_Inline := True; - - -- Back end switch -fpreserve-control-flow also sets the front end - -- flag that inhibits improper control flow transformations. - - elsif Switch_Chars (First .. Last) = "fpreserve-control-flow" then - Opt.Suppress_Control_Flow_Optimizations := True; - - -- Back end switch -fdiagnostics-format=json tells the frontend to - -- output its error and warning messages in the same format GCC - -- uses when passed -fdiagnostics-format=json. - - elsif Switch_Chars (First .. Last) = "fdiagnostics-format=json" - then - Opt.JSON_Output := True; - - -- Back end switch -fdump-scos, which exists primarily for C, is - -- also accepted for Ada as a synonym of -gnateS. - - elsif Switch_Chars (First .. Last) = "fdump-scos" then - Opt.Generate_SCO := True; - Opt.Generate_SCO_Instance_Table := True; - - elsif Switch_Chars (First) = 'g' then - Debugger_Level := 2; - - if First < Last then - case Switch_Chars (First + 1) is - when '0' => - Debugger_Level := 0; - when '1' => - Debugger_Level := 1; - when '2' => - Debugger_Level := 2; - when '3' => - Debugger_Level := 3; - when others => - null; - end case; + + if not Scan_Common_Back_End_Switch (Switch_Chars) then + + -- Store compilation switch, as Scan_Common_Back_End_Switch + -- only stores switches it recognizes. + + Store_Compilation_Switch (Switch_Chars); + + -- Back end switch -fdump-scos, which exists primarily for C, + -- is also accepted for Ada as a synonym of -gnateS. + + if Switch_Chars (First .. Last) = "fdump-scos" then + Opt.Generate_SCO := True; + Opt.Generate_SCO_Instance_Table := True; end if; end if; end if; diff --git a/gcc/ada/backend_utils.adb b/gcc/ada/backend_utils.adb new file mode 100644 index 0000000..6f492fd --- /dev/null +++ b/gcc/ada/backend_utils.adb @@ -0,0 +1,96 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- B A C K E N D _ U T I L S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2021-2021, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT 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 distributed with GNAT; see file COPYING3. If not, go to -- +-- http://www.gnu.org/licenses for a complete copy of the license. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +with Lib; +with Opt; use Opt; +with Switch; use Switch; + +package body Backend_Utils is + + --------------------------------- + -- Scan_Common_Back_End_Switch -- + --------------------------------- + + function Scan_Common_Back_End_Switch (Switch_Chars : String) return Boolean + is + First : constant Positive := Switch_Chars'First + 1; + Last : constant Natural := Switch_Last (Switch_Chars); + begin + + -- Recognize -gxxx switches + + if Switch_Chars (First) = 'g' then + Debugger_Level := 2; + + if First < Last then + case Switch_Chars (First + 1) is + when '0' => + Debugger_Level := 0; + when '1' => + Debugger_Level := 1; + when '2' => + Debugger_Level := 2; + when '3' => + Debugger_Level := 3; + when others => + null; + end case; + end if; + + -- Back end switch -fdiagnostics-format=json tells the frontend to + -- output its error and warning messages in the same format GCC + -- uses when passed -fdiagnostics-format=json. + + elsif Switch_Chars (First .. Last) = "fdiagnostics-format=json" then + Opt.JSON_Output := True; + + -- Back-end switch -fno-inline also sets the front end flags to entirely + -- inhibit all inlining. So we store it and set the appropriate + -- flags. + -- For gcc back ends, -fno-inline disables Inline pragmas only, + -- not Inline_Always to remain consistent with the always_inline + -- attribute behavior. + + elsif Switch_Chars (First .. Last) = "fno-inline" then + Opt.Disable_FE_Inline := True; + + -- Back end switch -fpreserve-control-flow also sets the front end + -- flag that inhibits improper control flow transformations. + + elsif Switch_Chars (First .. Last) = "fpreserve-control-flow" then + Opt.Suppress_Control_Flow_Optimizations := True; + + elsif Switch_Chars (First .. Last) = "S" then + Generate_Asm := True; + + else + return False; + end if; + + Lib.Store_Compilation_Switch (Switch_Chars); + return True; + end Scan_Common_Back_End_Switch; + +end Backend_Utils; diff --git a/gcc/ada/backend_utils.ads b/gcc/ada/backend_utils.ads new file mode 100644 index 0000000..71321ef --- /dev/null +++ b/gcc/ada/backend_utils.ads @@ -0,0 +1,36 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- B A C K E N D _ U T I L S -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2021-2021, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT 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 distributed with GNAT; see file COPYING3. If not, go to -- +-- http://www.gnu.org/licenses for a complete copy of the license. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- Procedures and functions used by both the Adabkend and Back_End packages. + +package Backend_Utils is + + function Scan_Common_Back_End_Switch (Switch_Chars : String) return Boolean; + -- Scan back-end switches which are common to all back-ends and have an + -- effect in the front-end. Call Store_Compilation_Switch and return True + -- if Switch_Chars is recognized as a common back end switch. Return False + -- otherwise. + +end Backend_Utils; diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb index 0014f6a..049038b 100644 --- a/gcc/ada/bindgen.adb +++ b/gcc/ada/bindgen.adb @@ -588,6 +588,27 @@ package body Bindgen is WBI (""); end if; + -- Import the default stack object if a size has been provided to the + -- binder. + + if Opt.Default_Stack_Size /= Opt.No_Stack_Size then + WBI (" Default_Stack_Size : Integer;"); + WBI (" pragma Import (C, Default_Stack_Size, " & + """__gl_default_stack_size"");"); + end if; + + -- Initialize stack limit variable of the environment task if the + -- stack check method is stack limit and stack check is enabled. + + if Stack_Check_Limits_On_Target + and then (Stack_Check_Default_On_Target or Stack_Check_Switch_Set) + then + WBI (""); + WBI (" procedure Initialize_Stack_Limit;"); + WBI (" pragma Import (C, Initialize_Stack_Limit, " & + """__gnat_initialize_stack_limit"");"); + end if; + if System_Secondary_Stack_Package_In_Closure then -- System.Secondary_Stack is in the closure of the program -- because the program uses the secondary stack or the restricted @@ -619,6 +640,15 @@ package body Bindgen is WBI (" begin"); + -- Set the default stack size if provided to the binder + + if Opt.Default_Stack_Size /= Opt.No_Stack_Size then + Set_String (" Default_Stack_Size := "); + Set_Int (Default_Stack_Size); + Set_String (";"); + Write_Statement_Buffer; + end if; + if Main_Priority /= No_Main_Priority then Set_String (" Main_Priority := "); Set_Int (Main_Priority); @@ -643,6 +673,7 @@ package body Bindgen is end if; if Main_Priority = No_Main_Priority + and then Opt.Default_Stack_Size = Opt.No_Stack_Size and then Main_CPU = No_Main_CPU and then not System_Tasking_Restricted_Stages_Used then diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb index cebeac5..8f5c0b0 100644 --- a/gcc/ada/checks.adb +++ b/gcc/ada/checks.adb @@ -6892,6 +6892,7 @@ package body Checks is elsif Is_Known_Valid (Typ) then if Is_Entity_Name (Expr) and then Ekind (Entity (Expr)) = E_Variable + and then Known_Esize (Entity (Expr)) and then Esize (Entity (Expr)) > Esize (Typ) then return False; @@ -9059,7 +9060,7 @@ package body Checks is function In_Result_Range return Boolean is begin - if Lo = No_Uint or else Hi = No_Uint then + if No (Lo) or else No (Hi) then return False; elsif Is_OK_Static_Subtype (Etype (N)) then @@ -9080,7 +9081,7 @@ package body Checks is procedure Max (A : in out Uint; B : Uint) is begin - if A = No_Uint or else B > A then + if No (A) or else B > A then A := B; end if; end Max; @@ -9091,7 +9092,7 @@ package body Checks is procedure Min (A : in out Uint; B : Uint) is begin - if A = No_Uint or else B < A then + if No (A) or else B < A then A := B; end if; end Min; @@ -9197,14 +9198,14 @@ package body Checks is Minimize_Eliminate_Overflows (Then_DE, Lo, Hi, Top_Level => False); - if Lo = No_Uint then + if No (Lo) then Bignum_Operands := True; end if; Minimize_Eliminate_Overflows (Else_DE, Rlo, Rhi, Top_Level => False); - if Rlo = No_Uint then + if No (Rlo) then Bignum_Operands := True; else Long_Long_Integer_Operands := @@ -9279,7 +9280,7 @@ package body Checks is Minimize_Eliminate_Overflows (Aexp, Lo, Hi, Top_Level => False); - if Lo = No_Uint then + if No (Lo) then Bignum_Operands := True; elsif Etype (Aexp) = LLIB then Long_Long_Integer_Operands := True; @@ -9368,7 +9369,7 @@ package body Checks is -- numbers at compile time for very little gain (the number of cases -- in which we could slip back from bignum mode is small). - if Rlo = No_Uint or else (Binary and then Llo = No_Uint) then + if No (Rlo) or else (Binary and then No (Llo)) then Lo := No_Uint; Hi := No_Uint; Bignum_Operands := True; @@ -9441,7 +9442,7 @@ package body Checks is -- 0 .. 1, but the cases are rare and it is not worth the effort. -- Failing to do this switching back is only an efficiency issue. - elsif Lo = No_Uint or else Lo < LLLo or else Hi > LLHi then + elsif No (Lo) or else Lo < LLLo or else Hi > LLHi then -- OK, we are definitely outside the range of Long_Long_Integer. The -- question is whether to move to Bignum mode, or stay in the domain @@ -11306,7 +11307,7 @@ package body Checks is renames Alignment_Warnings.Table (J); begin if Known_Alignment (AWR.E) - and then ((AWR.A /= No_Uint + and then ((Present (AWR.A) and then AWR.A mod Alignment (AWR.E) = 0) or else (Present (AWR.P) and then Has_Compatible_Alignment diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb index d096cbb..e37e092 100644 --- a/gcc/ada/contracts.adb +++ b/gcc/ada/contracts.adb @@ -144,7 +144,13 @@ package body Contracts is -- Part_Of if Ekind (Id) = E_Constant then - if Prag_Nam = Name_Part_Of then + if Prag_Nam in Name_Async_Readers + | Name_Async_Writers + | Name_Effective_Reads + | Name_Effective_Writes + | Name_No_Caching + | Name_Part_Of + then Add_Classification; -- The pragma is not a proper contract item @@ -778,25 +784,9 @@ package body Contracts is procedure Check_Type_Or_Object_External_Properties (Type_Or_Obj_Id : Entity_Id) is - function Decl_Kind (Is_Type : Boolean; - Object_Kind : String) return String; - -- Returns "type" or Object_Kind, depending on Is_Type - - --------------- - -- Decl_Kind -- - --------------- - - function Decl_Kind (Is_Type : Boolean; - Object_Kind : String) return String is - begin - if Is_Type then - return "type"; - else - return Object_Kind; - end if; - end Decl_Kind; - Is_Type_Id : constant Boolean := Is_Type (Type_Or_Obj_Id); + Decl_Kind : constant String := + (if Is_Type_Id then "type" else "object"); -- Local variables @@ -923,8 +913,7 @@ package body Contracts is if not Is_Library_Level_Entity (Type_Or_Obj_Id) then Error_Msg_N ("effectively volatile " - & Decl_Kind (Is_Type => Is_Type_Id, - Object_Kind => "variable") + & Decl_Kind & " & must be declared at library level " & "(SPARK RM 7.1.3(3))", Type_Or_Obj_Id); @@ -935,10 +924,7 @@ package body Contracts is and then not Is_Protected_Type (Obj_Typ) then Error_Msg_N - ("discriminated " - & Decl_Kind (Is_Type => Is_Type_Id, - Object_Kind => "object") - & " & cannot be volatile", + ("discriminated " & Decl_Kind & " & cannot be volatile", Type_Or_Obj_Id); end if; @@ -1019,7 +1005,7 @@ package body Contracts is Saved_SMP : constant Node_Id := SPARK_Mode_Pragma; -- Save the SPARK_Mode-related data to restore on exit - NC_Val : Boolean := False; + NC_Val : Boolean; Items : Node_Id; Prag : Node_Id; Ref_Elmt : Elmt_Id; @@ -1056,6 +1042,19 @@ package body Contracts is Set_SPARK_Mode (Obj_Id); end if; + -- Checks related to external properties, same for constants and + -- variables. + + Check_Type_Or_Object_External_Properties (Type_Or_Obj_Id => Obj_Id); + + -- Analyze the non-external volatility property No_Caching + + Prag := Get_Pragma (Obj_Id, Pragma_No_Caching); + + if Present (Prag) then + Analyze_External_Property_In_Decl_Part (Prag, NC_Val); + end if; + -- Constant-related checks if Ekind (Obj_Id) = E_Constant then @@ -1071,35 +1070,10 @@ package body Contracts is Check_Missing_Part_Of (Obj_Id); end if; - -- A constant cannot be effectively volatile (SPARK RM 7.1.3(4)). - -- This check is relevant only when SPARK_Mode is on, as it is not - -- a standard Ada legality rule. Internally-generated constants that - -- map generic formals to actuals in instantiations are allowed to - -- be volatile. - - if SPARK_Mode = On - and then Comes_From_Source (Obj_Id) - and then Is_Effectively_Volatile (Obj_Id) - and then No (Corresponding_Generic_Association (Parent (Obj_Id))) - then - Error_Msg_N ("constant cannot be volatile", Obj_Id); - end if; - -- Variable-related checks else pragma Assert (Ekind (Obj_Id) = E_Variable); - Check_Type_Or_Object_External_Properties - (Type_Or_Obj_Id => Obj_Id); - - -- Analyze the non-external volatility property No_Caching - - Prag := Get_Pragma (Obj_Id, Pragma_No_Caching); - - if Present (Prag) then - Analyze_External_Property_In_Decl_Part (Prag, NC_Val); - end if; - -- The anonymous object created for a single task type carries -- pragmas Depends and Global of the type. diff --git a/gcc/ada/cstand.adb b/gcc/ada/cstand.adb index 44cb69c..409944c 100644 --- a/gcc/ada/cstand.adb +++ b/gcc/ada/cstand.adb @@ -205,7 +205,7 @@ package body CStand is Mutate_Ekind (E, E_Floating_Point_Type); Set_Etype (E, E); - Init_Digits_Value (E, Digs); + Set_Digits_Value (E, UI_From_Int (Digs)); Set_Float_Rep (E, Rep); Init_Size (E, Siz); Set_Elem_Alignment (E, Align); @@ -578,6 +578,8 @@ package body CStand is Set_Has_Pragma_Pack (String_Type, True); end Pack_String_Type; + Char_Size : constant Unat := UI_From_Int (Standard_Character_Size); + -- Start of processing for Create_Standard begin @@ -652,8 +654,8 @@ package body CStand is Mutate_Ekind (Standard_Boolean, E_Enumeration_Type); Set_First_Literal (Standard_Boolean, Standard_False); Set_Etype (Standard_Boolean, Standard_Boolean); - Init_Esize (Standard_Boolean, Standard_Character_Size); - Init_RM_Size (Standard_Boolean, 1); + Set_Esize (Standard_Boolean, Char_Size); + Set_RM_Size (Standard_Boolean, Uint_1); Set_Elem_Alignment (Standard_Boolean); Set_Is_Unsigned_Type (Standard_Boolean); @@ -757,8 +759,8 @@ package body CStand is Mutate_Ekind (Standard_Character, E_Enumeration_Type); Set_Etype (Standard_Character, Standard_Character); - Init_Esize (Standard_Character, Standard_Character_Size); - Init_RM_Size (Standard_Character, 8); + Set_Esize (Standard_Character, Char_Size); + Set_RM_Size (Standard_Character, Uint_8); Set_Elem_Alignment (Standard_Character); Set_Has_Pragma_Ordered (Standard_Character); @@ -912,7 +914,7 @@ package body CStand is Set_Etype (Standard_String, Standard_String); Set_Component_Type (Standard_String, Standard_Character); Set_Component_Size (Standard_String, Uint_8); - Init_Size_Align (Standard_String); + Reinit_Size_Align (Standard_String); Set_Alignment (Standard_String, Uint_1); Pack_String_Type (Standard_String); @@ -956,7 +958,7 @@ package body CStand is Set_Etype (Standard_Wide_String, Standard_Wide_String); Set_Component_Type (Standard_Wide_String, Standard_Wide_Character); Set_Component_Size (Standard_Wide_String, Uint_16); - Init_Size_Align (Standard_Wide_String); + Reinit_Size_Align (Standard_Wide_String); Pack_String_Type (Standard_Wide_String); -- Set index type of Wide_String @@ -993,7 +995,7 @@ package body CStand is Set_Component_Type (Standard_Wide_Wide_String, Standard_Wide_Wide_Character); Set_Component_Size (Standard_Wide_Wide_String, Uint_32); - Init_Size_Align (Standard_Wide_Wide_String); + Reinit_Size_Align (Standard_Wide_Wide_String); Set_Is_Ada_2005_Only (Standard_Wide_Wide_String); Pack_String_Type (Standard_Wide_Wide_String); @@ -1009,10 +1011,10 @@ package body CStand is -- Setup entity for Natural - Mutate_Ekind (Standard_Natural, E_Signed_Integer_Subtype); - Set_Etype (Standard_Natural, Base_Type (Standard_Integer)); - Init_Esize (Standard_Natural, Standard_Integer_Size); - Init_RM_Size (Standard_Natural, Standard_Integer_Size - 1); + Mutate_Ekind (Standard_Natural, E_Signed_Integer_Subtype); + Set_Etype (Standard_Natural, Base_Type (Standard_Integer)); + Set_Esize (Standard_Natural, UI_From_Int (Standard_Integer_Size)); + Set_RM_Size (Standard_Natural, UI_From_Int (Standard_Integer_Size - 1)); Set_Elem_Alignment (Standard_Natural); Set_Size_Known_At_Compile_Time (Standard_Natural); @@ -1024,10 +1026,11 @@ package body CStand is -- Setup entity for Positive - Mutate_Ekind (Standard_Positive, E_Signed_Integer_Subtype); - Set_Etype (Standard_Positive, Base_Type (Standard_Integer)); - Init_Esize (Standard_Positive, Standard_Integer_Size); - Init_RM_Size (Standard_Positive, Standard_Integer_Size - 1); + Mutate_Ekind (Standard_Positive, E_Signed_Integer_Subtype); + Set_Etype (Standard_Positive, Base_Type (Standard_Integer)); + Set_Esize (Standard_Positive, UI_From_Int (Standard_Integer_Size)); + Set_RM_Size + (Standard_Positive, UI_From_Int (Standard_Integer_Size - 1)); Set_Elem_Alignment (Standard_Positive); Set_Size_Known_At_Compile_Time (Standard_Positive); @@ -1132,7 +1135,7 @@ package body CStand is Init_Size (Standard_A_String, System_Address_Size * 2); end if; - Init_Alignment (Standard_A_String); + pragma Assert (not Known_Alignment (Standard_A_String)); Set_Directly_Designated_Type (Standard_A_String, Standard_String); @@ -1156,14 +1159,14 @@ package body CStand is Mutate_Ekind (Standard_Debug_Renaming_Type, E_Signed_Integer_Subtype); Set_Scope (Standard_Debug_Renaming_Type, Standard_Standard); Set_Etype (Standard_Debug_Renaming_Type, Base_Type (Standard_Integer)); - Init_Esize (Standard_Debug_Renaming_Type, 0); - Init_RM_Size (Standard_Debug_Renaming_Type, 0); + Set_Esize (Standard_Debug_Renaming_Type, Uint_0); + Set_RM_Size (Standard_Debug_Renaming_Type, Uint_0); Set_Size_Known_At_Compile_Time (Standard_Debug_Renaming_Type); - Set_Integer_Bounds (Standard_Debug_Renaming_Type, - Typ => Base_Type (Standard_Debug_Renaming_Type), + Set_Integer_Bounds (Standard_Debug_Renaming_Type, + Typ => Base_Type (Standard_Debug_Renaming_Type), Lb => Uint_1, Hb => Uint_0); - Set_Is_Constrained (Standard_Debug_Renaming_Type); + Set_Is_Constrained (Standard_Debug_Renaming_Type); Set_Has_Size_Clause (Standard_Debug_Renaming_Type); -- Note on type names. The type names for the following special types @@ -1186,8 +1189,8 @@ package body CStand is Mutate_Ekind (Any_Id, E_Variable); Set_Scope (Any_Id, Standard_Standard); Set_Etype (Any_Id, Any_Type); - Init_Esize (Any_Id); - Init_Alignment (Any_Id); + pragma Assert (not Known_Esize (Any_Id)); + pragma Assert (not Known_Alignment (Any_Id)); Any_Access := New_Standard_Entity ("an access type"); Mutate_Ekind (Any_Access, E_Access_Type); @@ -1204,8 +1207,8 @@ package body CStand is Set_Etype (Any_Character, Any_Character); Set_Is_Unsigned_Type (Any_Character); Set_Is_Character_Type (Any_Character); - Init_Esize (Any_Character, Standard_Character_Size); - Init_RM_Size (Any_Character, 8); + Set_Esize (Any_Character, Char_Size); + Set_RM_Size (Any_Character, Uint_8); Set_Elem_Alignment (Any_Character); Set_Scalar_Range (Any_Character, Scalar_Range (Standard_Character)); @@ -1214,15 +1217,15 @@ package body CStand is Set_Scope (Any_Array, Standard_Standard); Set_Etype (Any_Array, Any_Array); Set_Component_Type (Any_Array, Any_Character); - Init_Size_Align (Any_Array); + Reinit_Size_Align (Any_Array); Make_Dummy_Index (Any_Array); Any_Boolean := New_Standard_Entity ("a boolean type"); Mutate_Ekind (Any_Boolean, E_Enumeration_Type); Set_Scope (Any_Boolean, Standard_Standard); Set_Etype (Any_Boolean, Standard_Boolean); - Init_Esize (Any_Boolean, Standard_Character_Size); - Init_RM_Size (Any_Boolean, 1); + Set_Esize (Any_Boolean, Char_Size); + Set_RM_Size (Any_Boolean, Uint_1); Set_Elem_Alignment (Any_Boolean); Set_Is_Unsigned_Type (Any_Boolean); Set_Scalar_Range (Any_Boolean, Scalar_Range (Standard_Boolean)); @@ -1233,7 +1236,7 @@ package body CStand is Set_Etype (Any_Composite, Any_Composite); Set_Component_Size (Any_Composite, Uint_0); Set_Component_Type (Any_Composite, Standard_Integer); - Init_Size_Align (Any_Composite); + Reinit_Size_Align (Any_Composite); Any_Discrete := New_Standard_Entity ("a discrete type"); Mutate_Ekind (Any_Discrete, E_Signed_Integer_Type); @@ -1297,7 +1300,7 @@ package body CStand is Set_Scope (Any_String, Standard_Standard); Set_Etype (Any_String, Any_String); Set_Component_Type (Any_String, Any_Character); - Init_Size_Align (Any_String); + Reinit_Size_Align (Any_String); Make_Dummy_Index (Any_String); Raise_Type := New_Standard_Entity ("raise type"); @@ -1506,7 +1509,7 @@ package body CStand is Set_Scope (Standard_Exception_Type, Standard_Standard); Set_Stored_Constraint (Standard_Exception_Type, No_Elist); - Init_Size_Align (Standard_Exception_Type); + Set_RM_Size (Standard_Exception_Type, Uint_0); Set_Size_Known_At_Compile_Time (Standard_Exception_Type, True); @@ -1726,7 +1729,7 @@ package body CStand is Mutate_Ekind (Id, E_Component); Set_Etype (Id, Typ); Set_Scope (Id, Rec); - Init_Component_Location (Id); + Reinit_Component_Location (Id); Set_Original_Record_Component (Id, Id); Set_Is_Aliased (Id); Set_Is_Independent (Id); diff --git a/gcc/ada/einfo-utils.adb b/gcc/ada/einfo-utils.adb index 4690c8f..15bd9e8 100644 --- a/gcc/ada/einfo-utils.adb +++ b/gcc/ada/einfo-utils.adb @@ -358,131 +358,179 @@ package body Einfo.Utils is return Ekind (Id) in Type_Kind; end Is_Type; - ----------------------------------- - -- Field Initialization Routines -- - ----------------------------------- + ------------------------------------------ + -- Type Representation Attribute Fields -- + ------------------------------------------ - procedure Init_Alignment (Id : E) is + function Known_Alignment (E : Entity_Id) return B is begin - Reinit_Field_To_Zero (Id, F_Alignment); - end Init_Alignment; + return not Field_Is_Initial_Zero (E, F_Alignment); + end Known_Alignment; - procedure Init_Alignment (Id : E; V : Int) is + procedure Reinit_Alignment (Id : E) is begin - Set_Alignment (Id, UI_From_Int (V)); - end Init_Alignment; + Reinit_Field_To_Zero (Id, F_Alignment); + end Reinit_Alignment; - procedure Init_Component_Bit_Offset (Id : E) is + procedure Copy_Alignment (To, From : E) is begin - Set_Component_Bit_Offset (Id, No_Uint); - end Init_Component_Bit_Offset; + if Known_Alignment (From) then + Set_Alignment (To, Alignment (From)); + else + Reinit_Alignment (To); + end if; + end Copy_Alignment; - procedure Init_Component_Bit_Offset (Id : E; V : Int) is + function Known_Component_Bit_Offset (E : Entity_Id) return B is begin - Set_Component_Bit_Offset (Id, UI_From_Int (V)); - end Init_Component_Bit_Offset; + return Present (Component_Bit_Offset (E)); + end Known_Component_Bit_Offset; - procedure Init_Component_Size (Id : E) is + function Known_Static_Component_Bit_Offset (E : Entity_Id) return B is begin - Set_Component_Size (Id, Uint_0); - end Init_Component_Size; + return Present (Component_Bit_Offset (E)) + and then Component_Bit_Offset (E) >= Uint_0; + end Known_Static_Component_Bit_Offset; - procedure Init_Component_Size (Id : E; V : Int) is + function Known_Component_Size (E : Entity_Id) return B is begin - Set_Component_Size (Id, UI_From_Int (V)); - end Init_Component_Size; + return Component_Size (E) /= Uint_0 + and then Present (Component_Size (E)); + end Known_Component_Size; - procedure Init_Digits_Value (Id : E) is + function Known_Static_Component_Size (E : Entity_Id) return B is begin - Set_Digits_Value (Id, Uint_0); - end Init_Digits_Value; + return Component_Size (E) > Uint_0; + end Known_Static_Component_Size; - procedure Init_Digits_Value (Id : E; V : Int) is + Use_New_Unknown_Rep : constant Boolean := False; + -- If False, we represent "unknown" as Uint_0, which is wrong. + -- We intend to make it True (and remove it), and represent + -- "unknown" as Field_Is_Initial_Zero. We also need to change + -- the type of Esize and RM_Size from Uint to Valid_Uint. + + function Known_Esize (E : Entity_Id) return B is begin - Set_Digits_Value (Id, UI_From_Int (V)); - end Init_Digits_Value; + if Use_New_Unknown_Rep then + return not Field_Is_Initial_Zero (E, F_Esize); + else + return Esize (E) /= Uint_0 + and then Present (Esize (E)); + end if; + end Known_Esize; - procedure Init_Esize (Id : E) is + function Known_Static_Esize (E : Entity_Id) return B is begin - Set_Esize (Id, Uint_0); - end Init_Esize; + return Known_Esize (E) + and then Esize (E) >= Uint_0 + and then not Is_Generic_Type (E); + end Known_Static_Esize; - procedure Init_Esize (Id : E; V : Int) is + procedure Reinit_Esize (Id : E) is begin - Set_Esize (Id, UI_From_Int (V)); - end Init_Esize; + if Use_New_Unknown_Rep then + Reinit_Field_To_Zero (Id, F_Esize); + else + Set_Esize (Id, Uint_0); + end if; + end Reinit_Esize; - procedure Init_Normalized_First_Bit (Id : E) is + procedure Copy_Esize (To, From : E) is begin - Set_Normalized_First_Bit (Id, No_Uint); - end Init_Normalized_First_Bit; + if Known_Esize (From) then + Set_Esize (To, Esize (From)); + else + Reinit_Esize (To); + end if; + end Copy_Esize; - procedure Init_Normalized_First_Bit (Id : E; V : Int) is + function Known_Normalized_First_Bit (E : Entity_Id) return B is begin - Set_Normalized_First_Bit (Id, UI_From_Int (V)); - end Init_Normalized_First_Bit; + return Present (Normalized_First_Bit (E)); + end Known_Normalized_First_Bit; - procedure Init_Normalized_Position (Id : E) is + function Known_Static_Normalized_First_Bit (E : Entity_Id) return B is begin - Set_Normalized_Position (Id, No_Uint); - end Init_Normalized_Position; + return Present (Normalized_First_Bit (E)) + and then Normalized_First_Bit (E) >= Uint_0; + end Known_Static_Normalized_First_Bit; - procedure Init_Normalized_Position (Id : E; V : Int) is + function Known_Normalized_Position (E : Entity_Id) return B is begin - Set_Normalized_Position (Id, UI_From_Int (V)); - end Init_Normalized_Position; + return Present (Normalized_Position (E)); + end Known_Normalized_Position; - procedure Init_Normalized_Position_Max (Id : E) is + function Known_Static_Normalized_Position (E : Entity_Id) return B is begin - Set_Normalized_Position_Max (Id, No_Uint); - end Init_Normalized_Position_Max; + return Present (Normalized_Position (E)) + and then Normalized_Position (E) >= Uint_0; + end Known_Static_Normalized_Position; - procedure Init_Normalized_Position_Max (Id : E; V : Int) is + function Known_RM_Size (E : Entity_Id) return B is begin - Set_Normalized_Position_Max (Id, UI_From_Int (V)); - end Init_Normalized_Position_Max; + if Use_New_Unknown_Rep then + return not Field_Is_Initial_Zero (E, F_RM_Size); + else + return Present (RM_Size (E)) + and then (RM_Size (E) /= Uint_0 + or else Is_Discrete_Type (E) + or else Is_Fixed_Point_Type (E)); + end if; + end Known_RM_Size; - procedure Init_RM_Size (Id : E) is + function Known_Static_RM_Size (E : Entity_Id) return B is begin - Set_RM_Size (Id, Uint_0); - end Init_RM_Size; + if Use_New_Unknown_Rep then + return Known_RM_Size (E) + and then RM_Size (E) >= Uint_0 + and then not Is_Generic_Type (E); + else + return (RM_Size (E) > Uint_0 + or else Is_Discrete_Type (E) + or else Is_Fixed_Point_Type (E)) + and then not Is_Generic_Type (E); + end if; + end Known_Static_RM_Size; - procedure Init_RM_Size (Id : E; V : Int) is + procedure Reinit_RM_Size (Id : E) is begin - Set_RM_Size (Id, UI_From_Int (V)); - end Init_RM_Size; + if Use_New_Unknown_Rep then + Reinit_Field_To_Zero (Id, F_RM_Size); + else + Set_RM_Size (Id, Uint_0); + end if; + end Reinit_RM_Size; - procedure Copy_Alignment (To, From : E) is + procedure Copy_RM_Size (To, From : E) is begin - if Known_Alignment (From) then - Set_Alignment (To, Alignment (From)); + if Known_RM_Size (From) then + Set_RM_Size (To, RM_Size (From)); else - Init_Alignment (To); + Reinit_RM_Size (To); end if; - end Copy_Alignment; + end Copy_RM_Size; - ----------------------------- - -- Init_Component_Location -- - ----------------------------- + ------------------------------- + -- Reinit_Component_Location -- + ------------------------------- - procedure Init_Component_Location (Id : E) is + procedure Reinit_Component_Location (Id : E) is begin - Set_Normalized_First_Bit (Id, No_Uint); - Set_Normalized_Position_Max (Id, No_Uint); + Set_Normalized_First_Bit (Id, No_Uint); Set_Component_Bit_Offset (Id, No_Uint); - Set_Esize (Id, Uint_0); + Reinit_Esize (Id); Set_Normalized_Position (Id, No_Uint); - end Init_Component_Location; + end Reinit_Component_Location; - ---------------------------- - -- Init_Object_Size_Align -- - ---------------------------- + ------------------------------ + -- Reinit_Object_Size_Align -- + ------------------------------ - procedure Init_Object_Size_Align (Id : E) is + procedure Reinit_Object_Size_Align (Id : E) is begin - Init_Esize (Id); - Init_Alignment (Id); - end Init_Object_Size_Align; + Reinit_Esize (Id); + Reinit_Alignment (Id); + end Reinit_Object_Size_Align; --------------- -- Init_Size -- @@ -491,120 +539,25 @@ package body Einfo.Utils is procedure Init_Size (Id : E; V : Int) is begin pragma Assert (Is_Type (Id)); - pragma Assert - (not Known_Esize (Id) or else Esize (Id) = V); - pragma Assert - (RM_Size (Id) = No_Uint - or else RM_Size (Id) = Uint_0 - or else RM_Size (Id) = V); + pragma Assert (not Known_Esize (Id) or else Esize (Id) = V); + if Use_New_Unknown_Rep then + pragma Assert (not Known_RM_Size (Id) or else RM_Size (Id) = V); + end if; Set_Esize (Id, UI_From_Int (V)); Set_RM_Size (Id, UI_From_Int (V)); end Init_Size; - --------------------- - -- Init_Size_Align -- - --------------------- + ----------------------- + -- Reinit_Size_Align -- + ----------------------- - procedure Init_Size_Align (Id : E) is + procedure Reinit_Size_Align (Id : E) is begin pragma Assert (Ekind (Id) in Type_Kind | E_Void); - Init_Esize (Id); - Init_RM_Size (Id); - Init_Alignment (Id); - end Init_Size_Align; - - ---------------------------------------------- - -- Type Representation Attribute Predicates -- - ---------------------------------------------- - - function Known_Alignment (E : Entity_Id) return B is - Result : constant B := not Field_Is_Initial_Zero (E, F_Alignment); - begin - return Result; - end Known_Alignment; - - function Known_Component_Bit_Offset (E : Entity_Id) return B is - begin - return Component_Bit_Offset (E) /= No_Uint; - end Known_Component_Bit_Offset; - - function Known_Component_Size (E : Entity_Id) return B is - begin - return Component_Size (E) /= Uint_0 - and then Component_Size (E) /= No_Uint; - end Known_Component_Size; - - function Known_Esize (E : Entity_Id) return B is - begin - return Esize (E) /= Uint_0 - and then Esize (E) /= No_Uint; - end Known_Esize; - - function Known_Normalized_First_Bit (E : Entity_Id) return B is - begin - return Normalized_First_Bit (E) /= No_Uint; - end Known_Normalized_First_Bit; - - function Known_Normalized_Position (E : Entity_Id) return B is - begin - return Normalized_Position (E) /= No_Uint; - end Known_Normalized_Position; - - function Known_Normalized_Position_Max (E : Entity_Id) return B is - begin - return Normalized_Position_Max (E) /= No_Uint; - end Known_Normalized_Position_Max; - - function Known_RM_Size (E : Entity_Id) return B is - begin - return RM_Size (E) /= No_Uint - and then (RM_Size (E) /= Uint_0 - or else Is_Discrete_Type (E) - or else Is_Fixed_Point_Type (E)); - end Known_RM_Size; - - function Known_Static_Component_Bit_Offset (E : Entity_Id) return B is - begin - return Component_Bit_Offset (E) /= No_Uint - and then Component_Bit_Offset (E) >= Uint_0; - end Known_Static_Component_Bit_Offset; - - function Known_Static_Component_Size (E : Entity_Id) return B is - begin - return Component_Size (E) > Uint_0; - end Known_Static_Component_Size; - - function Known_Static_Esize (E : Entity_Id) return B is - begin - return Esize (E) > Uint_0 - and then not Is_Generic_Type (E); - end Known_Static_Esize; - - function Known_Static_Normalized_First_Bit (E : Entity_Id) return B is - begin - return Normalized_First_Bit (E) /= No_Uint - and then Normalized_First_Bit (E) >= Uint_0; - end Known_Static_Normalized_First_Bit; - - function Known_Static_Normalized_Position (E : Entity_Id) return B is - begin - return Normalized_Position (E) /= No_Uint - and then Normalized_Position (E) >= Uint_0; - end Known_Static_Normalized_Position; - - function Known_Static_Normalized_Position_Max (E : Entity_Id) return B is - begin - return Normalized_Position_Max (E) /= No_Uint - and then Normalized_Position_Max (E) >= Uint_0; - end Known_Static_Normalized_Position_Max; - - function Known_Static_RM_Size (E : Entity_Id) return B is - begin - return (RM_Size (E) > Uint_0 - or else Is_Discrete_Type (E) - or else Is_Fixed_Point_Type (E)) - and then not Is_Generic_Type (E); - end Known_Static_RM_Size; + Reinit_Esize (Id); + Reinit_RM_Size (Id); + Reinit_Alignment (Id); + end Reinit_Size_Align; -------------------- -- Address_Clause -- diff --git a/gcc/ada/einfo-utils.ads b/gcc/ada/einfo-utils.ads index a6517b9..4eca35e 100644 --- a/gcc/ada/einfo-utils.ads +++ b/gcc/ada/einfo-utils.ads @@ -310,75 +310,115 @@ package Einfo.Utils is pragma Inline (Type_High_Bound); pragma Inline (Type_Low_Bound); - ---------------------------------------------- - -- Type Representation Attribute Predicates -- - ---------------------------------------------- - - -- These predicates test the setting of the indicated attribute. The - -- Known predicate is True if and only if the value has been set. The - -- Known_Static predicate is True only if the value is set (Known) and is - -- set to a compile time known value. Note that in the case of Alignment - -- and Normalized_First_Bit, dynamic values are not possible, so we do not - -- need a separate Known_Static calls in these cases. The not set (unknown) - -- values are as follows: - - -- Alignment Uint_0 or No_Uint - -- Component_Size Uint_0 or No_Uint - -- Component_Bit_Offset No_Uint - -- Digits_Value Uint_0 or No_Uint - -- Esize Uint_0 or No_Uint - -- Normalized_First_Bit No_Uint - -- Normalized_Position No_Uint - -- Normalized_Position_Max No_Uint - -- RM_Size Uint_0 or No_Uint - - -- It would be cleaner to use No_Uint in all these cases, but historically - -- we chose to use Uint_0 at first, and the change over will take time ??? - -- This is particularly true for the RM_Size field, where a value of zero - -- is legitimate. We deal with this by a considering that the value is - -- always known static for discrete types (and no other types can have - -- an RM_Size value of zero). - + ------------------------------------------ + -- Type Representation Attribute Fields -- + ------------------------------------------ + + -- Each of the following fields can be in a "known" or "unknown" state: + + -- Alignment + -- Component_Size + -- Component_Bit_Offset + -- Digits_Value + -- Esize + -- Normalized_First_Bit + -- Normalized_Position + -- RM_Size + -- + -- NOTE: "known" here does not mean "known at compile time". It means that + -- the compiler has computed the value of the field (either by default, or + -- by noting some representation clauses), and the field has not been + -- reinitialized. + -- + -- We document the Esize functions here; the others are analogous: + -- + -- Known_Esize: True if Set_Esize has been called without a subsequent + -- Reinit_Esize. + -- + -- Known_Static_Esize: True if Known_Esize and the Esize is known at + -- compile time. (We're not using "static" in the Ada RM sense here. We + -- are using it to mean "known at compile time.) + -- + -- Reinit_Esize: Set the Esize field to its initial unknown state. + -- + -- Copy_Esize: Copies the Esize from From to To; Known_Esize (From) may + -- be False, in which case Known_Esize (To) becomes False. + -- + -- Esize: This is the normal automatially-generated getter for Esize, + -- declared elsewhere. It is an error to call this if Set_Esize has not + -- yet been called, or if Reinit_Esize has been called subsequently. + -- + -- Set_Esize: This is the normal automatially-generated setter for + -- Esize. After a call to this, Known_Esize is True. It is an error + -- to call this with a No_Uint value. + -- + -- Normally, we call Set_Esize first, and then query Esize (and similarly + -- for other fields). However in some cases, we need to check Known_Esize + -- before calling Esize, because the code is written in such a way that we + -- don't know whether Set_Esize has already been called. + -- + -- We intend to use the initial zero value to represent "unknown". Note + -- that this value is different from No_Uint, and different from Uint_0. + -- However, this is work in progress; we are still using No_Uint or Uint_0 + -- to represent "unknown" in some cases. Using Uint_0 leads to several + -- bugs, because zero is a legitimate value (T'Size can be zero bits) -- + -- Uint_0 shouldn't mean two different things. + -- -- In two cases, Known_Static_Esize and Known_Static_RM_Size, there is one -- more consideration, which is that we always return False for generic - -- types. Within a template, the size can look known, because of the fake - -- size values we put in template types, but they are not really known and - -- anyone testing if they are known within the template should get False as - -- a result to prevent incorrect assumptions. - - function Known_Alignment (E : Entity_Id) return B; - function Known_Component_Bit_Offset (E : Entity_Id) return B; - function Known_Component_Size (E : Entity_Id) return B; - function Known_Esize (E : Entity_Id) return B; - function Known_Normalized_First_Bit (E : Entity_Id) return B; - function Known_Normalized_Position (E : Entity_Id) return B; - function Known_Normalized_Position_Max (E : Entity_Id) return B; - function Known_RM_Size (E : Entity_Id) return B; - - function Known_Static_Component_Bit_Offset (E : Entity_Id) return B; - function Known_Static_Component_Size (E : Entity_Id) return B; - function Known_Static_Esize (E : Entity_Id) return B; - function Known_Static_Normalized_First_Bit (E : Entity_Id) return B; - function Known_Static_Normalized_Position (E : Entity_Id) return B; - function Known_Static_Normalized_Position_Max (E : Entity_Id) return B; - function Known_Static_RM_Size (E : Entity_Id) return B; - - pragma Inline (Known_Alignment); - pragma Inline (Known_Component_Bit_Offset); - pragma Inline (Known_Component_Size); - pragma Inline (Known_Esize); - pragma Inline (Known_Normalized_First_Bit); - pragma Inline (Known_Normalized_Position); - pragma Inline (Known_Normalized_Position_Max); - pragma Inline (Known_RM_Size); - - pragma Inline (Known_Static_Component_Bit_Offset); - pragma Inline (Known_Static_Component_Size); - pragma Inline (Known_Static_Esize); - pragma Inline (Known_Static_Normalized_First_Bit); - pragma Inline (Known_Static_Normalized_Position); - pragma Inline (Known_Static_Normalized_Position_Max); - pragma Inline (Known_Static_RM_Size); + -- types. Within a template, the size can look Known_Static, because of the + -- fake size values we put in template types, but they are not really + -- Known_Static and anyone testing if they are Known_Static within the + -- template should get False as a result to prevent incorrect assumptions. + + function Known_Alignment (E : Entity_Id) return B with Inline; + procedure Reinit_Alignment (Id : E) with Inline; + procedure Copy_Alignment (To, From : E); + + function Known_Component_Bit_Offset (E : Entity_Id) return B with Inline; + function Known_Static_Component_Bit_Offset (E : Entity_Id) return B + with Inline; + + function Known_Component_Size (E : Entity_Id) return B with Inline; + function Known_Static_Component_Size (E : Entity_Id) return B with Inline; + + function Known_Esize (E : Entity_Id) return B with Inline; + function Known_Static_Esize (E : Entity_Id) return B with Inline; + procedure Reinit_Esize (Id : E) with Inline; + procedure Copy_Esize (To, From : E); + + function Known_Normalized_First_Bit (E : Entity_Id) return B with Inline; + function Known_Static_Normalized_First_Bit (E : Entity_Id) return B + with Inline; + + function Known_Normalized_Position (E : Entity_Id) return B with Inline; + function Known_Static_Normalized_Position (E : Entity_Id) return B + with Inline; + + function Known_RM_Size (E : Entity_Id) return B with Inline; + function Known_Static_RM_Size (E : Entity_Id) return B with Inline; + procedure Reinit_RM_Size (Id : E) with Inline; + procedure Copy_RM_Size (To, From : E); + + --------------------------------------------------------- + -- Procedures for setting multiple of the above fields -- + --------------------------------------------------------- + + procedure Reinit_Component_Location (Id : E); + -- Initializes all fields describing the location of a component + -- (Normalized_Position, Component_Bit_Offset, Normalized_First_Bit, + -- Esize) to all be Unknown. + + procedure Init_Size (Id : E; V : Int); + -- Initialize both the Esize and RM_Size fields of E to V + + procedure Reinit_Size_Align (Id : E); + -- This procedure initializes both size fields and the alignment + -- field to all be Unknown. + + procedure Reinit_Object_Size_Align (Id : E); + -- Same as Reinit_Size_Align except RM_Size field (which is only for types) + -- is unaffected. --------------------------------------------------- -- Access to Subprograms in Subprograms_For_Type -- @@ -404,89 +444,6 @@ package Einfo.Utils is procedure Set_Predicate_Function (Id : E; V : E); procedure Set_Predicate_Function_M (Id : E; V : E); - ----------------------------------- - -- Field Initialization Routines -- - ----------------------------------- - - -- These routines are overloadings of some of the above Set procedures - -- where the argument is normally a Uint. The overloadings take an Int - -- parameter instead, and appropriately convert it. There are also - -- versions that implicitly initialize to the appropriate "not set" - -- value. The not set (unknown) values are as follows: - - -- Alignment Uint_0 - -- Component_Size Uint_0 - -- Component_Bit_Offset No_Uint - -- Digits_Value Uint_0 - -- Esize Uint_0 - -- Normalized_First_Bit No_Uint - -- Normalized_Position No_Uint - -- Normalized_Position_Max No_Uint - -- RM_Size Uint_0 - - -- It would be cleaner to use No_Uint in all these cases, but historically - -- we chose to use Uint_0 at first, and the change over will take time ??? - -- This is particularly true for the RM_Size field, where a value of zero - -- is legitimate and causes some special tests around the code. - - -- Contrary to the corresponding Set procedures above, these routines - -- do NOT check the entity kind of their argument, instead they set the - -- underlying Uint fields directly (this allows them to be used for - -- entities whose Ekind has not been set yet). - - procedure Init_Alignment (Id : E; V : Int); - procedure Init_Component_Bit_Offset (Id : E; V : Int); - procedure Init_Component_Size (Id : E; V : Int); - procedure Init_Digits_Value (Id : E; V : Int); - procedure Init_Esize (Id : E; V : Int); - procedure Init_Normalized_First_Bit (Id : E; V : Int); - procedure Init_Normalized_Position (Id : E; V : Int); - procedure Init_Normalized_Position_Max (Id : E; V : Int); - procedure Init_RM_Size (Id : E; V : Int); - - procedure Init_Alignment (Id : E); - procedure Init_Component_Bit_Offset (Id : E); - procedure Init_Component_Size (Id : E); - procedure Init_Digits_Value (Id : E); - procedure Init_Esize (Id : E); - procedure Init_Normalized_First_Bit (Id : E); - procedure Init_Normalized_Position (Id : E); - procedure Init_Normalized_Position_Max (Id : E); - procedure Init_RM_Size (Id : E); - - -- The following Copy_xxx procedures copy the value of xxx from From to - -- To. If xxx is set to its initial invalid (zero-bits) value, then it is - -- reset to invalid in To. We only have Copy_Alignment so far, but more are - -- planned. - - procedure Copy_Alignment (To, From : E); - - pragma Inline (Init_Alignment); - pragma Inline (Init_Component_Bit_Offset); - pragma Inline (Init_Component_Size); - pragma Inline (Init_Digits_Value); - pragma Inline (Init_Esize); - pragma Inline (Init_Normalized_First_Bit); - pragma Inline (Init_Normalized_Position); - pragma Inline (Init_Normalized_Position_Max); - pragma Inline (Init_RM_Size); - - procedure Init_Component_Location (Id : E); - -- Initializes all fields describing the location of a component - -- (Normalized_Position, Component_Bit_Offset, Normalized_First_Bit, - -- Normalized_Position_Max, Esize) to all be Unknown. - - procedure Init_Size (Id : E; V : Int); - -- Initialize both the Esize and RM_Size fields of E to V - - procedure Init_Size_Align (Id : E); - -- This procedure initializes both size fields and the alignment - -- field to all be Unknown. - - procedure Init_Object_Size_Align (Id : E); - -- Same as Init_Size_Align except RM_Size field (which is only for types) - -- is unaffected. - --------------- -- Iterators -- --------------- diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads index e87ce4c..39ddd66 100644 --- a/gcc/ada/einfo.ads +++ b/gcc/ada/einfo.ads @@ -3762,17 +3762,6 @@ package Einfo is -- units from the start of the record to the lowest addressed storage -- unit containing part or all of the field. --- Normalized_Position_Max --- Defined in components and discriminants. For almost all cases, this --- is the same as Normalized_Position. The one exception is for the case --- of a discriminated record containing one or more arrays whose length --- depends on discriminants. In this case, the Normalized_Position_Max --- field represents the maximum possible value of Normalized_Position --- assuming min/max values for discriminant subscripts in all fields. --- This is used by Layout in front end layout mode to properly compute --- the maximum size of such records (needed for allocation purposes when --- there are default discriminants, and also for the 'Size value). - -- Number_Dimensions (synthesized) -- Applies to array types and subtypes. Returns the number of dimensions -- of the array type or subtype as a value of type Pos. @@ -5228,7 +5217,6 @@ package Einfo is -- Linker_Section_Pragma $$$ -- Normalized_First_Bit -- Current_Value (always Empty) - -- Normalized_Position_Max -- Component_Bit_Offset -- Esize -- Component_Clause @@ -5328,7 +5316,6 @@ package Einfo is -- E_Discriminant -- Normalized_First_Bit -- Current_Value (always Empty) - -- Normalized_Position_Max -- Component_Bit_Offset -- Esize -- Component_Clause diff --git a/gcc/ada/errout.adb b/gcc/ada/errout.adb index 0122304..99c7f9a 100644 --- a/gcc/ada/errout.adb +++ b/gcc/ada/errout.adb @@ -106,15 +106,15 @@ package body Errout is Opan : Source_Span; Msg_Cont : Boolean; Node : Node_Id); - -- This is the low level routine used to post messages after dealing with + -- This is the low-level routine used to post messages after dealing with -- the issue of messages placed on instantiations (which get broken up - -- into separate calls in Error_Msg). Sptr is the location on which the + -- into separate calls in Error_Msg). Span is the location on which the -- flag will be placed in the output. In the case where the flag is on -- the template, this points directly to the template, not to one of the - -- instantiation copies of the template. Optr is the original location + -- instantiation copies of the template. Opan is the original location -- used to flag the error, and this may indeed point to an instantiation - -- copy. So typically we can see Optr pointing to the template location - -- in an instantiation copy when Sptr points to the source location of + -- copy. So typically we can see Opan pointing to the template location + -- in an instantiation copy when Span points to the source location of -- the actual instantiation (i.e the line with the new). Msg_Cont is -- set true if this is a continuation message. Node is the relevant -- Node_Id for this message, to be used to compute the enclosing entity if @@ -2473,7 +2473,8 @@ package body Errout is function Get_Line_End (Buf : Source_Buffer_Ptr; Loc : Source_Ptr) return Source_Ptr; - -- Get the source location for the end of the line in Buf for Loc + -- Get the source location for the end of the line in Buf for Loc. If + -- Loc is past the end of Buf already, return Buf'Last. function Get_Line_Start (Buf : Source_Buffer_Ptr; @@ -2515,9 +2516,9 @@ package body Errout is (Buf : Source_Buffer_Ptr; Loc : Source_Ptr) return Source_Ptr is - Cur_Loc : Source_Ptr := Loc; + Cur_Loc : Source_Ptr := Source_Ptr'Min (Loc, Buf'Last); begin - while Cur_Loc <= Buf'Last + while Cur_Loc < Buf'Last and then Buf (Cur_Loc) /= ASCII.LF loop Cur_Loc := Cur_Loc + 1; @@ -2692,9 +2693,7 @@ package body Errout is Write_Buffer_Char (Buf, Cur_Loc); end if; - Cur_Loc := Cur_Loc + 1; - - if Buf (Cur_Loc - 1) = ASCII.LF then + if Buf (Cur_Loc) = ASCII.LF then Cur_Line := Cur_Line + 1; -- Output ... for skipped lines @@ -2719,6 +2718,8 @@ package body Errout is Width); end if; end if; + + Cur_Loc := Cur_Loc + 1; end loop; end; diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index 1b08436..88303c9 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -504,7 +504,7 @@ package body Exp_Aggr is -- Scalar types are OK if their size is a multiple of Storage_Unit elsif Is_Scalar_Type (Ctyp) then - pragma Assert (Csiz /= No_Uint); + pragma Assert (Present (Csiz)); if Csiz mod System_Storage_Unit /= 0 then return False; @@ -4003,7 +4003,7 @@ package body Exp_Aggr is and then Present (First_Index (Etype (Expr_Q))) then declare - Expr_Q_Type : constant Node_Id := Etype (Expr_Q); + Expr_Q_Type : constant Entity_Id := Etype (Expr_Q); begin Append_List_To (L, Build_Array_Aggr_Code diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index fc6b0ef..c962c2a 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -5530,6 +5530,21 @@ package body Exp_Attr is end if; end Pred; + ---------------------------------- + -- Preelaborable_Initialization -- + ---------------------------------- + + when Attribute_Preelaborable_Initialization => + + -- This attribute should already be folded during analysis, but if + -- for some reason it hasn't been, we fold it now. + + Fold_Uint + (N, + UI_From_Int + (Boolean'Pos (Has_Preelaborable_Initialization (Ptyp))), + Static => False); + -------------- -- Priority -- -------------- @@ -7339,7 +7354,7 @@ package body Exp_Attr is if Nkind (P) in N_Has_Entity and then Present (Entity (P)) and then Is_Object (Entity (P)) - and then Esize (Entity (P)) /= Uint_0 + and then Known_Esize (Entity (P)) then if Esize (Entity (P)) <= System_Max_Integer_Size then Size := Esize (Entity (P)); @@ -8028,7 +8043,7 @@ package body Exp_Attr is -- Common processing for record and array component case - if Siz /= No_Uint and then Siz /= 0 then + if Present (Siz) and then Siz /= 0 then declare CS : constant Boolean := Comes_From_Source (N); diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index ad82e56..45d5baf 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -3421,7 +3421,8 @@ package body Exp_Ch3 is Clean_Task_Names (Typ, Proc_Id); - -- Simple initialization + -- Simple initialization. If the Esize is not yet set, we pass + -- Uint_0 as expected by Get_Simple_Init_Val. elsif Component_Needs_Simple_Initialization (Typ) then Actions := @@ -3431,7 +3432,9 @@ package body Exp_Ch3 is Get_Simple_Init_Val (Typ => Typ, N => N, - Size => Esize (Id))); + Size => + (if Known_Esize (Id) then Esize (Id) + else Uint_0))); -- Nothing needed for this case @@ -6507,7 +6510,8 @@ package body Exp_Ch3 is Get_Simple_Init_Val (Typ => Typ, N => Obj_Def, - Size => Esize (Def_Id))); + Size => (if Known_Esize (Def_Id) then Esize (Def_Id) + else Uint_0))); Analyze_And_Resolve (Expression (N), Typ, Suppress => All_Checks); @@ -6534,7 +6538,8 @@ package body Exp_Ch3 is Get_Simple_Init_Val (Typ => Typ, N => Obj_Def, - Size => Esize (Def_Id))); + Size => + (if Known_Esize (Def_Id) then Esize (Def_Id) else Uint_0))); Analyze_And_Resolve (Expression (N), Typ); end if; @@ -8506,7 +8511,7 @@ package body Exp_Ch3 is if Compile_Time_Known_Value (Lo) then Lo_Val := Expr_Value (Lo); - if Lo_Bound = No_Uint or else Lo_Bound < Lo_Val then + if No (Lo_Bound) or else Lo_Bound < Lo_Val then Lo_Bound := Lo_Val; end if; end if; @@ -8514,7 +8519,7 @@ package body Exp_Ch3 is if Compile_Time_Known_Value (Hi) then Hi_Val := Expr_Value (Hi); - if Hi_Bound = No_Uint or else Hi_Bound > Hi_Val then + if No (Hi_Bound) or else Hi_Bound > Hi_Val then Hi_Bound := Hi_Val; end if; end if; @@ -8643,7 +8648,7 @@ package body Exp_Ch3 is -- If zero is invalid, it is a convenient value to use that is for -- sure an appropriate invalid value in all situations. - elsif Lo_Bound /= No_Uint and then Lo_Bound > Uint_0 then + elsif Present (Lo_Bound) and then Lo_Bound > Uint_0 then return Make_Integer_Literal (Loc, 0); -- Unsigned types @@ -8702,7 +8707,7 @@ package body Exp_Ch3 is -- If zero is invalid, it is a convenient value to use that is for -- sure an appropriate invalid value in all situations. - if Lo_Bound /= No_Uint and then Lo_Bound > Uint_0 then + if Present (Lo_Bound) and then Lo_Bound > Uint_0 then Expr := Make_Integer_Literal (Loc, 0); -- Cases where all one bits is the appropriate invalid value @@ -8741,7 +8746,7 @@ package body Exp_Ch3 is -- For this exceptional case, use largest positive value - if Lo_Bound /= No_Uint and then Hi_Bound /= No_Uint + if Present (Lo_Bound) and then Present (Hi_Bound) and then Lo_Bound <= (-(2 ** Signed_Size)) and then Hi_Bound < 2 ** Signed_Size then @@ -8811,7 +8816,7 @@ package body Exp_Ch3 is -- Determine the size of the object. This is either the size provided -- by the caller, or the Esize of the scalar type. - if Size = No_Uint or else Size <= Uint_0 then + if No (Size) or else Size <= Uint_0 then Size_To_Use := UI_Max (Uint_1, Esize (Typ)); else Size_To_Use := Size; @@ -8821,7 +8826,7 @@ package body Exp_Ch3 is -- will create values of type Long_Long_Long_Unsigned and the range -- must fit this type. - if Size_To_Use /= No_Uint + if Present (Size_To_Use) and then Size_To_Use > System_Max_Integer_Size then Size_To_Use := UI_From_Int (System_Max_Integer_Size); diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 16f513e..497a52b 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -767,8 +767,7 @@ package body Exp_Ch4 is Cond := Make_Op_Gt (Loc, Left_Opnd => Cond, - Right_Opnd => - Make_Integer_Literal (Loc, Type_Access_Level (PtrT))); + Right_Opnd => Accessibility_Level (N, Dynamic_Level)); -- Due to the complexity and side effects of the check, utilize an -- if statement instead of the regular Program_Error circuitry. @@ -2294,7 +2293,7 @@ package body Exp_Ch4 is -- We can only do this if we in fact have full range information (which -- won't be the case if either operand is bignum at this stage). - if Llo /= No_Uint and then Rlo /= No_Uint then + if Present (Llo) and then Present (Rlo) then case N_Op_Compare (Nkind (N)) is when N_Op_Eq => if Llo = Lhi and then Rlo = Rhi and then Llo = Rlo then @@ -7763,8 +7762,8 @@ package body Exp_Ch4 is if Is_Unchecked_Union (Op_Type) then declare - Lhs_Type : constant Node_Id := Etype (L_Exp); - Rhs_Type : constant Node_Id := Etype (R_Exp); + Lhs_Type : constant Entity_Id := Etype (L_Exp); + Rhs_Type : constant Entity_Id := Etype (R_Exp); Lhs_Discr_Vals : Elist_Id; -- List of inferred discriminant values for left operand. @@ -12361,10 +12360,16 @@ package body Exp_Ch4 is -- an instantiation, otherwise the conversion will already have been -- rejected as illegal. - -- Note: warnings are issued by the analyzer for the instance cases + -- Note: warnings are issued by the analyzer for the instance cases, + -- and, since we are late in expansion, a check is performed to + -- verify that neither the target type nor the operand type are + -- internally generated - as this can lead to spurious errors when, + -- for example, the operand type is a result of BIP expansion. elsif In_Instance_Body and then Statically_Deeper_Relation_Applies (Target_Type) + and then not Is_Internal (Target_Type) + and then not Is_Internal (Operand_Type) and then Type_Access_Level (Operand_Type) > Type_Access_Level (Target_Type) then diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb index 8ac9662..9827326 100644 --- a/gcc/ada/exp_ch5.adb +++ b/gcc/ada/exp_ch5.adb @@ -742,8 +742,8 @@ package body Exp_Ch5 is -- in the front end. declare - L_Index_Typ : constant Node_Id := Etype (First_Index (L_Type)); - R_Index_Typ : constant Node_Id := Etype (First_Index (R_Type)); + L_Index_Typ : constant Entity_Id := Etype (First_Index (L_Type)); + R_Index_Typ : constant Entity_Id := Etype (First_Index (R_Type)); Left_Lo : constant Node_Id := Type_Low_Bound (L_Index_Typ); Left_Hi : constant Node_Id := Type_High_Bound (L_Index_Typ); @@ -1382,8 +1382,8 @@ package body Exp_Ch5 is Loc : constant Source_Ptr := Sloc (N); - L_Index_Typ : constant Node_Id := Etype (First_Index (L_Type)); - R_Index_Typ : constant Node_Id := Etype (First_Index (R_Type)); + L_Index_Typ : constant Entity_Id := Etype (First_Index (L_Type)); + R_Index_Typ : constant Entity_Id := Etype (First_Index (R_Type)); Left_Lo : constant Node_Id := Type_Low_Bound (L_Index_Typ); Right_Lo : constant Node_Id := Type_Low_Bound (R_Index_Typ); @@ -1698,8 +1698,8 @@ package body Exp_Ch5 is (Etype (Left_Base_Index))) and then RTE_Available (RE_Fast_Copy_Bitfield) then - pragma Assert (Esize (L_Type) /= 0); - pragma Assert (Esize (R_Type) /= 0); + pragma Assert (Known_Esize (L_Type)); + pragma Assert (Known_Esize (R_Type)); return Expand_Assign_Array_Bitfield_Fast (N, Larray, Rarray); end if; diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 59704a4..7717fa7 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -4520,6 +4520,8 @@ package body Exp_Ch6 is or else (Is_Record_Type (Formal_Typ) and then Is_Record_Type (Parent_Typ))) + and then Known_Esize (Formal_Typ) + and then Known_Esize (Parent_Typ) and then (Esize (Formal_Typ) /= Esize (Parent_Typ) or else Has_Pragma_Pack (Formal_Typ) /= @@ -7435,6 +7437,10 @@ package body Exp_Ch6 is and then not Is_Class_Wide_Type (Utyp) and then (Nkind (Exp) in N_Type_Conversion | N_Unchecked_Type_Conversion + or else (Nkind (Exp) = N_Explicit_Dereference + and then Nkind (Prefix (Exp)) in + N_Type_Conversion | + N_Unchecked_Type_Conversion) or else (Is_Entity_Name (Exp) and then Is_Formal (Entity (Exp)))) then diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb index f7807ac..8d08ff1 100644 --- a/gcc/ada/exp_ch7.adb +++ b/gcc/ada/exp_ch7.adb @@ -5918,12 +5918,7 @@ package body Exp_Ch7 is Build_Static_Dispatch_Tables (N); end if; - -- If procedures marked with CUDA_Global have been defined within N, - -- we need to register them with the CUDA runtime at program startup. - -- This requires multiple declarations and function calls which need - -- to be appended to N's declarations. - - Build_And_Insert_CUDA_Initialization (N); + Expand_CUDA_Package (N); Build_Task_Activation_Call (N); @@ -6072,7 +6067,7 @@ package body Exp_Ch7 is Pop_Scope; end if; - -- Build dispatch tables of library level tagged types + -- Build dispatch tables of library-level tagged types if Tagged_Type_Expansion and then (Is_Compilation_Unit (Id) @@ -9560,8 +9555,11 @@ package body Exp_Ch7 is -- If initialization procedure for an array of controlled objects is -- trivial, do not generate a useless call to it. + -- The initialization procedure may be missing altogether in the case + -- of a derived container whose components have trivial initialization. - if (Is_Array_Type (Utyp) and then Is_Trivial_Subprogram (Proc)) + if No (Proc) + or else (Is_Array_Type (Utyp) and then Is_Trivial_Subprogram (Proc)) or else (not Comes_From_Source (Proc) and then Present (Alias (Proc)) diff --git a/gcc/ada/exp_dbug.adb b/gcc/ada/exp_dbug.adb index bfc3b33..a375169 100644 --- a/gcc/ada/exp_dbug.adb +++ b/gcc/ada/exp_dbug.adb @@ -438,7 +438,7 @@ package body Exp_Dbug is Enable or else Is_Packed (Underlying_Type (Etype (Prefix (Ren)))) - or else (First_Bit /= No_Uint + or else (Present (First_Bit) and then First_Bit /= Uint_0); end; diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb index e9d6e74..bac6492 100644 --- a/gcc/ada/exp_disp.adb +++ b/gcc/ada/exp_disp.adb @@ -93,10 +93,6 @@ package body Exp_Disp is -- Duplicate_Subexpr with an explicit dereference when From is an access -- parameter. - function Original_View_In_Visible_Part (Typ : Entity_Id) return Boolean; - -- Check if the type has a private view or if the public view appears in - -- the visible part of a package spec. - function Prim_Op_Kind (Prim : Entity_Id; Typ : Entity_Id) return Node_Id; @@ -581,7 +577,7 @@ package body Exp_Disp is -- If number of primitives already set in the tag component, use it if Present (Tag_Comp) - and then DT_Entry_Count (Tag_Comp) /= No_Uint + and then Present (DT_Entry_Count (Tag_Comp)) then return UI_To_Int (DT_Entry_Count (Tag_Comp)); @@ -4716,7 +4712,7 @@ package body Exp_Disp is Exname : Entity_Id; HT_Link : Entity_Id; ITable : Node_Id; - I_Depth : Nat := 0; + I_Depth : Nat; Iface_Table_Node : Node_Id; Name_ITable : Name_Id; Nb_Prim : Nat := 0; @@ -6614,7 +6610,6 @@ package body Exp_Disp is Append_Elmt (DT, DT_Decl); Analyze_List (Result, Suppress => All_Checks); - Set_Has_Dispatch_Table (Typ); -- Mark entities containing dispatch tables. Required by the backend to -- handle them properly. @@ -6647,6 +6642,8 @@ package body Exp_Disp is <<Leave_SCIL>> + Set_Has_Dispatch_Table (Typ); + -- Register the tagged type in the call graph nodes table Register_CG_Node (Typ); @@ -7394,31 +7391,6 @@ package body Exp_Disp is end if; end New_Value; - ----------------------------------- - -- Original_View_In_Visible_Part -- - ----------------------------------- - - function Original_View_In_Visible_Part (Typ : Entity_Id) return Boolean is - Scop : constant Entity_Id := Scope (Typ); - - begin - -- The scope must be a package - - if not Is_Package_Or_Generic_Package (Scop) then - return False; - end if; - - -- A type with a private declaration has a private view declared in - -- the visible part. - - if Has_Private_Declaration (Typ) then - return True; - end if; - - return List_Containing (Parent (Typ)) = - Visible_Declarations (Package_Specification (Scop)); - end Original_View_In_Visible_Part; - ------------------ -- Prim_Op_Kind -- ------------------ @@ -8036,14 +8008,14 @@ package body Exp_Disp is (Find_Dispatching_Type (Interface_Alias (Prim)), Typ, Use_Full_View => True) then - pragma Assert (DT_Position (Prim) = No_Uint - and then Present (DTC_Entity (Interface_Alias (Prim)))); + pragma Assert (No (DT_Position (Prim))); + pragma Assert (Present (DTC_Entity (Interface_Alias (Prim)))); E := Interface_Alias (Prim); Set_DT_Position_Value (Prim, DT_Position (E)); pragma Assert - (DT_Position (Alias (Prim)) = No_Uint + (No (DT_Position (Alias (Prim))) or else DT_Position (Alias (Prim)) = DT_Position (E)); Set_DT_Position_Value (Alias (Prim), DT_Position (E)); Set_Fixed_Prim (UI_To_Int (DT_Position (Prim))); @@ -8094,7 +8066,7 @@ package body Exp_Disp is -- Skip primitives previously set entries - if DT_Position (Prim) /= No_Uint then + if Present (DT_Position (Prim)) then null; -- Primitives covering interface primitives are handled later @@ -8127,7 +8099,7 @@ package body Exp_Disp is while Present (Prim_Elmt) loop Prim := Node (Prim_Elmt); - if DT_Position (Prim) = No_Uint + if No (DT_Position (Prim)) and then Present (Interface_Alias (Prim)) then pragma Assert (Present (Alias (Prim)) @@ -8139,14 +8111,14 @@ package body Exp_Disp is (Find_Dispatching_Type (Interface_Alias (Prim)), Typ, Use_Full_View => True) then - pragma Assert (DT_Position (Alias (Prim)) /= No_Uint); + pragma Assert (Present (DT_Position (Alias (Prim)))); Set_DT_Position_Value (Prim, DT_Position (Alias (Prim))); -- Otherwise it will be placed in the secondary DT else pragma Assert - (DT_Position (Interface_Alias (Prim)) /= No_Uint); + (Present (DT_Position (Interface_Alias (Prim)))); Set_DT_Position_Value (Prim, DT_Position (Interface_Alias (Prim))); end if; @@ -8175,7 +8147,7 @@ package body Exp_Disp is -- At this point all the primitives MUST have a position in the -- dispatch table. - if DT_Position (Prim) = No_Uint then + if No (DT_Position (Prim)) then raise Program_Error; end if; @@ -8795,7 +8767,7 @@ package body Exp_Disp is -- (primary or secondary) dispatch table. if Present (DTC_Entity (Prim)) - and then DT_Position (Prim) /= No_Uint + and then Present (DT_Position (Prim)) then Write_Str (" at #"); Write_Int (UI_To_Int (DT_Position (Prim))); diff --git a/gcc/ada/exp_pakd.adb b/gcc/ada/exp_pakd.adb index 88f86f4..779dbb3 100644 --- a/gcc/ada/exp_pakd.adb +++ b/gcc/ada/exp_pakd.adb @@ -493,7 +493,7 @@ package body Exp_Pakd is Ancest : Entity_Id; PB_Type : Entity_Id; - PASize : Uint; + PASize : Uint := No_Uint; Decl : Node_Id; PAT : Entity_Id; Len_Expr : Node_Id; @@ -563,19 +563,21 @@ package body Exp_Pakd is -- Do not reset RM_Size if already set, as happens in the case of -- a modular type. - if not Known_Esize (PAT) then - Set_Esize (PAT, PASize); - end if; + if Present (PASize) then + if not Known_Esize (PAT) then + Set_Esize (PAT, PASize); + end if; - if not Known_RM_Size (PAT) then - Set_RM_Size (PAT, PASize); + if not Known_RM_Size (PAT) then + Set_RM_Size (PAT, PASize); + end if; end if; Adjust_Esize_Alignment (PAT); -- Set remaining fields of packed array type - Init_Alignment (PAT); + Reinit_Alignment (PAT); Set_Parent (PAT, Empty); Set_Associated_Node_For_Itype (PAT, Typ); Set_Original_Array_Type (PAT, Typ); @@ -680,7 +682,9 @@ package body Exp_Pakd is -- type, since this size clearly belongs to the packed array type. The -- size of the conceptual unpacked type is always set to unknown. - PASize := RM_Size (Typ); + if Known_RM_Size (Typ) then + PASize := RM_Size (Typ); + end if; -- Case of an array where at least one index is of an enumeration -- type with a non-standard representation, but the component size @@ -943,7 +947,7 @@ package body Exp_Pakd is Make_Integer_Literal (Loc, 0), High_Bound => Lit)))); - if PASize = Uint_0 then + if Present (PASize) then PASize := Len_Bits; end if; @@ -1973,6 +1977,7 @@ package body Exp_Pakd is Rtyp : Entity_Id; PAT : Entity_Id; Lit : Node_Id; + Size : Unat; begin Convert_To_Actual_Subtype (Opnd); @@ -1994,9 +1999,15 @@ package body Exp_Pakd is -- where PAT is the packed array type, Mask is a mask of all 1 bits of -- length equal to the size of this packed type, and Rtyp is the actual - -- actual subtype of the operand. + -- actual subtype of the operand. Preserve old behavior in case size is + -- not set. - Lit := Make_Integer_Literal (Loc, 2 ** RM_Size (PAT) - 1); + if Known_RM_Size (PAT) then + Size := RM_Size (PAT); + else + Size := Uint_0; + end if; + Lit := Make_Integer_Literal (Loc, 2 ** Size - 1); Set_Print_In_Hex (Lit); if not Is_Array_Type (PAT) then diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 2584041..ad5a6fa 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -4892,6 +4892,9 @@ package body Exp_Util is then return False; + elsif not Known_Normalized_First_Bit (Comp) then + return True; + -- Otherwise if the component is not byte aligned, we know we have the -- nasty unaligned case. @@ -6589,6 +6592,7 @@ package body Exp_Util is Related_Id : Entity_Id := Empty; Is_Low_Bound : Boolean := False; Is_High_Bound : Boolean := False; + Discr_Number : Int := 0; Mode : Force_Evaluation_Mode := Relaxed) is begin @@ -6600,6 +6604,7 @@ package body Exp_Util is Related_Id => Related_Id, Is_Low_Bound => Is_Low_Bound, Is_High_Bound => Is_High_Bound, + Discr_Number => Discr_Number, Check_Side_Effects => Is_Static_Expression (Exp) or else Mode = Relaxed); @@ -10992,26 +10997,25 @@ package body Exp_Util is -- At the current time, the only types that we return False for (i.e. where -- we decide we know they cannot generate large temps) are ones where we -- know the size is 256 bits or less at compile time, and we are still not - -- doing a thorough job on arrays and records ??? + -- doing a thorough job on arrays and records. function May_Generate_Large_Temp (Typ : Entity_Id) return Boolean is begin if not Size_Known_At_Compile_Time (Typ) then return False; + end if; - elsif Esize (Typ) /= 0 and then Esize (Typ) <= 256 then + if Known_Esize (Typ) and then Esize (Typ) <= 256 then return False; + end if; - elsif Is_Array_Type (Typ) + if Is_Array_Type (Typ) and then Present (Packed_Array_Impl_Type (Typ)) then return May_Generate_Large_Temp (Packed_Array_Impl_Type (Typ)); - - -- We could do more here to find other small types ??? - - else - return True; end if; + + return True; end May_Generate_Large_Temp; -------------------------------------------- @@ -11623,6 +11627,7 @@ package body Exp_Util is Related_Id : Entity_Id := Empty; Is_Low_Bound : Boolean := False; Is_High_Bound : Boolean := False; + Discr_Number : Int := 0; Check_Side_Effects : Boolean := True) is function Build_Temporary @@ -11651,19 +11656,45 @@ package body Exp_Util is is Temp_Id : Entity_Id; Temp_Nam : Name_Id; + Should_Set_Related_Expression : Boolean := False; begin - -- The context requires an external symbol + -- The context requires an external symbol : expression is + -- the bound of an array, or a discriminant value. We create + -- a unique string using the related entity and an appropriate + -- suffix, rather than a numeric serial number (used for internal + -- entities) that may vary depending on compilation options, in + -- particular on the Assertions_Enabled mode. This avoids spurious + -- link errors. if Present (Related_Id) then if Is_Low_Bound then Temp_Nam := New_External_Name (Chars (Related_Id), "_FIRST"); - else pragma Assert (Is_High_Bound); + + elsif Is_High_Bound then Temp_Nam := New_External_Name (Chars (Related_Id), "_LAST"); + + else + pragma Assert (Discr_Number > 0); + + -- We don't have any intelligible way of printing T_DISCR in + -- CodePeer. Thus, set a related expression in this case. + + Should_Set_Related_Expression := True; + + -- Use fully qualified name to avoid ambiguities. + + Temp_Nam := + New_External_Name + (Get_Qualified_Name (Related_Id), "_DISCR", Discr_Number); end if; Temp_Id := Make_Defining_Identifier (Loc, Temp_Nam); + if Should_Set_Related_Expression then + Set_Related_Expression (Temp_Id, Related_Nod); + end if; + -- Otherwise generate an internal temporary else @@ -13111,11 +13142,11 @@ package body Exp_Util is (Component_Type (Ityp)))); end if; - if Ialign /= No_Uint and then Ialign > Maximum_Alignment then + if Present (Ialign) and then Ialign > Maximum_Alignment then return True; - elsif Ialign /= No_Uint - and then Oalign /= No_Uint + elsif Present (Ialign) + and then Present (Oalign) and then Ialign <= Oalign then return True; diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads index 5c931c9..56ff61f 100644 --- a/gcc/ada/exp_util.ads +++ b/gcc/ada/exp_util.ads @@ -668,6 +668,7 @@ package Exp_Util is Related_Id : Entity_Id := Empty; Is_Low_Bound : Boolean := False; Is_High_Bound : Boolean := False; + Discr_Number : Int := 0; Mode : Force_Evaluation_Mode := Relaxed); -- Force the evaluation of the expression right away. Similar behavior -- to Remove_Side_Effects when Variable_Ref is set to TRUE. That is to @@ -688,6 +689,12 @@ package Exp_Util is -- of the Is_xxx_Bound flags must be set. For use of these parameters see -- the warning in the body of Sem_Ch3.Process_Range_Expr_In_Decl. + -- Discr_Number is positive when the expression is a discriminant value + -- in an object or component declaration. In that case Discr_Number is + -- the position of the corresponding discriminant in the corresponding + -- type declaration, and the name for the evaluated expression is built + -- out of the Related_Id and the Discr_Number. + function Fully_Qualified_Name_String (E : Entity_Id; Append_NUL : Boolean := True) return String_Id; @@ -1004,6 +1011,7 @@ package Exp_Util is Related_Id : Entity_Id := Empty; Is_Low_Bound : Boolean := False; Is_High_Bound : Boolean := False; + Discr_Number : Int := 0; Check_Side_Effects : Boolean := True); -- Given the node for a subexpression, this function replaces the node if -- necessary by an equivalent subexpression that is guaranteed to be side @@ -1028,6 +1036,9 @@ package Exp_Util is -- of the Is_xxx_Bound flags must be set. For use of these parameters see -- the warning in the body of Sem_Ch3.Process_Range_Expr_In_Decl. -- + -- If Discr_Number is positive, the expression denotes a discrimant value + -- in a constraint, the suffix DISCR is used to create the external name. + -- The side effects are captured using one of the following methods: -- -- 1) a constant initialized with the value of the subexpression diff --git a/gcc/ada/fe.h b/gcc/ada/fe.h index 4517c59..488e811 100644 --- a/gcc/ada/fe.h +++ b/gcc/ada/fe.h @@ -69,6 +69,15 @@ extern Boolean Debug_Flag_NN; /* einfo: */ +/* Valid_Uint is used to preserve the old behavior of Esize and + friends, where Uint_0 was the default. All calls to this + are questionable. */ +INLINE Valid_Uint +No_Uint_To_0 (Uint X) +{ + return X == No_Uint ? Uint_0 : X; +} + #define Set_Alignment einfo__entities__set_alignment #define Set_Component_Bit_Offset einfo__entities__set_component_bit_offset #define Set_Component_Size einfo__entities__set_component_size @@ -615,30 +624,15 @@ B Known_Normalized_Position_Max (Entity_Id E); #define Known_RM_Size einfo__utils__known_rm_size B Known_RM_Size (Entity_Id E); -#define Known_Static_Component_Bit_Offset einfo__utils__known_static_component_bit_offset -B Known_Static_Component_Bit_Offset (Entity_Id E); - -#define Known_Static_Component_Size einfo__utils__known_static_component_size -B Known_Static_Component_Size (Entity_Id E); - -#define Known_Static_Esize einfo__utils__known_static_esize -B Known_Static_Esize (Entity_Id E); - -#define Known_Static_Normalized_First_Bit einfo__utils__known_static_normalized_first_bit -B Known_Static_Normalized_First_Bit (Entity_Id E); - -#define Known_Static_Normalized_Position einfo__utils__known_static_normalized_position -B Known_Static_Normalized_Position (Entity_Id E); - -#define Known_Static_Normalized_Position_Max einfo__utils__known_static_normalized_position_max -B Known_Static_Normalized_Position_Max (Entity_Id E); - -#define Known_Static_RM_Size einfo__utils__known_static_rm_size -B Known_Static_RM_Size (Entity_Id E); - #define Copy_Alignment einfo__utils__copy_alignment B Copy_Alignment(Entity_Id To, Entity_Id From); +#define Copy_Esize einfo__utils__copy_esize +B Copy_Esize(Entity_Id To, Entity_Id From); + +#define Copy_RM_Size einfo__utils__copy_rm_size +B Copy_RM_Size(Entity_Id To, Entity_Id From); + #define Is_Discrete_Or_Fixed_Point_Type einfo__utils__is_discrete_or_fixed_point_type B Is_Discrete_Or_Fixed_Point_Type (E Id); diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb index 84502d8..15ce832 100644 --- a/gcc/ada/freeze.adb +++ b/gcc/ada/freeze.adb @@ -1268,9 +1268,13 @@ package body Freeze is if Present (Component_Clause (Comp)) then Comp_Byte_Aligned := - (Normalized_First_Bit (Comp) mod System_Storage_Unit = 0) + Known_Normalized_First_Bit (Comp) and then - (Esize (Comp) mod System_Storage_Unit = 0); + Known_Esize (Comp) + and then + Normalized_First_Bit (Comp) mod System_Storage_Unit = 0 + and then + Esize (Comp) mod System_Storage_Unit = 0; else Comp_Byte_Aligned := not Is_Packed (Encl_Type); end if; @@ -3640,8 +3644,8 @@ package body Freeze is (No (Ancestor_Subtype (Arr)) or else not Has_Size_Clause (Ancestor_Subtype (Arr))) then - Set_Esize (Arr, Esize (Packed_Array_Impl_Type (Arr))); - Set_RM_Size (Arr, RM_Size (Packed_Array_Impl_Type (Arr))); + Copy_Esize (To => Arr, From => Packed_Array_Impl_Type (Arr)); + Copy_RM_Size (To => Arr, From => Packed_Array_Impl_Type (Arr)); end if; if not Has_Alignment_Clause (Arr) then @@ -4173,6 +4177,7 @@ package body Freeze is -- active. if Is_Access_Type (F_Type) + and then Known_Esize (F_Type) and then Esize (F_Type) > Ttypes.System_Address_Size and then (not Unnest_Subprogram_Mode or else not Is_Access_Subprogram_Type (F_Type)) @@ -4313,6 +4318,7 @@ package body Freeze is -- Check suspicious return of fat C pointer if Is_Access_Type (R_Type) + and then Known_Esize (R_Type) and then Esize (R_Type) > Ttypes.System_Address_Size and then not Has_Warnings_Off (E) and then not Has_Warnings_Off (R_Type) @@ -6249,7 +6255,8 @@ package body Freeze is if Is_Array_Type (E) then declare Ctyp : constant Entity_Id := Component_Type (E); - Rsiz : constant Uint := RM_Size (Ctyp); + Rsiz : constant Uint := + (if Known_RM_Size (Ctyp) then RM_Size (Ctyp) else Uint_0); SZ : constant Node_Id := Size_Clause (E); Btyp : constant Entity_Id := Base_Type (E); @@ -6695,7 +6702,7 @@ package body Freeze is if Is_Type (Full_View (E)) then Set_Size_Info (E, Full_View (E)); - Set_RM_Size (E, RM_Size (Full_View (E))); + Copy_RM_Size (To => E, From => Full_View (E)); end if; goto Leave; @@ -7467,7 +7474,7 @@ package body Freeze is and then not Target_Short_Enums then - Init_Esize (Typ, Standard_Integer_Size); + Set_Esize (Typ, UI_From_Int (Standard_Integer_Size)); Set_Alignment (Typ, Alignment (Standard_Integer)); -- Normal Ada case or size clause present or not Long_C_Enums on target @@ -8579,10 +8586,10 @@ package body Freeze is Orig_Hi : Ureal; -- Save original bounds (for shaving tests) - Actual_Size : Nat; + Actual_Size : Int; -- Actual size chosen - function Fsize (Lov, Hiv : Ureal) return Nat; + function Fsize (Lov, Hiv : Ureal) return Int; -- Returns size of type with given bounds. Also leaves these -- bounds set as the current bounds of the Typ. @@ -8596,7 +8603,7 @@ package body Freeze is -- Fsize -- ----------- - function Fsize (Lov, Hiv : Ureal) return Nat is + function Fsize (Lov, Hiv : Ureal) return Int is begin Set_Realval (Lo, Lov); Set_Realval (Hi, Hiv); @@ -8642,7 +8649,7 @@ package body Freeze is if Present (Atype) then Set_Esize (Typ, Esize (Atype)); else - Set_Esize (Typ, Esize (Btyp)); + Copy_Esize (To => Typ, From => Btyp); end if; end if; @@ -8705,8 +8712,8 @@ package body Freeze is Loval_Excl_EP : Ureal; Hival_Excl_EP : Ureal; - Size_Incl_EP : Nat; - Size_Excl_EP : Nat; + Size_Incl_EP : Int; + Size_Excl_EP : Int; Model_Num : Ureal; First_Subt : Entity_Id; @@ -9076,7 +9083,7 @@ package body Freeze is Actual_Size := 128; end if; - Init_Esize (Typ, Actual_Size); + Set_Esize (Typ, UI_From_Int (Actual_Size)); Adjust_Esize_For_Alignment (Typ); end if; @@ -9132,7 +9139,7 @@ package body Freeze is -- Set Esize to calculated size if not set already if not Known_Esize (Typ) then - Init_Esize (Typ, Actual_Size); + Set_Esize (Typ, UI_From_Int (Actual_Size)); end if; -- Set RM_Size if not already set. If already set, check value @@ -9141,7 +9148,9 @@ package body Freeze is Minsiz : constant Uint := UI_From_Int (Minimum_Size (Typ)); begin - if RM_Size (Typ) /= Uint_0 then + if Known_RM_Size (Typ) + and then RM_Size (Typ) /= Uint_0 + then if RM_Size (Typ) < Minsiz then Error_Msg_Uint_1 := RM_Size (Typ); Error_Msg_Uint_2 := Minsiz; diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 765654f..c341e2d 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -298,6 +298,7 @@ GNAT_ADA_OBJS = \ ada/alloc.o \ ada/aspects.o \ ada/atree.o \ + ada/backend_utils.o \ ada/butil.o \ ada/casing.o \ ada/checks.o \ diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 0120b21..884d1d8 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -4303,7 +4303,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) gnu_size = validate_size (Esize (gnat_entity), gnu_type, gnat_entity, VAR_DECL, false, false, size_s, type_s); - else + + /* ??? The test on Has_Size_Clause must be removed when "unknown" is + no longer represented as Uint_0 (i.e. Use_New_Unknown_Rep). */ + else if (Known_RM_Size (gnat_entity) + || Has_Size_Clause (gnat_entity)) gnu_size = validate_size (RM_Size (gnat_entity), gnu_type, gnat_entity, TYPE_DECL, false, Has_Size_Clause (gnat_entity), @@ -4386,7 +4390,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) /* Now set the RM size of the type. We cannot do it before padding because we need to accept arbitrary RM sizes on integral types. */ - set_rm_size (RM_Size (gnat_entity), gnu_type, gnat_entity); + if (Known_RM_Size (gnat_entity)) + set_rm_size (RM_Size (gnat_entity), gnu_type, gnat_entity); /* Back-annotate the alignment of the type if not already set. */ if (!Known_Alignment (gnat_entity)) @@ -4417,16 +4422,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) /* Likewise for the size, if any. */ if (!Known_Esize (gnat_entity) && TYPE_SIZE (gnu_type)) { - tree gnu_size = TYPE_SIZE (gnu_type); + tree size = TYPE_SIZE (gnu_type); /* If the size is self-referential, annotate the maximum value after saturating it, if need be, to avoid a No_Uint value. */ - if (CONTAINS_PLACEHOLDER_P (gnu_size)) + if (CONTAINS_PLACEHOLDER_P (size)) { const unsigned int align = UI_To_Int (Alignment (gnat_entity)) * BITS_PER_UNIT; - gnu_size - = maybe_saturate_size (max_size (gnu_size, true), align); + size = maybe_saturate_size (max_size (size, true), align); } /* If we are just annotating types and the type is tagged, the tag @@ -4464,12 +4468,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) if (TYPE_FIELDS (gnu_type)) offset = round_up (offset, DECL_ALIGN (TYPE_FIELDS (gnu_type))); - gnu_size = size_binop (PLUS_EXPR, gnu_size, offset); + size = size_binop (PLUS_EXPR, size, offset); } - gnu_size - = maybe_saturate_size (round_up (gnu_size, align), align); - Set_Esize (gnat_entity, annotate_value (gnu_size)); + size = maybe_saturate_size (round_up (size, align), align); + Set_Esize (gnat_entity, annotate_value (size)); /* Tagged types are Strict_Alignment so RM_Size = Esize. */ if (!Known_RM_Size (gnat_entity)) @@ -4478,12 +4481,13 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) /* Otherwise no adjustment is needed. */ else - Set_Esize (gnat_entity, annotate_value (gnu_size)); + Set_Esize (gnat_entity, No_Uint_To_0 (annotate_value (size))); } /* Likewise for the RM size, if any. */ if (!Known_RM_Size (gnat_entity) && TYPE_SIZE (gnu_type)) - Set_RM_Size (gnat_entity, annotate_value (rm_size (gnu_type))); + Set_RM_Size (gnat_entity, + No_Uint_To_0 (annotate_value (rm_size (gnu_type)))); /* If we are at global level, GCC applied variable_size to the size but this has done nothing. So, if it's not constant or self-referential, @@ -4758,9 +4762,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) if (!Known_Alignment (gnat_entity)) Copy_Alignment (gnat_entity, gnat_annotate_type); if (!Known_Esize (gnat_entity)) - Set_Esize (gnat_entity, Esize (gnat_annotate_type)); + Copy_Esize (gnat_entity, gnat_annotate_type); if (!Known_RM_Size (gnat_entity)) - Set_RM_Size (gnat_entity, RM_Size (gnat_annotate_type)); + Copy_RM_Size (gnat_entity, gnat_annotate_type); } /* If we haven't already, associate the ..._DECL node that we just made with @@ -8774,7 +8778,7 @@ annotate_object (Entity_Id gnat_entity, tree gnu_type, tree size, bool by_ref) size = TYPE_SIZE (gnu_type); if (size) - Set_Esize (gnat_entity, annotate_value (size)); + Set_Esize (gnat_entity, No_Uint_To_0 (annotate_value (size))); } if (!Known_Alignment (gnat_entity)) @@ -8880,8 +8884,9 @@ annotate_rep (Entity_Id gnat_entity, tree gnu_type) (gnat_field, annotate_value (bit_from_pos (offset, bit_offset))); - Set_Esize (gnat_field, - annotate_value (DECL_SIZE (TREE_PURPOSE (t)))); + Set_Esize + (gnat_field, + No_Uint_To_0 (annotate_value (DECL_SIZE (TREE_PURPOSE (t))))); } else if (is_extension) { diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 3df56aa..d3c421d 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -9279,10 +9279,10 @@ process_freeze_entity (Node_Id gnat_node) Copy_Alignment (gnat_entity, full_view); if (!Known_Esize (gnat_entity)) - Set_Esize (gnat_entity, Esize (full_view)); + Copy_Esize (gnat_entity, full_view); if (!Known_RM_Size (gnat_entity)) - Set_RM_Size (gnat_entity, RM_Size (full_view)); + Copy_RM_Size (gnat_entity, full_view); /* The above call may have defined this entity (the simplest example of this is when we have a private enumeral type since the bounds diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads index 0a3046e..360e2e1 100644 --- a/gcc/ada/gen_il-fields.ads +++ b/gcc/ada/gen_il-fields.ads @@ -828,7 +828,6 @@ package Gen_IL.Fields is Nonzero_Is_True, Normalized_First_Bit, Normalized_Position, - Normalized_Position_Max, OK_To_Rename, Optimize_Alignment_Space, Optimize_Alignment_Time, diff --git a/gcc/ada/gen_il-gen-gen_entities.adb b/gcc/ada/gen_il-gen-gen_entities.adb index 41dd232..bca0549 100644 --- a/gcc/ada/gen_il-gen-gen_entities.adb +++ b/gcc/ada/gen_il-gen-gen_entities.adb @@ -316,7 +316,6 @@ begin -- Gen_IL.Gen.Gen_Entities Sm (Interface_Name, Node_Id), Sm (Normalized_First_Bit, Uint), Sm (Normalized_Position, Uint), - Sm (Normalized_Position_Max, Uint), Sm (Original_Record_Component, Node_Id))); Cc (E_Component, Record_Field_Kind, diff --git a/gcc/ada/gen_il-gen.adb b/gcc/ada/gen_il-gen.adb index a9c7bd7..3bb9807 100644 --- a/gcc/ada/gen_il-gen.adb +++ b/gcc/ada/gen_il-gen.adb @@ -1405,6 +1405,10 @@ package body Gen_IL.Gen is -- Print out a subtype (of type Node_Id or Entity_Id) for a given -- nonroot abstract type. + procedure Put_Opt_Subtype (T : Node_Or_Entity_Type); + -- Print out an "optional" subtype; that is, one that allows + -- Empty. Their names start with "Opt_". + procedure Put_Enum_Type is procedure Put_Enum_Lit (T : Node_Or_Entity_Type); -- Print out one enumeration literal in the declaration of @@ -1496,6 +1500,29 @@ package body Gen_IL.Gen is end if; end Put_Id_Subtype; + procedure Put_Opt_Subtype (T : Node_Or_Entity_Type) is + begin + if Type_Table (T).Parent /= No_Type then + Put (S, "subtype Opt_" & Id_Image (T) & " is" & LF); + Increase_Indent (S, 2); + Put (S, Id_Image (Root)); + + -- Assert that the Opt_XXX subtype is empty or in the XXX + -- subtype. + + if Enable_Assertions then + Put (S, " with Predicate =>" & LF); + Increase_Indent (S, 2); + Put (S, "Opt_" & Id_Image (T) & " = Empty or else" & LF); + Put (S, "Opt_" & Id_Image (T) & " in " & Id_Image (T)); + Decrease_Indent (S, 2); + end if; + + Put (S, ";" & LF); + Decrease_Indent (S, 2); + end if; + end Put_Opt_Subtype; + begin -- Put_Type_And_Subtypes Put_Enum_Type; @@ -1544,7 +1571,20 @@ package body Gen_IL.Gen is end if; end loop; - Put (S, "subtype Flag is Boolean;" & LF & LF); + Put (S, LF & "-- Optional subtypes of " & Id_Image (Root) & "." & + " These allow Empty." & LF & LF); + + Iterate_Types (Root, Pre => Put_Opt_Subtype'Access); + + Put (S, LF & "-- Optional union types:" & LF & LF); + + for T in First_Abstract (Root) .. Last_Abstract (Root) loop + if Type_Table (T) /= null and then Type_Table (T).Is_Union then + Put_Opt_Subtype (T); + end if; + end loop; + + Put (S, LF & "subtype Flag is Boolean;" & LF & LF); end Put_Type_And_Subtypes; function Low_Level_Getter_Name (T : Type_Enum) return String is diff --git a/gcc/ada/gen_il-internals.ads b/gcc/ada/gen_il-internals.ads index ae448de..53c23a2 100644 --- a/gcc/ada/gen_il-internals.ads +++ b/gcc/ada/gen_il-internals.ads @@ -190,11 +190,6 @@ package Gen_IL.Internals is (Field_Type : Type_Enum) return String is (if Field_Type = Elist_Id then "No_Elist" else "Uint_0"); - function Invalid_Val - (Field_Type : Uint_Subtype) return String is - ("No_Uint"); - -- We could generalize this to other than Uint at some point - ---------------- subtype Node_Field is diff --git a/gcc/ada/gnat1drv.adb b/gcc/ada/gnat1drv.adb index 6f65d74..95c1537 100644 --- a/gcc/ada/gnat1drv.adb +++ b/gcc/ada/gnat1drv.adb @@ -1616,7 +1616,14 @@ begin Errout.Finalize (Last_Call => True); Errout.Output_Messages; - Repinfo.List_Rep_Info (Ttypes.Bytes_Big_Endian); + + -- Back annotation of representation info is not done in CodePeer and + -- SPARK modes. + + if not (Generate_SCIL or GNATprove_Mode) then + Repinfo.List_Rep_Info (Ttypes.Bytes_Big_Endian); + end if; + Inline.List_Inlining_Info; -- Only write the library if the backend did not generate any error diff --git a/gcc/ada/gnat_cuda.adb b/gcc/ada/gnat_cuda.adb index b7ce953..6273a5d 100644 --- a/gcc/ada/gnat_cuda.adb +++ b/gcc/ada/gnat_cuda.adb @@ -66,6 +66,25 @@ package body GNAT_CUDA is -- least one procedure marked with aspect CUDA_Global. The values are -- Elists of the marked procedures. + procedure Build_And_Insert_CUDA_Initialization (N : Node_Id); + -- Builds declarations necessary for CUDA initialization and inserts them + -- in N, the package body that contains CUDA_Global nodes. These + -- declarations are: + -- + -- * A symbol to hold the pointer P to the CUDA fat binary. + -- + -- * A type definition T for a wrapper that contains the pointer to the + -- CUDA fat binary. + -- + -- * An object of the aforementioned type to hold the aforementioned + -- pointer. + -- + -- * For each CUDA_Global procedure in the package, a declaration of a C + -- string containing the function's name. + -- + -- * A procedure that takes care of calling CUDA functions that register + -- CUDA_Global procedures with the runtime. + function Get_CUDA_Kernels (Pack_Id : Entity_Id) return Elist_Id; -- Returns an Elist of all procedures marked with pragma CUDA_Global that -- are declared within package body Pack_Body. Returns No_Elist if Pack_Id @@ -94,6 +113,23 @@ package body GNAT_CUDA is Append_Elmt (Kernel, Kernels); end Add_CUDA_Kernel; + procedure Expand_CUDA_Package (N : Node_Id) is + begin + + -- If not compiling for the host, do not do anything. + + if not Debug_Flag_Underscore_C then + return; + end if; + + -- If procedures marked with CUDA_Global have been defined within N, + -- we need to register them with the CUDA runtime at program startup. + -- This requires multiple declarations and function calls which need + -- to be appended to N's declarations. + + Build_And_Insert_CUDA_Initialization (N); + end Expand_CUDA_Package; + ---------- -- Hash -- ---------- @@ -524,7 +560,7 @@ package body GNAT_CUDA is -- Start of processing for Build_And_Insert_CUDA_Initialization begin - if CUDA_Node_List = No_Elist or not Debug_Flag_Underscore_C then + if CUDA_Node_List = No_Elist then return; end if; diff --git a/gcc/ada/gnat_cuda.ads b/gcc/ada/gnat_cuda.ads index 200aeeb..d35bc8a 100644 --- a/gcc/ada/gnat_cuda.ads +++ b/gcc/ada/gnat_cuda.ads @@ -82,26 +82,8 @@ package GNAT_CUDA is -- Kernel is a procedure entity marked with CUDA_Global, Pack_Id is the -- entity of its parent package body. - procedure Build_And_Insert_CUDA_Initialization (N : Node_Id); - -- Builds declarations necessary for CUDA initialization and inserts them - -- in N, the package body that contains CUDA_Global nodes. These - -- declarations are: - -- - -- * A symbol to hold the pointer to the CUDA fat binary - -- - -- * A type definition for a wrapper that contains the pointer to the - -- CUDA fat binary - -- - -- * An object of the aforementioned type to hold the aforementioned - -- pointer. - -- - -- * For each CUDA_Global procedure in the package, a declaration of a C - -- string containing the function's name. - -- - -- * A function that takes care of calling CUDA functions that register - -- CUDA_Global procedures with the runtime. - -- - -- * A boolean that holds the result of the call to the aforementioned - -- function. + procedure Expand_CUDA_Package (N : Node_Id); + -- When compiling for the host, generate code to register kernels with the + -- CUDA runtime and post-process kernels. end GNAT_CUDA; diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index 713a662..9919cad 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -21,7 +21,7 @@ @copying @quotation -GNAT User's Guide for Native Platforms , Jun 23, 2021 +GNAT User's Guide for Native Platforms , Aug 03, 2021 AdaCore @@ -12633,8 +12633,8 @@ See @ref{e6,,Static Stack Usage Analysis} for details. This switch enables most warnings from the GCC back end. The code generator detects a number of warning situations that are missed by the GNAT front end, and this switch can be used to activate them. -The use of this switch also sets the default front end warning mode to -@code{-gnatwa}, that is, most front end warnings activated as well. +The use of this switch also sets the default front-end warning mode to +@code{-gnatwa}, that is, most front-end warnings are activated as well. @end table @geindex -w (gcc) @@ -12645,8 +12645,8 @@ The use of this switch also sets the default front end warning mode to @item @code{-w} Conversely, this switch suppresses warnings from the GCC back end. -The use of this switch also sets the default front end warning mode to -@code{-gnatws}, that is, front end warnings suppressed as well. +The use of this switch also sets the default front-end warning mode to +@code{-gnatws}, that is, front-end warnings are suppressed as well. @end table @geindex -Werror (gcc) @@ -12659,6 +12659,9 @@ The use of this switch also sets the default front end warning mode to This switch causes warnings from the GCC back end to be treated as errors. The warning string still appears, but the warning messages are counted as errors, and prevent the generation of an object file. +The use of this switch also sets the default front-end warning mode to +@code{-gnatwe}, that is, front-end warning messages and style check +messages are treated as errors as well. @end table A string of warning parameters can be used in the same parameter. For example: @@ -23100,9 +23103,9 @@ calling convention. All convention specifiers are ignored on this platform. When a subprogram @code{F} (caller) calls a subprogram @code{G} -(callee), there are several ways to push @code{G}’s parameters on the +(callee), there are several ways to push @code{G}‘s parameters on the stack and there are several possible scenarios to clean up the stack -upon @code{G}’s return. A calling convention is an agreed upon software +upon @code{G}‘s return. A calling convention is an agreed upon software protocol whereby the responsibilities between the caller (@code{F}) and the callee (@code{G}) are clearly defined. Several calling conventions are available for Windows: diff --git a/gcc/ada/init.c b/gcc/ada/init.c index c48e244..2bbb601 100644 --- a/gcc/ada/init.c +++ b/gcc/ada/init.c @@ -661,6 +661,28 @@ __gnat_install_handler (void) #include <signal.h> #include <unistd.h> +/* SA_SIGINFO is not supported by default on LynxOS, so all we have + available here is the "sig" argument. On newer LynxOS versions it's + possible to support SA_SIGINFO by setting a kernel configuration macro. + + To wit: + + #define NONPOSIX_SA_HANDLER_PROTO (0) + + This macro must be set to 1 in either sys/bsp.<bspname>/uparam.h + or in the associated uparam.h customization file sys/bsp.<bspname>/xparam.h + (uparam.h includes xparam.h for customization) + + The NONPOSIX_SA_HANDLER_PROTO macro makes it possible to provide + signal-catching function with 'info' and 'context' input parameters + even if SA_SIGINFO flag is not set or it is set for a non-realtime signal. + + It also allows signal-catching function to update thread context even + if SA_UPDATECTX flag is not set. + + This would be useful, but relying on that would transmit the requirement + to users to configure that feature as well, which is undesirable. */ + static void __gnat_error_handler (int sig) { diff --git a/gcc/ada/inline.adb b/gcc/ada/inline.adb index 6c330b2..773b376 100644 --- a/gcc/ada/inline.adb +++ b/gcc/ada/inline.adb @@ -4215,8 +4215,6 @@ package body Inline is (Subp : Entity_Id; Decls : List_Id) return Boolean is - D : Node_Id; - function Is_Unchecked_Conversion (D : Node_Id) return Boolean; -- Nested subprograms make a given body ineligible for inlining, but -- we make an exception for instantiations of unchecked conversion. @@ -4250,6 +4248,10 @@ package body Inline is and then Is_Intrinsic_Subprogram (Conv); end Is_Unchecked_Conversion; + -- Local variables + + Decl : Node_Id; + -- Start of processing for Has_Excluded_Declaration begin @@ -4259,19 +4261,19 @@ package body Inline is return False; end if; - D := First (Decls); - while Present (D) loop + Decl := First (Decls); + while Present (Decl) loop -- First declarations universally excluded - if Nkind (D) = N_Package_Declaration then + if Nkind (Decl) = N_Package_Declaration then Cannot_Inline - ("cannot inline & (nested package declaration)?", D, Subp); + ("cannot inline & (nested package declaration)?", Decl, Subp); return True; - elsif Nkind (D) = N_Package_Instantiation then + elsif Nkind (Decl) = N_Package_Instantiation then Cannot_Inline - ("cannot inline & (nested package instantiation)?", D, Subp); + ("cannot inline & (nested package instantiation)?", Decl, Subp); return True; end if; @@ -4280,51 +4282,50 @@ package body Inline is if Back_End_Inlining then null; - elsif Nkind (D) = N_Task_Type_Declaration - or else Nkind (D) = N_Single_Task_Declaration + elsif Nkind (Decl) = N_Task_Type_Declaration + or else Nkind (Decl) = N_Single_Task_Declaration then Cannot_Inline - ("cannot inline & (nested task type declaration)?", D, Subp); + ("cannot inline & (nested task type declaration)?", Decl, Subp); return True; - elsif Nkind (D) = N_Protected_Type_Declaration - or else Nkind (D) = N_Single_Protected_Declaration + elsif Nkind (Decl) in N_Protected_Type_Declaration + | N_Single_Protected_Declaration then Cannot_Inline ("cannot inline & (nested protected type declaration)?", - D, Subp); + Decl, Subp); return True; - elsif Nkind (D) = N_Subprogram_Body then + elsif Nkind (Decl) = N_Subprogram_Body then Cannot_Inline - ("cannot inline & (nested subprogram)?", D, Subp); + ("cannot inline & (nested subprogram)?", Decl, Subp); return True; - elsif Nkind (D) = N_Function_Instantiation - and then not Is_Unchecked_Conversion (D) + elsif Nkind (Decl) = N_Function_Instantiation + and then not Is_Unchecked_Conversion (Decl) then Cannot_Inline - ("cannot inline & (nested function instantiation)?", D, Subp); + ("cannot inline & (nested function instantiation)?", Decl, Subp); return True; - elsif Nkind (D) = N_Procedure_Instantiation then + elsif Nkind (Decl) = N_Procedure_Instantiation then Cannot_Inline - ("cannot inline & (nested procedure instantiation)?", D, Subp); + ("cannot inline & (nested procedure instantiation)?", + Decl, Subp); return True; -- Subtype declarations with predicates will generate predicate -- functions, i.e. nested subprogram bodies, so inlining is not -- possible. - elsif Nkind (D) = N_Subtype_Declaration - and then Present (Aspect_Specifications (D)) - then + elsif Nkind (Decl) = N_Subtype_Declaration then declare A : Node_Id; A_Id : Aspect_Id; begin - A := First (Aspect_Specifications (D)); + A := First (Aspect_Specifications (Decl)); while Present (A) loop A_Id := Get_Aspect_Id (Chars (Identifier (A))); @@ -4334,7 +4335,7 @@ package body Inline is then Cannot_Inline ("cannot inline & (subtype declaration with " - & "predicate)?", D, Subp); + & "predicate)?", Decl, Subp); return True; end if; @@ -4343,7 +4344,7 @@ package body Inline is end; end if; - Next (D); + Next (Decl); end loop; return False; diff --git a/gcc/ada/itypes.adb b/gcc/ada/itypes.adb index f51b44a..ffaa4fe 100644 --- a/gcc/ada/itypes.adb +++ b/gcc/ada/itypes.adb @@ -29,7 +29,6 @@ with Sinfo; use Sinfo; with Sinfo.Nodes; use Sinfo.Nodes; with Stand; use Stand; with Targparm; use Targparm; -with Uintp; use Uintp; package body Itypes is @@ -62,9 +61,9 @@ package body Itypes is end if; -- Make sure Esize (Typ) was properly initialized, it should be since - -- New_Internal_Entity/New_External_Entity call Init_Size_Align. + -- New_Internal_Entity/New_External_Entity call Reinit_Size_Align. - pragma Assert (Esize (Typ) = Uint_0); + pragma Assert (not Known_Esize (Typ)); Set_Etype (Typ, Any_Type); Set_Is_Itype (Typ); diff --git a/gcc/ada/layout.adb b/gcc/ada/layout.adb index e69386c..092f2f5 100644 --- a/gcc/ada/layout.adb +++ b/gcc/ada/layout.adb @@ -155,7 +155,7 @@ package body Layout is exit when Esize (E) mod Abits = 0; end loop; - Init_Alignment (E, Abits / SSU); + Set_Alignment (E, UI_From_Int (Abits / SSU)); return; end if; @@ -243,8 +243,8 @@ package body Layout is -- like or need the size to be set. if Ekind (E) = E_String_Literal_Subtype then - Set_Esize (E, Uint_0); - Set_RM_Size (E, Uint_0); + Reinit_Esize (E); + Reinit_RM_Size (E); return; end if; @@ -287,7 +287,7 @@ package body Layout is elsif Ekind (E) = E_Access_Subtype then Set_Size_Info (E, Base_Type (E)); - Set_RM_Size (E, RM_Size (Base_Type (E))); + Copy_RM_Size (To => E, From => Base_Type (E)); -- For other access types, we use either address size, or, if a fat -- pointer is used (pointer-to-unconstrained array case), twice the @@ -379,7 +379,7 @@ package body Layout is -- If size is big enough, set it and exit if S >= RM_Size (E) then - Init_Esize (E, S); + Set_Esize (E, UI_From_Int (S)); exit; -- If the RM_Size is greater than System_Max_Integer_Size @@ -426,15 +426,15 @@ package body Layout is begin if not Known_Esize (E) then - Set_Esize (E, Esize (PAT)); + Copy_Esize (To => E, From => PAT); end if; if not Known_RM_Size (E) then - Set_RM_Size (E, RM_Size (PAT)); + Copy_RM_Size (To => E, From => PAT); end if; - if not Known_Alignment (E) and then Known_Alignment (PAT) then - Set_Alignment (E, Alignment (PAT)); + if not Known_Alignment (E) then + Copy_Alignment (To => E, From => PAT); end if; end; end if; @@ -624,13 +624,13 @@ package body Layout is if Is_Scalar_Type (E) then if Size <= SSU then - Init_Esize (E, SSU); + Set_Esize (E, UI_From_Int (SSU)); elsif Size <= 16 then - Init_Esize (E, 16); + Set_Esize (E, Uint_16); elsif Size <= 32 then - Init_Esize (E, 32); + Set_Esize (E, Uint_32); else - Set_Esize (E, (Size + 63) / 64 * 64); + Set_Esize (E, (Size + 63) / 64 * 64); end if; -- Finally, make sure that alignment is consistent with @@ -899,7 +899,7 @@ package body Layout is -- nothing to do with code. if Is_Generic_Type (Root_Type (FST)) then - Set_RM_Size (Def_Id, Uint_0); + Reinit_RM_Size (Def_Id); -- If the subtype statically matches the first subtype, then it is -- required to have exactly the same layout. This is required by @@ -1021,7 +1021,7 @@ package body Layout is -- this new calculated value. if not Known_Alignment (E) then - Init_Alignment (E, A); + Set_Alignment (E, UI_From_Int (A)); -- Cases where we have inherited an alignment @@ -1030,7 +1030,7 @@ package body Layout is -- sure that no constructed types have weird alignments. elsif not Comes_From_Source (E) then - Init_Alignment (E, A); + Set_Alignment (E, UI_From_Int (A)); -- If this inherited alignment is the same as the one we computed, -- then obviously everything is fine, and we do not need to reset it. @@ -1136,7 +1136,7 @@ package body Layout is -- ACATS problem which seems to have disappeared anyway, and -- in any case, this peculiarity was never documented. - Init_Alignment (E, A); + Set_Alignment (E, UI_From_Int (A)); -- If no Size (or Object_Size) was specified, then we have -- inherited the object size, so we should also inherit the diff --git a/gcc/ada/libgnarl/s-vxwext__noints.adb b/gcc/ada/libgnarl/s-vxwext__noints.adb deleted file mode 100644 index 421781f..0000000 --- a/gcc/ada/libgnarl/s-vxwext__noints.adb +++ /dev/null @@ -1,126 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- --- -- --- S Y S T E M . V X W O R K S . E X T -- --- -- --- B o d y -- --- -- --- Copyright (C) 2008-2021, Free Software Foundation, Inc. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- ------------------------------------------------------------------------------- - --- This package provides vxworks specific support functions needed --- by System.OS_Interface. - --- This is a version for VxWorks 5 based systems with no interrupts: --- HI-Ravenscar for VxWorks 5, VxWorks 653 vThreads (not ravenscar-cert) - -package body System.VxWorks.Ext is - - ERROR : constant := -1; - - -------------- - -- Int_Lock -- - -------------- - - function Int_Lock return int is - begin - return ERROR; - end Int_Lock; - - ---------------- - -- Int_Unlock -- - ---------------- - - function Int_Unlock (Old : int) return int is - pragma Unreferenced (Old); - begin - return ERROR; - end Int_Unlock; - - ----------------------- - -- Interrupt_Connect -- - ----------------------- - - function Interrupt_Connect - (Vector : Interrupt_Vector; - Handler : Interrupt_Handler; - Parameter : System.Address := System.Null_Address) return int - is - pragma Unreferenced (Vector, Handler, Parameter); - begin - return ERROR; - end Interrupt_Connect; - - ----------------------- - -- Interrupt_Context -- - ----------------------- - - function Interrupt_Context return int is - begin - -- For VxWorks 653 vThreads, never in an interrupt context - - return 0; - end Interrupt_Context; - - -------------------------------- - -- Interrupt_Number_To_Vector -- - -------------------------------- - - function Interrupt_Number_To_Vector - (intNum : int) return Interrupt_Vector - is - pragma Unreferenced (intNum); - begin - return 0; - end Interrupt_Number_To_Vector; - - --------------- - -- semDelete -- - --------------- - - function semDelete (Sem : SEM_ID) return int is - function Os_Sem_Delete (Sem : SEM_ID) return int; - pragma Import (C, Os_Sem_Delete, "semDelete"); - begin - return Os_Sem_Delete (Sem); - end semDelete; - - ------------------------ - -- taskCpuAffinitySet -- - ------------------------ - - function taskCpuAffinitySet (tid : t_id; CPU : int) return int is - pragma Unreferenced (tid, CPU); - begin - return ERROR; - end taskCpuAffinitySet; - - ------------------------- - -- taskMaskAffinitySet -- - ------------------------- - - function taskMaskAffinitySet (tid : t_id; CPU_Set : unsigned) return int is - pragma Unreferenced (tid, CPU_Set); - begin - return ERROR; - end taskMaskAffinitySet; - -end System.VxWorks.Ext; diff --git a/gcc/ada/libgnarl/s-vxwext__vthreads.ads b/gcc/ada/libgnarl/s-vxwext__vthreads.ads deleted file mode 100644 index e97561e..0000000 --- a/gcc/ada/libgnarl/s-vxwext__vthreads.ads +++ /dev/null @@ -1,109 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- --- -- --- S Y S T E M . V X W O R K S . E X T -- --- -- --- S p e c -- --- -- --- Copyright (C) 2008-2021, Free Software Foundation, Inc. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- ------------------------------------------------------------------------------- - --- This package provides VxWorks specific support functions needed --- by System.OS_Interface. - --- This is the VxWorks 653 vThreads version of this package - -with Interfaces.C; - -package System.VxWorks.Ext is - pragma Preelaborate; - - subtype SEM_ID is Long_Integer; - -- typedef struct semaphore *SEM_ID; - - type sigset_t is mod 2 ** Interfaces.C.long'Size; - - type t_id is new Long_Integer; - subtype int is Interfaces.C.int; - subtype unsigned is Interfaces.C.unsigned; - - type Interrupt_Handler is access procedure (parameter : System.Address); - pragma Convention (C, Interrupt_Handler); - - type Interrupt_Vector is new System.Address; - function Int_Lock return int; - pragma Inline (Int_Lock); - - function Int_Unlock (Old : int) return int; - pragma Inline (Int_Unlock); - - function Interrupt_Connect - (Vector : Interrupt_Vector; - Handler : Interrupt_Handler; - Parameter : System.Address := System.Null_Address) return int; - pragma Convention (C, Interrupt_Connect); - - function Interrupt_Context return int; - pragma Convention (C, Interrupt_Context); - - function Interrupt_Number_To_Vector - (intNum : int) return Interrupt_Vector; - pragma Convention (C, Interrupt_Number_To_Vector); - - function semDelete (Sem : SEM_ID) return int; - pragma Convention (C, semDelete); - - function Task_Cont (tid : t_id) return int; - pragma Import (C, Task_Cont, "taskResume"); - - function Task_Stop (tid : t_id) return int; - pragma Import (C, Task_Stop, "taskSuspend"); - - function kill (pid : t_id; sig : int) return int; - pragma Import (C, kill, "kill"); - - function getpid return t_id; - pragma Import (C, getpid, "taskIdSelf"); - - function Set_Time_Slice (ticks : int) return int; - pragma Import (C, Set_Time_Slice, "kernelTimeSlice"); - - type UINT64 is mod 2 ** Long_Long_Integer'Size; - - function tickGet return UINT64; - -- "tickGet" not available for cert vThreads: - pragma Import (C, tickGet, "tick64Get"); - - -------------------------------- - -- Processor Affinity for SMP -- - -------------------------------- - - function taskCpuAffinitySet (tid : t_id; CPU : int) return int; - pragma Convention (C, taskCpuAffinitySet); - -- For SMP run-times set the CPU affinity. - -- For uniprocessor systems return ERROR status. - - function taskMaskAffinitySet (tid : t_id; CPU_Set : unsigned) return int; - pragma Convention (C, taskMaskAffinitySet); - -- For SMP run-times set the CPU mask affinity. - -- For uniprocessor systems return ERROR status. - -end System.VxWorks.Ext; diff --git a/gcc/ada/libgnat/a-calend.adb b/gcc/ada/libgnat/a-calend.adb index 8295a7c..5dedfc5 100644 --- a/gcc/ada/libgnat/a-calend.adb +++ b/gcc/ada/libgnat/a-calend.adb @@ -35,6 +35,8 @@ with Interfaces.C; with System.OS_Primitives; +with System.OS_Lib; + package body Ada.Calendar with SPARK_Mode => Off is @@ -685,13 +687,10 @@ is type int_Pointer is access all Interfaces.C.int; type long_Pointer is access all Interfaces.C.long; - type time_t is - range -(2 ** (Standard'Address_Size - Integer'(1))) .. - +(2 ** (Standard'Address_Size - Integer'(1)) - 1); - type time_t_Pointer is access all time_t; + type OS_Time_Pointer is access all System.OS_Lib.OS_Time; procedure localtime_tzoff - (timer : time_t_Pointer; + (timer : OS_Time_Pointer; is_historic : int_Pointer; off : long_Pointer); pragma Import (C, localtime_tzoff, "__gnat_localtime_tzoff"); @@ -708,7 +707,7 @@ is Date_N : Time_Rep; Flag : aliased Interfaces.C.int; Offset : aliased Interfaces.C.long; - Secs_T : aliased time_t; + Secs_T : aliased System.OS_Lib.OS_Time; -- Start of processing for UTC_Time_Offset @@ -745,7 +744,7 @@ is -- Convert the date into seconds - Secs_T := time_t (Date_N / Nano); + Secs_T := System.OS_Lib.To_Ada (Long_Long_Integer (Date_N / Nano)); -- Determine whether to treat the input date as historical or not. A -- value of "0" signifies that the date is NOT historic. diff --git a/gcc/ada/libgnat/a-cbdlli.adb b/gcc/ada/libgnat/a-cbdlli.adb index 143805e..3752ca9 100644 --- a/gcc/ada/libgnat/a-cbdlli.adb +++ b/gcc/ada/libgnat/a-cbdlli.adb @@ -27,6 +27,8 @@ -- This unit was originally developed by Matthew J Heaney. -- ------------------------------------------------------------------------------ +with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting; + with System; use type System.Address; with System.Put_Images; @@ -858,74 +860,6 @@ is procedure Sort (Container : in out List) is N : Node_Array renames Container.Nodes; - - procedure Partition (Pivot, Back : Count_Type); - -- What does this do ??? - - procedure Sort (Front, Back : Count_Type); - -- Internal procedure, what does it do??? rename it??? - - --------------- - -- Partition -- - --------------- - - procedure Partition (Pivot, Back : Count_Type) is - Node : Count_Type; - - begin - Node := N (Pivot).Next; - while Node /= Back loop - if N (Node).Element < N (Pivot).Element then - declare - Prev : constant Count_Type := N (Node).Prev; - Next : constant Count_Type := N (Node).Next; - - begin - N (Prev).Next := Next; - - if Next = 0 then - Container.Last := Prev; - else - N (Next).Prev := Prev; - end if; - - N (Node).Next := Pivot; - N (Node).Prev := N (Pivot).Prev; - - N (Pivot).Prev := Node; - - if N (Node).Prev = 0 then - Container.First := Node; - else - N (N (Node).Prev).Next := Node; - end if; - - Node := Next; - end; - - else - Node := N (Node).Next; - end if; - end loop; - end Partition; - - ---------- - -- Sort -- - ---------- - - procedure Sort (Front, Back : Count_Type) is - Pivot : constant Count_Type := - (if Front = 0 then Container.First else N (Front).Next); - begin - if Pivot /= Back then - Partition (Pivot, Back); - Sort (Front, Pivot); - Sort (Pivot, Back); - end if; - end Sort; - - -- Start of processing for Sort - begin if Container.Length <= 1 then return; @@ -941,8 +875,43 @@ is declare Lock : With_Lock (Container.TC'Unchecked_Access); + + package Descriptors is new List_Descriptors + (Node_Ref => Count_Type, Nil => 0); + use Descriptors; + + function Next (Idx : Count_Type) return Count_Type is + (N (Idx).Next); + procedure Set_Next (Idx : Count_Type; Next : Count_Type) + with Inline; + procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) + with Inline; + function "<" (L, R : Count_Type) return Boolean is + (N (L).Element < N (R).Element); + procedure Update_Container (List : List_Descriptor) with Inline; + + procedure Set_Next (Idx : Count_Type; Next : Count_Type) is + begin + N (Idx).Next := Next; + end Set_Next; + + procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) is + begin + N (Idx).Prev := Prev; + end Set_Prev; + + procedure Update_Container (List : List_Descriptor) is + begin + Container.First := List.First; + Container.Last := List.Last; + Container.Length := List.Length; + end Update_Container; + + procedure Sort_List is new Doubly_Linked_List_Sort; begin - Sort (Front => 0, Back => 0); + Sort_List (List_Descriptor'(First => Container.First, + Last => Container.Last, + Length => Container.Length)); end; pragma Assert (N (Container.First).Prev = 0); diff --git a/gcc/ada/libgnat/a-cdlili.adb b/gcc/ada/libgnat/a-cdlili.adb index d989751..1d48ed9 100644 --- a/gcc/ada/libgnat/a-cdlili.adb +++ b/gcc/ada/libgnat/a-cdlili.adb @@ -29,6 +29,8 @@ with Ada.Unchecked_Deallocation; +with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting; + with System; use type System.Address; with System.Put_Images; @@ -674,156 +676,6 @@ is ---------- procedure Sort (Container : in out List) is - - type List_Descriptor is - record - First, Last : Node_Access; - Length : Count_Type; - end record; - - function Merge_Sort (Arg : List_Descriptor) return List_Descriptor; - -- Sort list of given length using MergeSort; length must be >= 2. - -- As required by RM, the sort is stable. - - ---------------- - -- Merge_Sort -- - ---------------- - - function Merge_Sort (Arg : List_Descriptor) return List_Descriptor - is - procedure Split_List - (Unsplit : List_Descriptor; Part1, Part2 : out List_Descriptor); - -- Split list into two parts for divide-and-conquer. - -- Unsplit.Length must be >= 2. - - function Merge_Parts - (Part1, Part2 : List_Descriptor) return List_Descriptor; - -- Merge two sorted lists, preserving sorted property. - - ---------------- - -- Split_List -- - ---------------- - - procedure Split_List - (Unsplit : List_Descriptor; Part1, Part2 : out List_Descriptor) - is - Rover : Node_Access := Unsplit.First; - Bump_Count : constant Count_Type := (Unsplit.Length - 1) / 2; - begin - for Iter in 1 .. Bump_Count loop - Rover := Rover.Next; - end loop; - - Part1 := (First => Unsplit.First, - Last => Rover, - Length => Bump_Count + 1); - - Part2 := (First => Rover.Next, - Last => Unsplit.Last, - Length => Unsplit.Length - Part1.Length); - - -- Detach - Part1.Last.Next := null; - Part2.First.Prev := null; - end Split_List; - - ----------------- - -- Merge_Parts -- - ----------------- - - function Merge_Parts - (Part1, Part2 : List_Descriptor) return List_Descriptor - is - Empty : constant List_Descriptor := (null, null, 0); - - procedure Detach_First (Source : in out List_Descriptor; - Detached : out Node_Access); - -- Detach the first element from a non-empty list and - -- return the detached node via the Detached parameter. - - ------------------ - -- Detach_First -- - ------------------ - - procedure Detach_First (Source : in out List_Descriptor; - Detached : out Node_Access) is - begin - Detached := Source.First; - - if Source.Length = 1 then - Source := Empty; - else - Source := (Source.First.Next, - Source.Last, - Source.Length - 1); - - Detached.Next.Prev := null; - Detached.Next := null; - end if; - end Detach_First; - - P1 : List_Descriptor := Part1; - P2 : List_Descriptor := Part2; - Merged : List_Descriptor := Empty; - - Take_From_P2 : Boolean; - Detached : Node_Access; - - -- Start of processing for Merge_Parts - - begin - while (P1.Length /= 0) or (P2.Length /= 0) loop - if P1.Length = 0 then - Take_From_P2 := True; - elsif P2.Length = 0 then - Take_From_P2 := False; - else - -- If the compared elements are equal then Take_From_P2 - -- must be False in order to ensure stability. - - Take_From_P2 := P2.First.Element < P1.First.Element; - end if; - - if Take_From_P2 then - Detach_First (P2, Detached); - else - Detach_First (P1, Detached); - end if; - - if Merged.Length = 0 then - Merged := (First | Last => Detached, Length => 1); - else - Detached.Prev := Merged.Last; - Merged.Last.Next := Detached; - Merged.Last := Detached; - Merged.Length := Merged.Length + 1; - end if; - end loop; - return Merged; - end Merge_Parts; - - -- Start of processing for Merge_Sort - - begin - if Arg.Length < 2 then - -- already sorted - return Arg; - end if; - - declare - Part1, Part2 : List_Descriptor; - begin - Split_List (Unsplit => Arg, Part1 => Part1, Part2 => Part2); - - Part1 := Merge_Sort (Part1); - Part2 := Merge_Sort (Part2); - - return Merge_Parts (Part1, Part2); - end; - end Merge_Sort; - - -- Start of processing for Sort - begin if Container.Length <= 1 then return; @@ -838,28 +690,43 @@ is -- element tampering by a generic actual subprogram. declare - Lock : With_Lock (Container.TC'Unchecked_Access); + Lock : With_Lock (Container.TC'Unchecked_Access); + + package Descriptors is new List_Descriptors + (Node_Ref => Node_Access, Nil => null); + use Descriptors; + + function Next (N : Node_Access) return Node_Access is (N.Next); + procedure Set_Next (N : Node_Access; Next : Node_Access) + with Inline; + procedure Set_Prev (N : Node_Access; Prev : Node_Access) + with Inline; + function "<" (L, R : Node_Access) return Boolean is + (L.Element < R.Element); + procedure Update_Container (List : List_Descriptor) with Inline; + + procedure Set_Next (N : Node_Access; Next : Node_Access) is + begin + N.Next := Next; + end Set_Next; - Unsorted : constant List_Descriptor := - (First => Container.First, - Last => Container.Last, - Length => Container.Length); + procedure Set_Prev (N : Node_Access; Prev : Node_Access) is + begin + N.Prev := Prev; + end Set_Prev; + + procedure Update_Container (List : List_Descriptor) is + begin + Container.First := List.First; + Container.Last := List.Last; + Container.Length := List.Length; + end Update_Container; - Sorted : List_Descriptor; + procedure Sort_List is new Doubly_Linked_List_Sort; begin - -- If a call to the formal < operator references the container - -- during sorting, seeing an empty container seems preferable - -- to seeing an internally inconsistent container. - -- - Container.First := null; - Container.Last := null; - Container.Length := 0; - - Sorted := Merge_Sort (Unsorted); - - Container.First := Sorted.First; - Container.Last := Sorted.Last; - Container.Length := Sorted.Length; + Sort_List (List_Descriptor'(First => Container.First, + Last => Container.Last, + Length => Container.Length)); end; pragma Assert (Container.First.Prev = null); diff --git a/gcc/ada/libgnat/a-cfdlli.adb b/gcc/ada/libgnat/a-cfdlli.adb index b289def..c9897c7 100644 --- a/gcc/ada/libgnat/a-cfdlli.adb +++ b/gcc/ada/libgnat/a-cfdlli.adb @@ -25,6 +25,8 @@ -- <http://www.gnu.org/licenses/>. -- ------------------------------------------------------------------------------ +with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting; + with System; use type System.Address; package body Ada.Containers.Formal_Doubly_Linked_Lists with @@ -976,77 +978,6 @@ is procedure Sort (Container : in out List) is N : Node_Array renames Container.Nodes; - - procedure Partition (Pivot : Count_Type; Back : Count_Type); - procedure Sort (Front : Count_Type; Back : Count_Type); - - --------------- - -- Partition -- - --------------- - - procedure Partition (Pivot : Count_Type; Back : Count_Type) is - Node : Count_Type; - - begin - Node := N (Pivot).Next; - while Node /= Back loop - if N (Node).Element < N (Pivot).Element then - declare - Prev : constant Count_Type := N (Node).Prev; - Next : constant Count_Type := N (Node).Next; - - begin - N (Prev).Next := Next; - - if Next = 0 then - Container.Last := Prev; - else - N (Next).Prev := Prev; - end if; - - N (Node).Next := Pivot; - N (Node).Prev := N (Pivot).Prev; - - N (Pivot).Prev := Node; - - if N (Node).Prev = 0 then - Container.First := Node; - else - N (N (Node).Prev).Next := Node; - end if; - - Node := Next; - end; - - else - Node := N (Node).Next; - end if; - end loop; - end Partition; - - ---------- - -- Sort -- - ---------- - - procedure Sort (Front : Count_Type; Back : Count_Type) is - Pivot : Count_Type; - - begin - if Front = 0 then - Pivot := Container.First; - else - Pivot := N (Front).Next; - end if; - - if Pivot /= Back then - Partition (Pivot, Back); - Sort (Front, Pivot); - Sort (Pivot, Back); - end if; - end Sort; - - -- Start of processing for Sort - begin if Container.Length <= 1 then return; @@ -1055,7 +986,44 @@ is pragma Assert (N (Container.First).Prev = 0); pragma Assert (N (Container.Last).Next = 0); - Sort (Front => 0, Back => 0); + declare + package Descriptors is new List_Descriptors + (Node_Ref => Count_Type, Nil => 0); + use Descriptors; + + function Next (Idx : Count_Type) return Count_Type is + (N (Idx).Next); + procedure Set_Next (Idx : Count_Type; Next : Count_Type) + with Inline; + procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) + with Inline; + function "<" (L, R : Count_Type) return Boolean is + (N (L).Element < N (R).Element); + procedure Update_Container (List : List_Descriptor) with Inline; + + procedure Set_Next (Idx : Count_Type; Next : Count_Type) is + begin + N (Idx).Next := Next; + end Set_Next; + + procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) is + begin + N (Idx).Prev := Prev; + end Set_Prev; + + procedure Update_Container (List : List_Descriptor) is + begin + Container.First := List.First; + Container.Last := List.Last; + Container.Length := List.Length; + end Update_Container; + + procedure Sort_List is new Doubly_Linked_List_Sort; + begin + Sort_List (List_Descriptor'(First => Container.First, + Last => Container.Last, + Length => Container.Length)); + end; pragma Assert (N (Container.First).Prev = 0); pragma Assert (N (Container.Last).Next = 0); diff --git a/gcc/ada/libgnat/a-cfdlli.ads b/gcc/ada/libgnat/a-cfdlli.ads index 8713d33..590643e 100644 --- a/gcc/ada/libgnat/a-cfdlli.ads +++ b/gcc/ada/libgnat/a-cfdlli.ads @@ -1596,8 +1596,7 @@ is M_Elements_Sorted'Result = (for all I in 1 .. M.Length (Container) => (for all J in I .. M.Length (Container) => - Element (Container, I) = Element (Container, J) - or Element (Container, I) < Element (Container, J))); + not (Element (Container, J) < Element (Container, I)))); pragma Annotate (GNATprove, Inline_For_Proof, M_Elements_Sorted); end Formal_Model; diff --git a/gcc/ada/libgnat/a-cidlli.adb b/gcc/ada/libgnat/a-cidlli.adb index 3fc57da..1cf9401 100644 --- a/gcc/ada/libgnat/a-cidlli.adb +++ b/gcc/ada/libgnat/a-cidlli.adb @@ -29,6 +29,8 @@ with Ada.Unchecked_Deallocation; +with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting; + with System; use type System.Address; with System.Put_Images; @@ -731,73 +733,6 @@ is ---------- procedure Sort (Container : in out List) is - procedure Partition (Pivot : Node_Access; Back : Node_Access); - -- Comment ??? - - procedure Sort (Front, Back : Node_Access); - -- Comment??? Confusing name??? change name??? - - --------------- - -- Partition -- - --------------- - - procedure Partition (Pivot : Node_Access; Back : Node_Access) is - Node : Node_Access; - - begin - Node := Pivot.Next; - while Node /= Back loop - if Node.Element.all < Pivot.Element.all then - declare - Prev : constant Node_Access := Node.Prev; - Next : constant Node_Access := Node.Next; - - begin - Prev.Next := Next; - - if Next = null then - Container.Last := Prev; - else - Next.Prev := Prev; - end if; - - Node.Next := Pivot; - Node.Prev := Pivot.Prev; - - Pivot.Prev := Node; - - if Node.Prev = null then - Container.First := Node; - else - Node.Prev.Next := Node; - end if; - - Node := Next; - end; - - else - Node := Node.Next; - end if; - end loop; - end Partition; - - ---------- - -- Sort -- - ---------- - - procedure Sort (Front, Back : Node_Access) is - Pivot : constant Node_Access := - (if Front = null then Container.First else Front.Next); - begin - if Pivot /= Back then - Partition (Pivot, Back); - Sort (Front, Pivot); - Sort (Pivot, Back); - end if; - end Sort; - - -- Start of processing for Sort - begin if Container.Length <= 1 then return; @@ -813,8 +748,42 @@ is declare Lock : With_Lock (Container.TC'Unchecked_Access); + + package Descriptors is new List_Descriptors + (Node_Ref => Node_Access, Nil => null); + use Descriptors; + + function Next (N : Node_Access) return Node_Access is (N.Next); + procedure Set_Next (N : Node_Access; Next : Node_Access) + with Inline; + procedure Set_Prev (N : Node_Access; Prev : Node_Access) + with Inline; + function "<" (L, R : Node_Access) return Boolean is + (L.Element.all < R.Element.all); + procedure Update_Container (List : List_Descriptor) with Inline; + + procedure Set_Next (N : Node_Access; Next : Node_Access) is + begin + N.Next := Next; + end Set_Next; + + procedure Set_Prev (N : Node_Access; Prev : Node_Access) is + begin + N.Prev := Prev; + end Set_Prev; + + procedure Update_Container (List : List_Descriptor) is + begin + Container.First := List.First; + Container.Last := List.Last; + Container.Length := List.Length; + end Update_Container; + + procedure Sort_List is new Doubly_Linked_List_Sort; begin - Sort (Front => null, Back => null); + Sort_List (List_Descriptor'(First => Container.First, + Last => Container.Last, + Length => Container.Length)); end; pragma Assert (Container.First.Prev = null); diff --git a/gcc/ada/libgnat/a-costso.adb b/gcc/ada/libgnat/a-costso.adb new file mode 100644 index 0000000..e14ecbb --- /dev/null +++ b/gcc/ada/libgnat/a-costso.adb @@ -0,0 +1,191 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT LIBRARY COMPONENTS -- +-- -- +-- A D A . C O N T A I N E R S . S T A B L E _ S O R T I N G -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 1995-2021, AdaCore -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +package body Ada.Containers.Stable_Sorting is + package body List_Descriptors is + procedure Doubly_Linked_List_Sort (List : List_Descriptor) is + + Empty : constant List_Descriptor := (Nil, Nil, 0); + + function Merge_Sort (Arg : List_Descriptor) return List_Descriptor; + -- Sort list of given length using MergeSort; length must be >= 2. + -- As required by RM, the sort is stable. + + ---------------- + -- Merge_Sort -- + ---------------- + + function Merge_Sort (Arg : List_Descriptor) return List_Descriptor + is + procedure Split_List + (Unsplit : List_Descriptor; Part1, Part2 : out List_Descriptor); + -- Split list into two parts for divide-and-conquer. + -- Unsplit.Length must be >= 2. + + function Merge_Parts + (Part1, Part2 : List_Descriptor) return List_Descriptor; + -- Merge two sorted lists, preserving sorted property. + + ---------------- + -- Split_List -- + ---------------- + + procedure Split_List + (Unsplit : List_Descriptor; Part1, Part2 : out List_Descriptor) + is + Rover : Node_Ref := Unsplit.First; + Bump_Count : constant Count_Type := (Unsplit.Length - 1) / 2; + begin + for Iter in 1 .. Bump_Count loop + Rover := Next (Rover); + end loop; + + Part1 := (First => Unsplit.First, + Last => Rover, + Length => Bump_Count + 1); + + Part2 := (First => Next (Rover), + Last => Unsplit.Last, + Length => Unsplit.Length - Part1.Length); + + -- Detach + Set_Next (Part1.Last, Nil); + Set_Prev (Part2.First, Nil); + end Split_List; + + ----------------- + -- Merge_Parts -- + ----------------- + + function Merge_Parts + (Part1, Part2 : List_Descriptor) return List_Descriptor + is + procedure Detach_First (Source : in out List_Descriptor; + Detached : out Node_Ref); + -- Detach the first element from a non-empty list and + -- return the detached node via the Detached parameter. + + ------------------ + -- Detach_First -- + ------------------ + + procedure Detach_First (Source : in out List_Descriptor; + Detached : out Node_Ref) is + begin + Detached := Source.First; + + if Source.Length = 1 then + Source := Empty; + else + Source := (Next (Source.First), + Source.Last, + Source.Length - 1); + + Set_Prev (Next (Detached), Nil); + Set_Next (Detached, Nil); + end if; + end Detach_First; + + P1 : List_Descriptor := Part1; + P2 : List_Descriptor := Part2; + Merged : List_Descriptor := Empty; + + Take_From_P2 : Boolean; + Detached : Node_Ref; + + -- Start of processing for Merge_Parts + + begin + while (P1.Length /= 0) or (P2.Length /= 0) loop + if P1.Length = 0 then + Take_From_P2 := True; + elsif P2.Length = 0 then + Take_From_P2 := False; + else + -- If the compared elements are equal then Take_From_P2 + -- must be False in order to ensure stability. + + Take_From_P2 := P2.First < P1.First; + end if; + + if Take_From_P2 then + Detach_First (P2, Detached); + else + Detach_First (P1, Detached); + end if; + + if Merged.Length = 0 then + Merged := (First | Last => Detached, Length => 1); + else + Set_Prev (Detached, Merged.Last); + Set_Next (Merged.Last, Detached); + Merged.Last := Detached; + Merged.Length := Merged.Length + 1; + end if; + end loop; + return Merged; + end Merge_Parts; + + -- Start of processing for Merge_Sort + + begin + if Positive (Arg.Length) < 2 then + -- already sorted + return Arg; + end if; + + declare + Part1, Part2 : List_Descriptor; + begin + Split_List (Unsplit => Arg, Part1 => Part1, Part2 => Part2); + + Part1 := Merge_Sort (Part1); + Part2 := Merge_Sort (Part2); + + return Merge_Parts (Part1, Part2); + end; + end Merge_Sort; + + -- Start of processing for Sort + + begin + if List.Length > 1 then + -- If a call to the formal "<" op references the container + -- during sorting, seeing an empty container seems preferable + -- to seeing an internally inconsistent container. + -- + Update_Container (Empty); + + Update_Container (Merge_Sort (List)); + end if; + end Doubly_Linked_List_Sort; + end List_Descriptors; +end Ada.Containers.Stable_Sorting; diff --git a/gcc/ada/libgnat/a-costso.ads b/gcc/ada/libgnat/a-costso.ads new file mode 100644 index 0000000..db0be24 --- /dev/null +++ b/gcc/ada/libgnat/a-costso.ads @@ -0,0 +1,71 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT LIBRARY COMPONENTS -- +-- -- +-- A D A . C O N T A I N E R S . S T A B L E _ S O R T I N G -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 1995-2021, AdaCore -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- Stable_Sorting package + +-- This package provides a generic stable sorting procedure that is +-- intended for use by the various doubly linked list container generics. +-- If a stable array sorting algorithm with better-than-quadratic worst +-- case execution time is ever needed, then it could also reside here. + +private package Ada.Containers.Stable_Sorting is + pragma Annotate (CodePeer, Skip_Analysis); + pragma Pure; + pragma Remote_Types; + + -- Stable sorting algorithms with N-log-N worst case execution time. + + generic + type Node_Ref is private; -- access value or array index + Nil : Node_Ref; + package List_Descriptors is + + type List_Descriptor is + record + First, Last : Node_Ref := Nil; + Length : Count_Type := 0; + end record; + + -- We use a nested generic here so that the inner generic can + -- refer to the List_Descriptor type. + + generic + with function Next (N : Node_Ref) return Node_Ref is <>; + with procedure Set_Next (N : Node_Ref; Next : Node_Ref) is <>; + with procedure Set_Prev (N : Node_Ref; Prev : Node_Ref) is <>; + with function "<" (L, R : Node_Ref) return Boolean is <>; + + with procedure Update_Container (List : List_Descriptor) is <>; + procedure Doubly_Linked_List_Sort (List : List_Descriptor); + + end List_Descriptors; + +end Ada.Containers.Stable_Sorting; diff --git a/gcc/ada/libgnat/a-crdlli.adb b/gcc/ada/libgnat/a-crdlli.adb index 6538b26..48cdb0c 100644 --- a/gcc/ada/libgnat/a-crdlli.adb +++ b/gcc/ada/libgnat/a-crdlli.adb @@ -27,6 +27,8 @@ -- This unit was originally developed by Matthew J Heaney. -- ------------------------------------------------------------------------------ +with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting; + with System; use type System.Address; package body Ada.Containers.Restricted_Doubly_Linked_Lists is @@ -509,83 +511,53 @@ package body Ada.Containers.Restricted_Doubly_Linked_Lists is procedure Sort (Container : in out List) is N : Node_Array renames Container.Nodes; - - procedure Partition (Pivot, Back : Count_Type); - procedure Sort (Front, Back : Count_Type); - - --------------- - -- Partition -- - --------------- - - procedure Partition (Pivot, Back : Count_Type) is - Node : Count_Type := N (Pivot).Next; - - begin - while Node /= Back loop - if N (Node).Element < N (Pivot).Element then - declare - Prev : constant Count_Type := N (Node).Prev; - Next : constant Count_Type := N (Node).Next; - - begin - N (Prev).Next := Next; - - if Next = 0 then - Container.Last := Prev; - else - N (Next).Prev := Prev; - end if; - - N (Node).Next := Pivot; - N (Node).Prev := N (Pivot).Prev; - - N (Pivot).Prev := Node; - - if N (Node).Prev = 0 then - Container.First := Node; - else - N (N (Node).Prev).Next := Node; - end if; - - Node := Next; - end; - - else - Node := N (Node).Next; - end if; - end loop; - end Partition; - - ---------- - -- Sort -- - ---------- - - procedure Sort (Front, Back : Count_Type) is - Pivot : constant Count_Type := - (if Front = 0 then Container.First else N (Front).Next); - begin - if Pivot /= Back then - Partition (Pivot, Back); - Sort (Front, Pivot); - Sort (Pivot, Back); - end if; - end Sort; - - -- Start of processing for Sort - begin if Container.Length <= 1 then return; end if; - pragma Assert (N (Container.First).Prev = 0); - pragma Assert (N (Container.Last).Next = 0); - -- if Container.Busy > 0 then -- raise Program_Error; -- end if; - Sort (Front => 0, Back => 0); + declare + package Descriptors is new List_Descriptors + (Node_Ref => Count_Type, Nil => 0); + use Descriptors; + + function Next (Idx : Count_Type) return Count_Type is + (N (Idx).Next); + procedure Set_Next (Idx : Count_Type; Next : Count_Type) + with Inline; + procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) + with Inline; + function "<" (L, R : Count_Type) return Boolean is + (N (L).Element < N (R).Element); + procedure Update_Container (List : List_Descriptor) with Inline; + + procedure Set_Next (Idx : Count_Type; Next : Count_Type) is + begin + N (Idx).Next := Next; + end Set_Next; + + procedure Set_Prev (Idx : Count_Type; Prev : Count_Type) is + begin + N (Idx).Prev := Prev; + end Set_Prev; + + procedure Update_Container (List : List_Descriptor) is + begin + Container.First := List.First; + Container.Last := List.Last; + Container.Length := List.Length; + end Update_Container; + + procedure Sort_List is new Doubly_Linked_List_Sort; + begin + Sort_List (List_Descriptor'(First => Container.First, + Last => Container.Last, + Length => Container.Length)); + end; pragma Assert (N (Container.First).Prev = 0); pragma Assert (N (Container.Last).Next = 0); diff --git a/gcc/ada/libgnat/a-elchha__vxworks-ppc-full.adb b/gcc/ada/libgnat/a-elchha__vxworks-ppc-full.adb deleted file mode 100644 index 69f5cc2..0000000 --- a/gcc/ada/libgnat/a-elchha__vxworks-ppc-full.adb +++ /dev/null @@ -1,150 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME COMPONENTS -- --- -- --- A D A . E X C E P T I O N S . L A S T _ C H A N C E _ H A N D L E R -- --- -- --- B o d y -- --- -- --- Copyright (C) 2003-2021, Free Software Foundation, Inc. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - -pragma Warnings (Off); -with System.Standard_Library; -pragma Warnings (On); - -with GNAT.Debug_Utilities; use GNAT.Debug_Utilities; -with GNAT.IO; use GNAT.IO; - --- Default last chance handler for use with the full VxWorks 653 partition OS --- Ada run-time library. - --- Logs error with health monitor, and dumps exception identity and argument --- string for vxaddr2line for generation of a symbolic stack backtrace. - -procedure Ada.Exceptions.Last_Chance_Handler (Except : Exception_Occurrence) is - - ---------------------- - -- APEX definitions -- - ---------------------- - - pragma Warnings (Off); - type Error_Code_Type is ( - Deadline_Missed, - Application_Error, - Numeric_Error, - Illegal_Request, - Stack_Overflow, - Memory_Violation, - Hardware_Fault, - Power_Fail); - pragma Warnings (On); - pragma Convention (C, Error_Code_Type); - -- APEX Health Management error codes - - type Message_Addr_Type is new System.Address; - - type Apex_Integer is range -(2 ** 31) .. (2 ** 31) - 1; - pragma Convention (C, Apex_Integer); - - Max_Error_Message_Size : constant := 64; - - type Error_Message_Size_Type is new Apex_Integer range - 1 .. Max_Error_Message_Size; - - pragma Warnings (Off); - type Return_Code_Type is ( - No_Error, -- request valid and operation performed - No_Action, -- status of system unaffected by request - Not_Available, -- resource required by request unavailable - Invalid_Param, -- invalid parameter specified in request - Invalid_Config, -- parameter incompatible with configuration - Invalid_Mode, -- request incompatible with current mode - Timed_Out); -- time-out tied up with request has expired - pragma Warnings (On); - pragma Convention (C, Return_Code_Type); - -- APEX return codes - - procedure Raise_Application_Error - (Error_Code : Error_Code_Type; - Message_Addr : Message_Addr_Type; - Length : Error_Message_Size_Type; - Return_Code : out Return_Code_Type); - pragma Import (C, Raise_Application_Error, "RAISE_APPLICATION_ERROR"); - - procedure Unhandled_Terminate; - pragma No_Return (Unhandled_Terminate); - pragma Import (C, Unhandled_Terminate, "__gnat_unhandled_terminate"); - -- Perform system dependent shutdown code - - procedure Adainit; - pragma Import (Ada, Adainit, "adainit"); - - Adainit_Addr : constant System.Address := Adainit'Code_Address; - -- Part of arguments to vxaddr2line - - Result : Return_Code_Type; - - Message : String := - Exception_Name (Except) & ": " & ASCII.LF & - Exception_Message (Except) & ASCII.NUL; - - Message_Length : Error_Message_Size_Type; - -begin - New_Line; - Put_Line ("In last chance handler"); - Put_Line (Message (1 .. Message'Length - 1)); - New_Line; - - Put_Line ("adainit and traceback addresses for vxaddr2line:"); - - Put (Image_C (Adainit_Addr)); Put (" "); - - for J in 1 .. Except.Num_Tracebacks loop - Put (Image_C (Except.Tracebacks (J))); - Put (" "); - end loop; - - New_Line; - - if Message'Length > Error_Message_Size_Type'Last then - Message_Length := Error_Message_Size_Type'Last; - else - Message_Length := Message'Length; - end if; - - Raise_Application_Error - (Error_Code => Application_Error, - Message_Addr => Message_Addr_Type (Message (1)'Address), - Length => Message_Length, - Return_Code => Result); - - -- Shutdown the run-time library now. The rest of the procedure needs to be - -- careful not to use anything that would require runtime support. In - -- particular, functions returning strings are banned since the sec stack - -- is no longer functional. - - System.Standard_Library.Adafinal; - Unhandled_Terminate; -end Ada.Exceptions.Last_Chance_Handler; diff --git a/gcc/ada/libgnat/a-stbufi.adb b/gcc/ada/libgnat/a-stbufi.adb index 0a8feab..656e7bd 100644 --- a/gcc/ada/libgnat/a-stbufi.adb +++ b/gcc/ada/libgnat/a-stbufi.adb @@ -45,7 +45,7 @@ package body Ada.Strings.Text_Buffers.Files is end Put_UTF_8_Implementation; function Create_From_FD - (FD : GNAT.OS_Lib.File_Descriptor; + (FD : System.OS_Lib.File_Descriptor; Close_Upon_Finalization : Boolean := True) return File_Buffer is use OS; diff --git a/gcc/ada/libgnat/a-stbufi.ads b/gcc/ada/libgnat/a-stbufi.ads index 2a2db90..b9444ab 100644 --- a/gcc/ada/libgnat/a-stbufi.ads +++ b/gcc/ada/libgnat/a-stbufi.ads @@ -30,7 +30,7 @@ ------------------------------------------------------------------------------ with Ada.Finalization; -with GNAT.OS_Lib; +with System.OS_Lib; package Ada.Strings.Text_Buffers.Files is @@ -38,7 +38,7 @@ package Ada.Strings.Text_Buffers.Files is -- Output written to a File_Buffer is written to the associated file. function Create_From_FD - (FD : GNAT.OS_Lib.File_Descriptor; + (FD : System.OS_Lib.File_Descriptor; Close_Upon_Finalization : Boolean := True) return File_Buffer; -- file closed upon finalization if specified @@ -47,9 +47,11 @@ package Ada.Strings.Text_Buffers.Files is -- file closed upon finalization function Create_Standard_Output_Buffer return File_Buffer is - (Create_From_FD (GNAT.OS_Lib.Standout, Close_Upon_Finalization => False)); + (Create_From_FD (System.OS_Lib.Standout, + Close_Upon_Finalization => False)); function Create_Standard_Error_Buffer return File_Buffer is - (Create_From_FD (GNAT.OS_Lib.Standerr, Close_Upon_Finalization => False)); + (Create_From_FD (System.OS_Lib.Standerr, + Close_Upon_Finalization => False)); private @@ -60,7 +62,7 @@ private package Mapping is new Output_Mapping (Put_UTF_8_Implementation); - package OS renames GNAT.OS_Lib; + package OS renames System.OS_Lib; type Self_Ref (Self : not null access File_Buffer) is new Finalization.Limited_Controlled with null record; diff --git a/gcc/ada/libgnat/a-strfix.adb b/gcc/ada/libgnat/a-strfix.adb index ee72b6b..00967c4 100644 --- a/gcc/ada/libgnat/a-strfix.adb +++ b/gcc/ada/libgnat/a-strfix.adb @@ -38,10 +38,17 @@ -- bounds of function return results were also fixed, and use of & removed for -- efficiency reasons. +-- Ghost code, loop invariants and assertions in this unit are meant for +-- analysis only, not for run-time checking, as it would be too costly +-- otherwise. This is enforced by setting the assertion policy to Ignore. + +pragma Assertion_Policy (Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); + with Ada.Strings.Maps; use Ada.Strings.Maps; -with Ada.Strings.Search; -package body Ada.Strings.Fixed is +package body Ada.Strings.Fixed with SPARK_Mode is ------------------------ -- Search Subprograms -- @@ -146,9 +153,12 @@ package body Ada.Strings.Fixed is Right : Character) return String is begin - return Result : String (1 .. Left) do + return Result : String (1 .. Left) with Relaxed_Initialization do for J in Result'Range loop Result (J) := Right; + pragma Loop_Invariant + (for all K in 1 .. J => + Result (K)'Initialized and then Result (K) = Right); end loop; end return; end "*"; @@ -157,12 +167,82 @@ package body Ada.Strings.Fixed is (Left : Natural; Right : String) return String is - Ptr : Integer := 1; + Ptr : Integer := 0; + + -- Parts of the proof involving manipulations with the modulo operator + -- are complicated for the prover and can't be done automatically in + -- the global subprogram. That's why we isolate them in these two ghost + -- lemmas. + + procedure Lemma_Mod (K : Integer) with + Ghost, + Pre => + Right'Length /= 0 + and then Ptr mod Right'Length = 0 + and then Ptr in 0 .. Natural'Last - Right'Length + and then K in Ptr .. Ptr + Right'Length - 1, + Post => K mod Right'Length = K - Ptr; + -- Lemma_Mod is applied to an index considered in Lemma_Split to prove + -- that it has the right value modulo Right'Length. + + procedure Lemma_Split (Result : String) with + Ghost, + Relaxed_Initialization => Result, + Pre => + Right'Length /= 0 + and then Result'First = 1 + and then Result'Last >= 0 + and then Ptr mod Right'Length = 0 + and then Ptr in 0 .. Result'Last - Right'Length + and then Result (Result'First .. Ptr + Right'Length)'Initialized + and then Result (Ptr + 1 .. Ptr + Right'Length) = Right, + Post => + (for all K in Ptr + 1 .. Ptr + Right'Length => + Result (K) = Right (Right'First + (K - 1) mod Right'Length)); + -- Lemma_Split is used after Result (Ptr + 1 .. Ptr + Right'Length) is + -- updated to Right and concludes that the characters match for each + -- index when taken modulo Right'Length, as the considered slice starts + -- at index 1 modulo Right'Length. + + --------------- + -- Lemma_Mod -- + --------------- + + procedure Lemma_Mod (K : Integer) is null; + + ----------------- + -- Lemma_Split -- + ----------------- + + procedure Lemma_Split (Result : String) is + begin + for K in Ptr + 1 .. Ptr + Right'Length loop + Lemma_Mod (K - 1); + pragma Loop_Invariant + (for all J in Ptr + 1 .. K => + Result (J) = Right (Right'First + (J - 1) mod Right'Length)); + end loop; + end Lemma_Split; + + -- Start of processing for "*" + begin - return Result : String (1 .. Left * Right'Length) do + if Right'Length = 0 then + return ""; + end if; + + return Result : String (1 .. Left * Right'Length) + with Relaxed_Initialization + do for J in 1 .. Left loop - Result (Ptr .. Ptr + Right'Length - 1) := Right; + Result (Ptr + 1 .. Ptr + Right'Length) := Right; + Lemma_Split (Result); Ptr := Ptr + Right'Length; + pragma Loop_Invariant (Ptr = J * Right'Length); + pragma Loop_Invariant (Result (1 .. Ptr)'Initialized); + pragma Loop_Invariant + (for all K in 1 .. Ptr => + Result (K) = Right (Right'First + (K - 1) mod Right'Length)); end loop; end return; end "*"; @@ -176,7 +256,6 @@ package body Ada.Strings.Fixed is From : Positive; Through : Natural) return String is - Front : Integer; begin if From > Through then declare @@ -204,13 +283,22 @@ package body Ada.Strings.Fixed is end if; else - Front := From - Source'First; - return Result : String (1 .. Source'Length - (Through - From + 1)) do - Result (1 .. Front) := - Source (Source'First .. From - 1); - Result (Front + 1 .. Result'Last) := - Source (Through + 1 .. Source'Last); - end return; + declare + Front : constant Integer := From - Source'First; + + begin + return Result : String (1 .. Source'Length - (Through - From + 1)) + with Relaxed_Initialization + do + Result (1 .. Front) := + Source (Source'First .. From - 1); + + if Through < Source'Last then + Result (Front + 1 .. Result'Last) := + Source (Through + 1 .. Source'Last); + end if; + end return; + end; end if; end Delete; @@ -219,8 +307,7 @@ package body Ada.Strings.Fixed is From : Positive; Through : Natural; Justify : Alignment := Left; - Pad : Character := Space) - is + Pad : Character := Space) with SPARK_Mode => Off is begin Move (Source => Delete (Source, From, Through), Target => Source, @@ -240,16 +327,19 @@ package body Ada.Strings.Fixed is subtype Result_Type is String (1 .. Count); begin - if Count < Source'Length then + if Count <= Source'Length then return - Result_Type (Source (Source'First .. Source'First + Count - 1)); + Result_Type (Source (Source'First .. Source'First + (Count - 1))); else - return Result : Result_Type do + return Result : Result_Type with Relaxed_Initialization do Result (1 .. Source'Length) := Source; for J in Source'Length + 1 .. Count loop Result (J) := Pad; + pragma Loop_Invariant + (for all K in Source'Length + 1 .. J => + Result (K)'Initialized and then Result (K) = Pad); end loop; end return; end if; @@ -281,17 +371,31 @@ package body Ada.Strings.Fixed is Front : constant Integer := Before - Source'First; begin - if Before not in Source'First .. Source'Last + 1 then + if Before - 1 not in Source'First - 1 .. Source'Last then raise Index_Error; end if; - return Result : String (1 .. Source'Length + New_Item'Length) do + return Result : String (1 .. Source'Length + New_Item'Length) + with Relaxed_Initialization + do Result (1 .. Front) := Source (Source'First .. Before - 1); Result (Front + 1 .. Front + New_Item'Length) := New_Item; - Result (Front + New_Item'Length + 1 .. Result'Last) := - Source (Before .. Source'Last); + pragma Assert + (Result + (Before - Source'First + 1 + .. Before - Source'First + New_Item'Length) + = New_Item); + + if Before <= Source'Last then + Result (Front + New_Item'Length + 1 .. Result'Last) := + Source (Before .. Source'Last); + end if; + + pragma Assert + (Result (1 .. Before - Source'First) + = Source (Source'First .. Before - 1)); end return; end Insert; @@ -299,8 +403,7 @@ package body Ada.Strings.Fixed is (Source : in out String; Before : Positive; New_Item : String; - Drop : Truncation := Error) - is + Drop : Truncation := Error) with SPARK_Mode => Off is begin Move (Source => Insert (Source, Before, New_Item), Target => Source, @@ -316,7 +419,7 @@ package body Ada.Strings.Fixed is Target : out String; Drop : Truncation := Error; Justify : Alignment := Left; - Pad : Character := Space) + Pad : Character := Space) with SPARK_Mode => Off is Sfirst : constant Integer := Source'First; Slast : constant Integer := Source'Last; @@ -423,7 +526,7 @@ package body Ada.Strings.Fixed is Position : Positive; New_Item : String) return String is begin - if Position not in Source'First .. Source'Last + 1 then + if Position - 1 not in Source'First - 1 .. Source'Last then raise Index_Error; end if; @@ -434,11 +537,32 @@ package body Ada.Strings.Fixed is Front : constant Integer := Position - Source'First; begin - return Result : String (1 .. Result_Length) do + return Result : String (1 .. Result_Length) + with Relaxed_Initialization + do Result (1 .. Front) := Source (Source'First .. Position - 1); + pragma Assert + (Result (1 .. Position - Source'First) + = Source (Source'First .. Position - 1)); Result (Front + 1 .. Front + New_Item'Length) := New_Item; - Result (Front + New_Item'Length + 1 .. Result'Length) := - Source (Position + New_Item'Length .. Source'Last); + pragma Assert + (Result + (Position - Source'First + 1 + .. Position - Source'First + New_Item'Length) + = New_Item); + + if Position <= Source'Last - New_Item'Length then + Result (Front + New_Item'Length + 1 .. Result'Last) := + Source (Position + New_Item'Length .. Source'Last); + end if; + + pragma Assert + (if Position <= Source'Last - New_Item'Length + then + Result + (Position - Source'First + New_Item'Length + 1 + .. Result'Last) + = Source (Position + New_Item'Length .. Source'Last)); end return; end; end Overwrite; @@ -447,8 +571,7 @@ package body Ada.Strings.Fixed is (Source : in out String; Position : Positive; New_Item : String; - Drop : Truncation := Right) - is + Drop : Truncation := Right) with SPARK_Mode => Off is begin Move (Source => Overwrite (Source, Position, New_Item), Target => Source, @@ -463,10 +586,9 @@ package body Ada.Strings.Fixed is (Source : String; Low : Positive; High : Natural; - By : String) return String - is + By : String) return String is begin - if Low > Source'Last + 1 or else High < Source'First - 1 then + if Low - 1 > Source'Last or else High < Source'First - 1 then raise Index_Error; end if; @@ -484,11 +606,34 @@ package body Ada.Strings.Fixed is -- Length of result begin - return Result : String (1 .. Result_Length) do + return Result : String (1 .. Result_Length) + with Relaxed_Initialization do Result (1 .. Front_Len) := Source (Source'First .. Low - 1); + pragma Assert + (Result (1 .. Integer'Max (0, Low - Source'First)) + = Source (Source'First .. Low - 1)); Result (Front_Len + 1 .. Front_Len + By'Length) := By; - Result (Front_Len + By'Length + 1 .. Result'Length) := - Source (High + 1 .. Source'Last); + + if High < Source'Last then + Result (Front_Len + By'Length + 1 .. Result'Last) := + Source (High + 1 .. Source'Last); + end if; + + pragma Assert + (Result (1 .. Integer'Max (0, Low - Source'First)) + = Source (Source'First .. Low - 1)); + pragma Assert + (Result + (Integer'Max (0, Low - Source'First) + 1 + .. Integer'Max (0, Low - Source'First) + By'Length) + = By); + pragma Assert + (if High < Source'Last + then + Result + (Integer'Max (0, Low - Source'First) + By'Length + 1 + .. Result'Last) + = Source (High + 1 .. Source'Last)); end return; end; else @@ -503,8 +648,7 @@ package body Ada.Strings.Fixed is By : String; Drop : Truncation := Error; Justify : Alignment := Left; - Pad : Character := Space) - is + Pad : Character := Space) with SPARK_Mode => Off is begin Move (Replace_Slice (Source, Low, High, By), Source, Drop, Justify, Pad); end Replace_Slice; @@ -521,18 +665,26 @@ package body Ada.Strings.Fixed is subtype Result_Type is String (1 .. Count); begin - if Count < Source'Length then + if Count = 0 then + return ""; + + elsif Count < Source'Length then return Result_Type (Source (Source'Last - Count + 1 .. Source'Last)); -- Pad on left else - return Result : Result_Type do + return Result : Result_Type with Relaxed_Initialization do for J in 1 .. Count - Source'Length loop Result (J) := Pad; + pragma Loop_Invariant + (for all K in 1 .. J => + Result (K)'Initialized and then Result (K) = Pad); end loop; - Result (Count - Source'Length + 1 .. Count) := Source; + if Source'Length /= 0 then + Result (Count - Source'Length + 1 .. Count) := Source; + end if; end return; end if; end Tail; @@ -560,9 +712,18 @@ package body Ada.Strings.Fixed is Mapping : Maps.Character_Mapping) return String is begin - return Result : String (1 .. Source'Length) do + return Result : String (1 .. Source'Length) + with Relaxed_Initialization + do for J in Source'Range loop Result (J - (Source'First - 1)) := Value (Mapping, Source (J)); + pragma Loop_Invariant + (for all K in Source'First .. J => + Result (K - (Source'First - 1))'Initialized); + pragma Loop_Invariant + (for all K in Source'First .. J => + Result (K - (Source'First - 1)) = + Value (Mapping, Source (K))); end loop; end return; end Translate; @@ -574,6 +735,9 @@ package body Ada.Strings.Fixed is begin for J in Source'Range loop Source (J) := Value (Mapping, Source (J)); + pragma Loop_Invariant + (for all K in Source'First .. J => + Source (K) = Value (Mapping, Source'Loop_Entry (K))); end loop; end Translate; @@ -583,9 +747,17 @@ package body Ada.Strings.Fixed is is pragma Unsuppress (Access_Check); begin - return Result : String (1 .. Source'Length) do + return Result : String (1 .. Source'Length) + with Relaxed_Initialization + do for J in Source'Range loop Result (J - (Source'First - 1)) := Mapping.all (Source (J)); + pragma Loop_Invariant + (for all K in Source'First .. J => + Result (K - (Source'First - 1))'Initialized); + pragma Loop_Invariant + (for all K in Source'First .. J => + Result (K - (Source'First - 1)) = Mapping (Source (K))); end loop; end return; end Translate; @@ -598,6 +770,9 @@ package body Ada.Strings.Fixed is begin for J in Source'Range loop Source (J) := Mapping.all (Source (J)); + pragma Loop_Invariant + (for all K in Source'First .. J => + Source (K) = Mapping (Source'Loop_Entry (K))); end loop; end Translate; @@ -609,6 +784,9 @@ package body Ada.Strings.Fixed is (Source : String; Side : Trim_End) return String is + Empty_String : constant String (1 .. 0) := ""; + -- Without declaring the empty string as a separate string starting + -- at 1, SPARK provers have trouble proving the postcondition. begin case Side is when Strings.Left => @@ -618,7 +796,7 @@ package body Ada.Strings.Fixed is -- All blanks case if Low = 0 then - return ""; + return Empty_String; end if; declare @@ -635,7 +813,7 @@ package body Ada.Strings.Fixed is -- All blanks case if High = 0 then - return ""; + return Empty_String; end if; declare @@ -652,7 +830,7 @@ package body Ada.Strings.Fixed is -- All blanks case if Low = 0 then - return ""; + return Empty_String; end if; declare @@ -695,8 +873,7 @@ package body Ada.Strings.Fixed is return ""; end if; - High := - Index (Source, Set => Right, Test => Outside, Going => Backward); + High := Index (Source, Set => Right, Test => Outside, Going => Backward); -- Case where source comprises only characters in Right @@ -705,7 +882,8 @@ package body Ada.Strings.Fixed is end if; declare - subtype Result_Type is String (1 .. High - Low + 1); + Result_Length : constant Integer := High - Low + 1; + subtype Result_Type is String (1 .. Result_Length); begin return Result_Type (Source (Low .. High)); diff --git a/gcc/ada/libgnat/a-strfix.ads b/gcc/ada/libgnat/a-strfix.ads index 4214157..1a5ee94 100644 --- a/gcc/ada/libgnat/a-strfix.ads +++ b/gcc/ada/libgnat/a-strfix.ads @@ -13,14 +13,6 @@ -- -- ------------------------------------------------------------------------------ --- Preconditions in this unit are meant for analysis only, not for run-time --- checking, so that the expected exceptions are raised. This is enforced by --- setting the corresponding assertion policy to Ignore. - -pragma Assertion_Policy (Pre => Ignore); - -with Ada.Strings.Maps; - -- The language-defined package Strings.Fixed provides string-handling -- subprograms for fixed-length strings; that is, for values of type -- Standard.String. Several of these subprograms are procedures that modify @@ -40,6 +32,20 @@ with Ada.Strings.Maps; -- these effects. Similar control is provided by the string transformation -- procedures. +-- Preconditions in this unit are meant for analysis only, not for run-time +-- checking, so that the expected exceptions are raised. This is enforced by +-- setting the corresponding assertion policy to Ignore. Postconditions and +-- contract cases should not be executed at runtime as well, in order not to +-- slow down the execution of these functions. + +pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Contract_Cases => Ignore, + Ghost => Ignore); + +with Ada.Strings.Maps; use type Ada.Strings.Maps.Character_Mapping_Function; +with Ada.Strings.Search; + package Ada.Strings.Fixed with SPARK_Mode is pragma Preelaborate; @@ -108,56 +114,60 @@ package Ada.Strings.Fixed with SPARK_Mode is Going : Direction := Forward; Mapping : Maps.Character_Mapping_Function) return Natural with - Pre => - Pattern'Length /= 0 - and then (if Source'Length /= 0 then From in Source'Range), + Pre => Pattern'Length > 0 + and then Mapping /= null + and then (if Source'Length > 0 then From in Source'Range), Post => Index'Result in 0 | Source'Range, Contract_Cases => - -- If no slice in the considered range of Source matches Pattern, - -- then 0 is returned. + -- If Source is the empty string, then 0 is returned - ((for all J in Source'Range => - (if (if Going = Forward - then J in From .. Source'Last - Pattern'Length + 1 - else J <= From - Pattern'Length + 1) - then Translate (Source (J .. J - 1 + Pattern'Length), Mapping) - /= Pattern)) + (Source'Length = 0 => Index'Result = 0, - -- Otherwise, a valid index is returned + -- If some slice of Source matches Pattern, then a valid index is + -- returned. - others + Source'Length > 0 + and then + (for some J in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) => + Ada.Strings.Search.Match (Source, Pattern, Mapping, J)) => - -- The result is in the considered range of Source - (if Going = Forward - then Index'Result in From .. Source'Last - Pattern'Length + 1 - else Index'Result in Source'First .. From - Pattern'Length + 1) + Index'Result in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) -- The slice beginning at the returned index matches Pattern and then - Translate (Source (Index'Result - .. Index'Result - 1 + Pattern'Length), - Mapping) - = Pattern + Ada.Strings.Search.Match (Source, Pattern, Mapping, Index'Result) - -- The result is the smallest or largest index which satisfies the - -- matching, respectively when Going = Forward and - -- Going = Backwards. + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backward. and then (for all J in Source'Range => (if (if Going = Forward then J in From .. Index'Result - 1 - else J - 1 in Index'Result .. From - Pattern'Length) - then Translate (Source (J .. J - 1 + Pattern'Length), - Mapping) - /= Pattern))), + else J - 1 in Index'Result + .. From - Pattern'Length) + then not (Ada.Strings.Search.Match + (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others + => + Index'Result = 0), Global => null; pragma Ada_05 (Index); @@ -168,56 +178,59 @@ package Ada.Strings.Fixed with SPARK_Mode is Going : Direction := Forward; Mapping : Maps.Character_Mapping := Maps.Identity) return Natural with - Pre => - Pattern'Length /= 0 - and then (if Source'Length /= 0 then From in Source'Range), + Pre => Pattern'Length > 0 + and then (if Source'Length > 0 then From in Source'Range), Post => Index'Result in 0 | Source'Range, Contract_Cases => - -- If no slice in the considered range of Source matches Pattern, - -- then 0 is returned. + -- If Source is the empty string, then 0 is returned - ((for all J in Source'Range => - (if (if Going = Forward - then J in From .. Source'Last - Pattern'Length + 1 - else J <= From - Pattern'Length + 1) - then Translate (Source (J .. J - 1 + Pattern'Length), Mapping) - /= Pattern)) + (Source'Length = 0 => Index'Result = 0, - -- Otherwise, a valid index is returned + -- If some slice of Source matches Pattern, then a valid index is + -- returned. - others + Source'Length > 0 + and then + (for some J in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) => + Ada.Strings.Search.Match (Source, Pattern, Mapping, J)) => - -- The result is in the considered range of Source - (if Going = Forward - then Index'Result in From .. Source'Last - Pattern'Length + 1 - else Index'Result in Source'First .. From - Pattern'Length + 1) + Index'Result in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) - -- The slice beginning at the returned index matches Pattern + -- The slice beginning at the returned index matches Pattern - and then - Translate (Source (Index'Result - .. Index'Result - 1 + Pattern'Length), - Mapping) - = Pattern + and then + Ada.Strings.Search.Match (Source, Pattern, Mapping, Index'Result) -- The result is the smallest or largest index which satisfies the -- matching, respectively when Going = Forward and - -- Going = Backwards. + -- Going = Backward. and then (for all J in Source'Range => (if (if Going = Forward then J in From .. Index'Result - 1 - else J - 1 in Index'Result .. From - Pattern'Length) - then Translate (Source (J .. J - 1 + Pattern'Length), - Mapping) - /= Pattern))), + else J - 1 in Index'Result + .. From - Pattern'Length) + then not (Ada.Strings.Search.Match + (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others + => + Index'Result = 0), Global => null; pragma Ada_05 (Index); @@ -245,37 +258,33 @@ package Ada.Strings.Fixed with SPARK_Mode is Post => Index'Result in 0 | Source'Range, Contract_Cases => - -- If Source is empty, or if no slice of Source matches Pattern, then - -- 0 is returned. + -- If Source is the empty string, then 0 is returned (Source'Length = 0 - or else - (for all J in Source'First .. Source'Last - Pattern'Length + 1 => - Translate (Source (J .. J - 1 + Pattern'Length), Mapping) - /= Pattern) => Index'Result = 0, - -- Otherwise, a valid index is returned + -- If some slice of Source matches Pattern, then a valid index is + -- returned. - others + Source'Length > 0 + and then + (for some J in + Source'First .. Source'Last - (Pattern'Length - 1) => + Ada.Strings.Search.Match (Source, Pattern, Mapping, J)) => - -- The result is in the considered range of Source - Index'Result in Source'First .. Source'Last - Pattern'Length + 1 + Index'Result in Source'First .. Source'Last - (Pattern'Length - 1) -- The slice beginning at the returned index matches Pattern and then - Translate (Source (Index'Result - .. Index'Result - 1 + Pattern'Length), - Mapping) - = Pattern + Ada.Strings.Search.Match (Source, Pattern, Mapping, Index'Result) - -- The result is the smallest or largest index which satisfies the - -- matching, respectively when Going = Forward and - -- Going = Backwards. + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backward. and then (for all J in Source'Range => @@ -283,9 +292,14 @@ package Ada.Strings.Fixed with SPARK_Mode is then J <= Index'Result - 1 else J - 1 in Index'Result .. Source'Last - Pattern'Length) - then Translate (Source (J .. J - 1 + Pattern'Length), - Mapping) - /= Pattern))), + then not (Ada.Strings.Search.Match + (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others + => + Index'Result = 0), Global => null; function Index @@ -294,42 +308,38 @@ package Ada.Strings.Fixed with SPARK_Mode is Going : Direction := Forward; Mapping : Maps.Character_Mapping_Function) return Natural with - Pre => Pattern'Length > 0, + Pre => Pattern'Length > 0 and then Mapping /= null, Post => Index'Result in 0 | Source'Range, Contract_Cases => - -- If Source is empty, or if no slice of Source matches Pattern, then - -- 0 is returned. + -- If Source is the empty string, then 0 is returned (Source'Length = 0 - or else - (for all J in Source'First .. Source'Last - Pattern'Length + 1 => - Translate (Source (J .. J - 1 + Pattern'Length), Mapping) - /= Pattern) => Index'Result = 0, - -- Otherwise, a valid index is returned + -- If some slice of Source matches Pattern, then a valid index is + -- returned. - others + Source'Length > 0 + and then + (for some J in + Source'First .. Source'Last - (Pattern'Length - 1) => + Ada.Strings.Search.Match (Source, Pattern, Mapping, J)) => - -- The result is in the considered range of Source - Index'Result in Source'First .. Source'Last - Pattern'Length + 1 + Index'Result in Source'First .. Source'Last - (Pattern'Length - 1) - -- The slice beginning at the returned index matches Pattern + -- The slice beginning at the returned index matches Pattern - and then - Translate (Source (Index'Result - .. Index'Result - 1 + Pattern'Length), - Mapping) - = Pattern + and then + Ada.Strings.Search.Match (Source, Pattern, Mapping, Index'Result) - -- The result is the smallest or largest index which satisfies the - -- matching, respectively when Going = Forward and - -- Going = Backwards. + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backward. and then (for all J in Source'Range => @@ -337,9 +347,14 @@ package Ada.Strings.Fixed with SPARK_Mode is then J <= Index'Result - 1 else J - 1 in Index'Result .. Source'Last - Pattern'Length) - then Translate (Source (J .. J - 1 + Pattern'Length), - Mapping) - /= Pattern))), + then not (Ada.Strings.Search.Match + (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others + => + Index'Result = 0), Global => null; -- If Going = Forward, returns: @@ -383,9 +398,9 @@ package Ada.Strings.Fixed with SPARK_Mode is (Test = Inside) = Ada.Strings.Maps.Is_In (Source (Index'Result), Set) - -- The result is the smallest or largest index which satisfies the - -- property, respectively when Going = Forward and - -- Going = Backwards. + -- The result is the smallest or largest index which satisfies + -- the property, respectively when Going = Forward and Going = + -- Backward. and then (for all J in Source'Range => @@ -402,22 +417,23 @@ package Ada.Strings.Fixed with SPARK_Mode is Test : Membership := Inside; Going : Direction := Forward) return Natural with - Pre => (if Source'Length /= 0 then From in Source'Range), - + Pre => (if Source'Length > 0 then From in Source'Range), Post => Index'Result in 0 | Source'Range, Contract_Cases => - -- If no character in the considered slice of Source satisfies the - -- property Test on Set, then 0 is returned. + -- If Source is the empty string, or no character of the considered + -- slice of Source satisfies the property Test on Set, then 0 is + -- returned. - ((for all I in Source'Range => - (if I = From - or else (I > From) = (Going = Forward) - then (Test = Inside) /= Ada.Strings.Maps.Is_In (Source (I), Set))) + (Source'Length = 0 + or else + (for all J in Source'Range => + (if J = From or else (J > From) = (Going = Forward) then + (Test = Inside) /= Ada.Strings.Maps.Is_In (Source (J), Set))) => Index'Result = 0, - -- Otherwise, an index in the range of Source is returned + -- Otherwise, a index in the considered range of Source is returned others => @@ -426,7 +442,8 @@ package Ada.Strings.Fixed with SPARK_Mode is Index'Result in Source'Range and then (Index'Result = From - or else (Index'Result > From) = (Going = Forward)) + or else + (Index'Result > From) = (Going = Forward)) -- The character at the returned index satisfies the property -- Test on Set. @@ -435,19 +452,18 @@ package Ada.Strings.Fixed with SPARK_Mode is (Test = Inside) = Ada.Strings.Maps.Is_In (Source (Index'Result), Set) - -- The result is the smallest or largest index which satisfies the - -- property, respectively when Going = Forward and - -- Going = Backwards. + -- The result is the smallest or largest index which satisfies + -- the property, respectively when Going = Forward and Going = + -- Backward. and then (for all J in Source'Range => (if J /= Index'Result - and then (J < Index'Result) = (Going = Forward) - and then (J = From - or else (J > From) = (Going = Forward)) - then - (Test = Inside) - /= Ada.Strings.Maps.Is_In (Source (J), Set)))), + and then (J < Index'Result) = (Going = Forward) + and then (J = From + or else (J > From) = (Going = Forward)) + then (Test = Inside) + /= Ada.Strings.Maps.Is_In (Source (J), Set)))), Global => null; pragma Ada_05 (Index); -- Index searches for the first or last occurrence of any of a set of @@ -469,12 +485,14 @@ package Ada.Strings.Fixed with SPARK_Mode is Post => Index_Non_Blank'Result in 0 | Source'Range, Contract_Cases => - -- If all characters in the considered slice of Source are Space - -- characters, then 0 is returned. + -- If Source is the empty string, or all characters in the considered + -- slice of Source are Space characters, then 0 is returned. - ((for all J in Source'Range => - (if J = From or else (J > From) = (Going = Forward) - then Source (J) = ' ')) + (Source'Length = 0 + or else + (for all J in Source'Range => + (if J = From or else (J > From) = (Going = Forward) then + Source (J) = ' ')) => Index_Non_Blank'Result = 0, @@ -496,7 +514,7 @@ package Ada.Strings.Fixed with SPARK_Mode is -- The result is the smallest or largest index which is not a -- Space character, respectively when Going = Forward and - -- Going = Backwards. + -- Going = Backward. and then (for all J in Source'Range => @@ -535,8 +553,8 @@ package Ada.Strings.Fixed with SPARK_Mode is and then Source (Index_Non_Blank'Result) /= ' ' -- The result is the smallest or largest index which is not a - -- Space character, respectively when Going = Forward and - -- Going = Backwards. + -- Space character, respectively when Going = Forward and Going + -- = Backward. and then (for all J in Source'Range => @@ -560,7 +578,7 @@ package Ada.Strings.Fixed with SPARK_Mode is Pattern : String; Mapping : Maps.Character_Mapping_Function) return Natural with - Pre => Pattern'Length /= 0, + Pre => Pattern'Length /= 0 and then Mapping /= null, Global => null; -- Returns the maximum number of nonoverlapping slices of Source that match @@ -646,6 +664,7 @@ package Ada.Strings.Fixed with SPARK_Mode is First : out Positive; Last : out Natural) with + Pre => Source'First > 0, Contract_Cases => -- If Source is the empty string, or if no character of Source @@ -701,6 +720,7 @@ package Ada.Strings.Fixed with SPARK_Mode is (Source : String; Mapping : Maps.Character_Mapping_Function) return String with + Pre => Mapping /= null, Post => -- Lower bound of the returned string is 1 @@ -751,10 +771,11 @@ package Ada.Strings.Fixed with SPARK_Mode is (Source : in out String; Mapping : Maps.Character_Mapping_Function) with + Pre => Mapping /= null, Post => - -- Each character in Source after the call is the translation of - -- the character at the same position before the call, through Mapping. + -- Each character in Source after the call is the translation of the + -- character at the same position before the call, through Mapping. (for all J in Source'Range => Source (J) = Mapping (Source'Old (J))), Global => null; @@ -765,8 +786,8 @@ package Ada.Strings.Fixed with SPARK_Mode is with Post => - -- Each character in Source after the call is the translation of - -- the character at the same position before the call, through Mapping. + -- Each character in Source after the call is the translation of the + -- character at the same position before the call, through Mapping. (for all J in Source'Range => Source (J) = Ada.Strings.Maps.Value (Mapping, Source'Old (J))), @@ -778,32 +799,6 @@ package Ada.Strings.Fixed with SPARK_Mode is -- String Transformation Subprograms -- --------------------------------------- - procedure Replace_Slice - (Source : in out String; - Low : Positive; - High : Natural; - By : String; - Drop : Truncation := Error; - Justify : Alignment := Left; - Pad : Character := Space) - with - Pre => - - -- Incomplete contract - - Low - 1 <= Source'Last - and then High >= Source'First - 1, - Global => null; - -- If Low > Source'Last+1, or High < Source'First - 1, then Index_Error is - -- propagated. Otherwise: - -- - -- * If High >= Low, then the returned string comprises - -- Source (Source'First .. Low - 1) - -- & By & Source(High + 1 .. Source'Last), but with lower bound 1. - -- - -- * If High < Low, then the returned string is - -- Insert (Source, Before => Low, New_Item => By). - function Replace_Slice (Source : String; Low : Positive; @@ -834,19 +829,19 @@ package Ada.Strings.Fixed with SPARK_Mode is -- Length of the returned string Replace_Slice'Result'Length - = Natural'Max (0, Low - Source'First) + = Integer'Max (0, Low - Source'First) + By'Length - + Natural'Max (Source'Last - High, 0) + + Integer'Max (Source'Last - High, 0) -- Elements starting at Low are replaced by elements of By and then - Replace_Slice'Result (1 .. Natural'Max (0, Low - Source'First)) + Replace_Slice'Result (1 .. Integer'Max (0, Low - Source'First)) = Source (Source'First .. Low - 1) and then Replace_Slice'Result - (Natural'Max (0, Low - Source'First) + 1 - .. Natural'Max (0, Low - Source'First) + By'Length) + (Integer'Max (0, Low - Source'First) + 1 + .. Integer'Max (0, Low - Source'First) + By'Length) = By -- When there are remaining characters after the replaced slice, @@ -856,7 +851,7 @@ package Ada.Strings.Fixed with SPARK_Mode is (if High < Source'Last then Replace_Slice'Result - (Natural'Max (0, Low - Source'First) + By'Length + 1 + (Integer'Max (0, Low - Source'First) + By'Length + 1 .. Replace_Slice'Result'Last) = Source (High + 1 .. Source'Last)), @@ -890,6 +885,30 @@ package Ada.Strings.Fixed with SPARK_Mode is .. Replace_Slice'Result'Last) = Source (Low .. Source'Last))), Global => null; + -- If Low > Source'Last + 1, or High < Source'First - 1, then Index_Error + -- is propagated. Otherwise: + -- + -- * If High >= Low, then the returned string comprises + -- Source (Source'First .. Low - 1) + -- & By & Source(High + 1 .. Source'Last), but with lower bound 1. + -- + -- * If High < Low, then the returned string is + -- Insert (Source, Before => Low, New_Item => By). + + procedure Replace_Slice + (Source : in out String; + Low : Positive; + High : Natural; + By : String; + Drop : Truncation := Error; + Justify : Alignment := Left; + Pad : Character := Space) + with + Pre => Low - 1 <= Source'Last, + + -- Incomplete contract + + Global => null; -- Equivalent to: -- -- Move (Replace_Slice (Source, Low, High, By), @@ -929,7 +948,7 @@ package Ada.Strings.Fixed with SPARK_Mode is -- are appended to the returned string. and then - (if Before - 1 < Source'Last + (if Before <= Source'Last then Insert'Result (Before - Source'First + New_Item'Length + 1 @@ -937,7 +956,7 @@ package Ada.Strings.Fixed with SPARK_Mode is = Source (Before .. Source'Last)), Global => null; -- Propagates Index_Error if Before is not in - -- Source'First .. Source'Last+1; otherwise, returns + -- Source'First .. Source'Last + 1; otherwise, returns -- Source (Source'First .. Before - 1) -- & New_Item & Source(Before..Source'Last), but with lower bound 1. @@ -1384,9 +1403,8 @@ package Ada.Strings.Fixed with SPARK_Mode is -- Content of the string is Right concatenated with itself Left times and then - (for all J in 0 .. Left - 1 => - "*"'Result (J * Right'Length + 1 .. (J + 1) * Right'Length) - = Right), + (for all K in "*"'Result'Range => + "*"'Result (K) = Right (Right'First + (K - 1) mod Right'Length)), Global => null; -- These functions replicate a character or string a specified number of diff --git a/gcc/ada/libgnat/a-strsea.adb b/gcc/ada/libgnat/a-strsea.adb index d96a4c7..243c92c 100644 --- a/gcc/ada/libgnat/a-strsea.adb +++ b/gcc/ada/libgnat/a-strsea.adb @@ -35,10 +35,18 @@ -- case of identity mappings for Count and Index, and also Index_Non_Blank -- is specialized (rather than using the general Index routine). +-- Ghost code, loop invariants and assertions in this unit are meant for +-- analysis only, not for run-time checking, as it would be too costly +-- otherwise. This is enforced by setting the assertion policy to Ignore. + +pragma Assertion_Policy (Ghost => Ignore, + Loop_Invariant => Ignore, + Assert => Ignore); + with Ada.Strings.Maps; use Ada.Strings.Maps; with System; use System; -package body Ada.Strings.Search is +package body Ada.Strings.Search with SPARK_Mode is ----------------------- -- Local Subprograms -- @@ -61,13 +69,9 @@ package body Ada.Strings.Search is Set : Maps.Character_Set; Test : Membership) return Boolean is - begin - if Test = Inside then - return Is_In (Element, Set); - else - return not Is_In (Element, Set); - end if; - end Belongs; + (if Test = Inside then + Is_In (Element, Set) + else not (Is_In (Element, Set))); ----------- -- Count -- @@ -81,47 +85,63 @@ package body Ada.Strings.Search is PL1 : constant Integer := Pattern'Length - 1; Num : Natural; Ind : Natural; - Cur : Natural; begin if Pattern = "" then raise Pattern_Error; end if; + -- Isolating the null string case to ensure Source'First, Source'Last in + -- Positive. + + if Source = "" then + return 0; + end if; + Num := 0; - Ind := Source'First; + Ind := Source'First - 1; -- Unmapped case - if Mapping'Address = Maps.Identity'Address then - while Ind <= Source'Last - PL1 loop + if Is_Identity (Mapping) then + while Ind < Source'Last - PL1 loop + Ind := Ind + 1; if Pattern = Source (Ind .. Ind + PL1) then Num := Num + 1; - Ind := Ind + Pattern'Length; - else - Ind := Ind + 1; + Ind := Ind + PL1; end if; + + pragma Loop_Invariant (Num <= Ind - (Source'First - 1)); + pragma Loop_Invariant (Ind >= Source'First); end loop; -- Mapped case else - while Ind <= Source'Last - PL1 loop - Cur := Ind; + while Ind < Source'Last - PL1 loop + Ind := Ind + 1; for K in Pattern'Range loop - if Pattern (K) /= Value (Mapping, Source (Cur)) then - Ind := Ind + 1; + if Pattern (K) /= Value (Mapping, + Source (Ind + (K - Pattern'First))) + then + pragma Assert (not (Match (Source, Pattern, Mapping, Ind))); goto Cont; - else - Cur := Cur + 1; end if; + + pragma Loop_Invariant + (for all J in Pattern'First .. K => + Pattern (J) = Value (Mapping, + Source (Ind + (J - Pattern'First)))); end loop; + pragma Assert (Match (Source, Pattern, Mapping, Ind)); Num := Num + 1; - Ind := Ind + Pattern'Length; + Ind := Ind + PL1; - <<Cont>> + <<Cont>> null; + pragma Loop_Invariant (Num <= Ind - (Source'First - 1)); + pragma Loop_Invariant (Ind >= Source'First); end loop; end if; @@ -138,13 +158,19 @@ package body Ada.Strings.Search is PL1 : constant Integer := Pattern'Length - 1; Num : Natural; Ind : Natural; - Cur : Natural; begin if Pattern = "" then raise Pattern_Error; end if; + -- Isolating the null string case to ensure Source'First, Source'Last in + -- Positive. + + if Source = "" then + return 0; + end if; + -- Check for null pointer in case checks are off if Mapping = null then @@ -152,23 +178,28 @@ package body Ada.Strings.Search is end if; Num := 0; - Ind := Source'First; - while Ind <= Source'Last - PL1 loop - Cur := Ind; + Ind := Source'First - 1; + while Ind < Source'Last - PL1 loop + Ind := Ind + 1; for K in Pattern'Range loop - if Pattern (K) /= Mapping (Source (Cur)) then - Ind := Ind + 1; + if Pattern (K) /= Mapping (Source (Ind + (K - Pattern'First))) then + pragma Assert (not (Match (Source, Pattern, Mapping, Ind))); goto Cont; - else - Cur := Cur + 1; end if; + + pragma Loop_Invariant + (for all J in Pattern'First .. K => + Pattern (J) = Mapping (Source (Ind + (J - Pattern'First)))); end loop; + pragma Assert (Match (Source, Pattern, Mapping, Ind)); Num := Num + 1; - Ind := Ind + Pattern'Length; + Ind := Ind + PL1; <<Cont>> null; + pragma Loop_Invariant (Num <= Ind - (Source'First - 1)); + pragma Loop_Invariant (Ind >= Source'First); end loop; return Num; @@ -182,6 +213,7 @@ package body Ada.Strings.Search is begin for J in Source'Range loop + pragma Loop_Invariant (N <= J - Source'First); if Is_In (Source (J), Set) then N := N + 1; end if; @@ -217,12 +249,18 @@ package body Ada.Strings.Search is if Belongs (Source (J), Set, Test) then First := J; - for K in J + 1 .. Source'Last loop - if not Belongs (Source (K), Set, Test) then - Last := K - 1; - return; - end if; - end loop; + if J < Source'Last then + for K in J + 1 .. Source'Last loop + if not Belongs (Source (K), Set, Test) then + Last := K - 1; + return; + end if; + + pragma Loop_Invariant + (for all L in J .. K => + Belongs (Source (L), Set, Test)); + end loop; + end if; -- Here if J indexes first char of token, and all chars after J -- are in the token. @@ -230,6 +268,10 @@ package body Ada.Strings.Search is Last := Source'Last; return; end if; + + pragma Loop_Invariant + (for all K in Integer'Max (From, Source'First) .. J => + not (Belongs (Source (K), Set, Test))); end loop; -- Here if no token found @@ -250,12 +292,18 @@ package body Ada.Strings.Search is if Belongs (Source (J), Set, Test) then First := J; - for K in J + 1 .. Source'Last loop - if not Belongs (Source (K), Set, Test) then - Last := K - 1; - return; - end if; - end loop; + if J < Source'Last then + for K in J + 1 .. Source'Last loop + if not Belongs (Source (K), Set, Test) then + Last := K - 1; + return; + end if; + + pragma Loop_Invariant + (for all L in J .. K => + Belongs (Source (L), Set, Test)); + end loop; + end if; -- Here if J indexes first char of token, and all chars after J -- are in the token. @@ -263,6 +311,10 @@ package body Ada.Strings.Search is Last := Source'Last; return; end if; + + pragma Loop_Invariant + (for all K in Source'First .. J => + not (Belongs (Source (K), Set, Test))); end loop; -- Here if no token found @@ -292,53 +344,61 @@ package body Ada.Strings.Search is Mapping : Maps.Character_Mapping := Maps.Identity) return Natural is PL1 : constant Integer := Pattern'Length - 1; - Cur : Natural; - - Ind : Integer; - -- Index for start of match check. This can be negative if the pattern - -- length is greater than the string length, which is why this variable - -- is Integer instead of Natural. In this case, the search loops do not - -- execute at all, so this Ind value is never used. begin if Pattern = "" then raise Pattern_Error; end if; + -- If Pattern is longer than Source, it can't be found + + if Pattern'Length > Source'Length then + return 0; + end if; + -- Forwards case if Going = Forward then - Ind := Source'First; -- Unmapped forward case - if Mapping'Address = Maps.Identity'Address then - for J in 1 .. Source'Length - PL1 loop + if Is_Identity (Mapping) then + for Ind in Source'First .. Source'Last - PL1 loop if Pattern = Source (Ind .. Ind + PL1) then + pragma Assert (Match (Source, Pattern, Mapping, Ind)); return Ind; - else - Ind := Ind + 1; end if; + + pragma Loop_Invariant + (for all J in Source'First .. Ind => + not (Match (Source, Pattern, Mapping, J))); end loop; -- Mapped forward case else - for J in 1 .. Source'Length - PL1 loop - Cur := Ind; - + for Ind in Source'First .. Source'Last - PL1 loop for K in Pattern'Range loop - if Pattern (K) /= Value (Mapping, Source (Cur)) then + if Pattern (K) /= Value (Mapping, + Source (Ind + (K - Pattern'First))) + then goto Cont1; - else - Cur := Cur + 1; end if; + + pragma Loop_Invariant + (for all J in Pattern'First .. K => + Pattern (J) = Value (Mapping, + Source (Ind + (J - Pattern'First)))); end loop; + pragma Assert (Match (Source, Pattern, Mapping, Ind)); return Ind; - <<Cont1>> - Ind := Ind + 1; + <<Cont1>> + pragma Loop_Invariant + (for all J in Source'First .. Ind => + not (Match (Source, Pattern, Mapping, J))); + null; end loop; end if; @@ -347,35 +407,43 @@ package body Ada.Strings.Search is else -- Unmapped backward case - Ind := Source'Last - PL1; - - if Mapping'Address = Maps.Identity'Address then - for J in reverse 1 .. Source'Length - PL1 loop + if Is_Identity (Mapping) then + for Ind in reverse Source'First .. Source'Last - PL1 loop if Pattern = Source (Ind .. Ind + PL1) then + pragma Assert (Match (Source, Pattern, Mapping, Ind)); return Ind; - else - Ind := Ind - 1; end if; + + pragma Loop_Invariant + (for all J in Ind .. Source'Last - PL1 => + not (Match (Source, Pattern, Mapping, J))); end loop; -- Mapped backward case else - for J in reverse 1 .. Source'Length - PL1 loop - Cur := Ind; - + for Ind in reverse Source'First .. Source'Last - PL1 loop for K in Pattern'Range loop - if Pattern (K) /= Value (Mapping, Source (Cur)) then + if Pattern (K) /= Value (Mapping, + Source (Ind + (K - Pattern'First))) + then goto Cont2; - else - Cur := Cur + 1; end if; + + pragma Loop_Invariant + (for all J in Pattern'First .. K => + Pattern (J) = Value (Mapping, + Source (Ind + (J - Pattern'First)))); end loop; + pragma Assert (Match (Source, Pattern, Mapping, Ind)); return Ind; - <<Cont2>> - Ind := Ind - 1; + <<Cont2>> + pragma Loop_Invariant + (for all J in Ind .. Source'Last - PL1 => + not (Match (Source, Pattern, Mapping, J))); + null; end loop; end if; end if; @@ -393,9 +461,6 @@ package body Ada.Strings.Search is Mapping : Maps.Character_Mapping_Function) return Natural is PL1 : constant Integer := Pattern'Length - 1; - Ind : Natural; - Cur : Natural; - begin if Pattern = "" then raise Pattern_Error; @@ -416,43 +481,52 @@ package body Ada.Strings.Search is -- Forwards case if Going = Forward then - Ind := Source'First; - for J in 1 .. Source'Length - PL1 loop - Cur := Ind; - + for Ind in Source'First .. Source'Last - PL1 loop for K in Pattern'Range loop - if Pattern (K) /= Mapping.all (Source (Cur)) then + if Pattern (K) /= Mapping.all + (Source (Ind + (K - Pattern'First))) + then goto Cont1; - else - Cur := Cur + 1; end if; + + pragma Loop_Invariant + (for all J in Pattern'First .. K => + Pattern (J) = Mapping (Source (Ind + (J - Pattern'First)))); end loop; + pragma Assert (Match (Source, Pattern, Mapping, Ind)); return Ind; - <<Cont1>> - Ind := Ind + 1; + <<Cont1>> + pragma Loop_Invariant + (for all J in Source'First .. Ind => + not (Match (Source, Pattern, Mapping, J))); + null; end loop; -- Backwards case else - Ind := Source'Last - PL1; - for J in reverse 1 .. Source'Length - PL1 loop - Cur := Ind; - + for Ind in reverse Source'First .. Source'Last - PL1 loop for K in Pattern'Range loop - if Pattern (K) /= Mapping.all (Source (Cur)) then + if Pattern (K) /= Mapping.all + (Source (Ind + (K - Pattern'First))) + then goto Cont2; - else - Cur := Cur + 1; end if; + + pragma Loop_Invariant + (for all J in Pattern'First .. K => + Pattern (J) = Mapping (Source (Ind + (J - Pattern'First)))); end loop; return Ind; - <<Cont2>> - Ind := Ind - 1; + <<Cont2>> + pragma Loop_Invariant + (for all J in Ind .. (Source'Last - PL1) => + not (Match (Source, Pattern, Mapping, J))); + null; end loop; end if; @@ -476,6 +550,10 @@ package body Ada.Strings.Search is if Belongs (Source (J), Set, Test) then return J; end if; + + pragma Loop_Invariant + (for all C of Source (Source'First .. J) => + not (Belongs (C, Set, Test))); end loop; -- Backwards case @@ -485,6 +563,10 @@ package body Ada.Strings.Search is if Belongs (Source (J), Set, Test) then return J; end if; + + pragma Loop_Invariant + (for all C of Source (J .. Source'Last) => + not (Belongs (C, Set, Test))); end loop; end if; @@ -500,6 +582,8 @@ package body Ada.Strings.Search is Going : Direction := Forward; Mapping : Maps.Character_Mapping := Maps.Identity) return Natural is + Result : Natural; + PL1 : constant Integer := Pattern'Length - 1; begin -- AI05-056: If source is empty result is always zero @@ -512,17 +596,29 @@ package body Ada.Strings.Search is raise Index_Error; end if; - return + Result := Index (Source (From .. Source'Last), Pattern, Forward, Mapping); + pragma Assert + (if (for some J in From .. Source'Last - PL1 => + Match (Source, Pattern, Mapping, J)) + then Result in From .. Source'Last - PL1 + else Result = 0); else if From > Source'Last then raise Index_Error; end if; - return + Result := Index (Source (Source'First .. From), Pattern, Backward, Mapping); + pragma Assert + (if (for some J in Source'First .. From - PL1 => + Match (Source, Pattern, Mapping, J)) + then Result in Source'First .. From - PL1 + else Result = 0); end if; + + return Result; end Index; function Index @@ -603,6 +699,9 @@ package body Ada.Strings.Search is if Source (J) /= ' ' then return J; end if; + + pragma Loop_Invariant + (for all C of Source (Source'First .. J) => C = ' '); end loop; else -- Going = Backward @@ -610,6 +709,9 @@ package body Ada.Strings.Search is if Source (J) /= ' ' then return J; end if; + + pragma Loop_Invariant + (for all C of Source (J .. Source'Last) => C = ' '); end loop; end if; @@ -624,6 +726,13 @@ package body Ada.Strings.Search is Going : Direction := Forward) return Natural is begin + + -- For equivalence with Index, if Source is empty the result is 0 + + if Source'Length = 0 then + return 0; + end if; + if Going = Forward then if From < Source'First then raise Index_Error; @@ -642,4 +751,12 @@ package body Ada.Strings.Search is end if; end Index_Non_Blank; + function Is_Identity + (Mapping : Maps.Character_Mapping) return Boolean + with SPARK_Mode => Off + is + begin + return Mapping'Address = Maps.Identity'Address; + end Is_Identity; + end Ada.Strings.Search; diff --git a/gcc/ada/libgnat/a-strsea.ads b/gcc/ada/libgnat/a-strsea.ads index 623c0f4..4396747 100644 --- a/gcc/ada/libgnat/a-strsea.ads +++ b/gcc/ada/libgnat/a-strsea.ads @@ -32,76 +32,489 @@ -- This package contains the search functions from Ada.Strings.Fixed. They -- are separated out because they are shared by Ada.Strings.Bounded and -- Ada.Strings.Unbounded, and we don't want to drag in other irrelevant stuff --- from Ada.Strings.Fixed when using the other two packages. We make this a --- private package, since user programs should access these subprograms via --- one of the standard string packages. +-- from Ada.Strings.Fixed when using the other two packages. Although user +-- programs should access these subprograms via one of the standard string +-- packages, we do not make this a private package, since ghost function +-- Match is used in the contracts of the standard string packages. -with Ada.Strings.Maps; +-- Preconditions in this unit are meant for analysis only, not for run-time +-- checking, so that the expected exceptions are raised. This is enforced +-- by setting the corresponding assertion policy to Ignore. Postconditions, +-- contract cases and ghost code should not be executed at runtime as well, +-- in order not to slow down the execution of these functions. -private package Ada.Strings.Search is +pragma Assertion_Policy (Pre => Ignore, + Post => Ignore, + Contract_Cases => Ignore, + Ghost => Ignore); + +with Ada.Strings.Maps; use type Ada.Strings.Maps.Character_Mapping_Function; + +package Ada.Strings.Search with SPARK_Mode is pragma Preelaborate; + -- The ghost function Match tells whether the slice of Source starting at + -- From and of length Pattern'Length matches with Pattern with respect to + -- Mapping. Pattern should be non-empty and the considered slice should be + -- fully included in Source'Range. + + function Match + (Source : String; + Pattern : String; + Mapping : Maps.Character_Mapping_Function; + From : Integer) return Boolean + is + (for all K in Pattern'Range => + Pattern (K) = Mapping (Source (From + (K - Pattern'First)))) + with + Ghost, + Pre => Mapping /= null + and then Pattern'Length > 0 + and then Source'Length > 0 + and then From in Source'First .. Source'Last - (Pattern'Length - 1), + Global => null; + + function Match + (Source : String; + Pattern : String; + Mapping : Maps.Character_Mapping; + From : Integer) return Boolean + is + (for all K in Pattern'Range => + Pattern (K) = + Ada.Strings.Maps.Value + (Mapping, Source (From + (K - Pattern'First)))) + with + Ghost, + Pre => Pattern'Length > 0 + and then Source'Length > 0 + and then From in Source'First .. Source'Last - (Pattern'Length - 1), + Global => null; + + function Is_Identity + (Mapping : Maps.Character_Mapping) return Boolean + with + Post => (if Is_Identity'Result then + (for all K in Character => + Ada.Strings.Maps.Value (Mapping, K) = K)), + Global => null; + function Index (Source : String; Pattern : String; Going : Direction := Forward; - Mapping : Maps.Character_Mapping := Maps.Identity) return Natural; + Mapping : Maps.Character_Mapping := Maps.Identity) return Natural + with + Pre => Pattern'Length > 0, + + Post => Index'Result in 0 | Source'Range, + Contract_Cases => + + -- If Source is the empty string, then 0 is returned + + (Source'Length = 0 => Index'Result = 0, + + -- If some slice of Source matches Pattern, then a valid index is + -- returned. + + Source'Length > 0 + and then + (for some J in + Source'First .. Source'Last - (Pattern'Length - 1) => + Match (Source, Pattern, Mapping, J)) + => + + -- The result is in the considered range of Source + + Index'Result in Source'First .. Source'Last - (Pattern'Length - 1) + + -- The slice beginning at the returned index matches Pattern + + and then Match (Source, Pattern, Mapping, Index'Result) + + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backward. + + and then + (for all J in Source'Range => + (if (if Going = Forward + then J <= Index'Result - 1 + else J - 1 in Index'Result + .. Source'Last - Pattern'Length) + then not (Match (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others => Index'Result = 0), + Global => null; function Index (Source : String; Pattern : String; Going : Direction := Forward; - Mapping : Maps.Character_Mapping_Function) return Natural; + Mapping : Maps.Character_Mapping_Function) return Natural + with + Pre => Pattern'Length > 0 and then Mapping /= null, + Post => Index'Result in 0 | Source'Range, + Contract_Cases => + + -- If Source is the null string, then 0 is returned + + (Source'Length = 0 => Index'Result = 0, + + -- If some slice of Source matches Pattern, then a valid index is + -- returned. + + Source'Length > 0 and then + (for some J in Source'First .. Source'Last - (Pattern'Length - 1) => + Match (Source, Pattern, Mapping, J)) + => + + -- The result is in the considered range of Source + + Index'Result in Source'First .. Source'Last - (Pattern'Length - 1) + + -- The slice beginning at the returned index matches Pattern + + and then Match (Source, Pattern, Mapping, Index'Result) + + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backward. + + and then + (for all J in Source'Range => + (if (if Going = Forward + then J <= Index'Result - 1 + else J - 1 in Index'Result + .. Source'Last - Pattern'Length) + then not (Match (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others => Index'Result = 0), + Global => null; function Index (Source : String; Set : Maps.Character_Set; Test : Membership := Inside; - Going : Direction := Forward) return Natural; + Going : Direction := Forward) return Natural + with + Post => Index'Result in 0 | Source'Range, + Contract_Cases => + + -- If no character of Source satisfies the property Test on Set, then + -- 0 is returned. + + ((for all C of Source => + (Test = Inside) /= Ada.Strings.Maps.Is_In (C, Set)) + => + Index'Result = 0, + + -- Otherwise, a index in the range of Source is returned + + others => + + -- The result is in the range of Source + + Index'Result in Source'Range + + -- The character at the returned index satisfies the property + -- Test on Set + + and then (Test = Inside) + = Ada.Strings.Maps.Is_In (Source (Index'Result), Set) + + -- The result is the smallest or largest index which satisfies + -- the property, respectively when Going = Forward and Going = + -- Backward. + + and then + (for all J in Source'Range => + (if J /= Index'Result + and then (J < Index'Result) = (Going = Forward) + then (Test = Inside) + /= Ada.Strings.Maps.Is_In (Source (J), Set)))), + Global => null; function Index (Source : String; Pattern : String; From : Positive; Going : Direction := Forward; - Mapping : Maps.Character_Mapping := Maps.Identity) return Natural; + Mapping : Maps.Character_Mapping := Maps.Identity) return Natural + with + Pre => Pattern'Length > 0 + and then (if Source'Length > 0 then From in Source'Range), + + Post => Index'Result in 0 | Source'Range, + Contract_Cases => + + -- If Source is the empty string, then 0 is returned + + (Source'Length = 0 => Index'Result = 0, + + -- If some slice of Source matches Pattern, then a valid index is + -- returned. + + Source'Length > 0 + and then + (for some J in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) => + Match (Source, Pattern, Mapping, J)) + => + + -- The result is in the considered range of Source + + Index'Result in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) + + -- The slice beginning at the returned index matches Pattern + + and then Match (Source, Pattern, Mapping, Index'Result) + + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backward. + + and then + (for all J in Source'Range => + (if (if Going = Forward + then J in From .. Index'Result - 1 + else J - 1 in Index'Result + .. From - Pattern'Length) + then not (Match (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others => Index'Result = 0), + Global => null; function Index (Source : String; Pattern : String; From : Positive; Going : Direction := Forward; - Mapping : Maps.Character_Mapping_Function) return Natural; + Mapping : Maps.Character_Mapping_Function) return Natural + with + Pre => Pattern'Length > 0 + and then Mapping /= null + and then (if Source'Length > 0 then From in Source'Range), + + Post => Index'Result in 0 | Source'Range, + Contract_Cases => + + -- If Source is the empty string, then 0 is returned + + (Source'Length = 0 => Index'Result = 0, + + -- If some slice of Source matches Pattern, then a valid index is + -- returned. + + Source'Length > 0 + and then + (for some J in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) => + Match (Source, Pattern, Mapping, J)) + => + + -- The result is in the considered range of Source + + Index'Result in + (if Going = Forward then From else Source'First) + .. (if Going = Forward then Source'Last else From) + - (Pattern'Length - 1) + + -- The slice beginning at the returned index matches Pattern + + and then Match (Source, Pattern, Mapping, Index'Result) + + -- The result is the smallest or largest index which satisfies + -- the matching, respectively when Going = Forward and Going = + -- Backwards. + + and then + (for all J in Source'Range => + (if (if Going = Forward + then J in From .. Index'Result - 1 + else J - 1 in Index'Result + .. From - Pattern'Length) + then not (Match (Source, Pattern, Mapping, J)))), + + -- Otherwise, 0 is returned + + others => Index'Result = 0), + Global => null; function Index (Source : String; Set : Maps.Character_Set; From : Positive; Test : Membership := Inside; - Going : Direction := Forward) return Natural; + Going : Direction := Forward) return Natural + with + Pre => (if Source'Length > 0 then From in Source'Range), + Post => Index'Result in 0 | Source'Range, + Contract_Cases => + + -- If Source is the empty string, or no character of the considered + -- slice of Source satisfies the property Test on Set, then 0 is + -- returned. + + (Source'Length = 0 + or else + (for all J in Source'Range => + (if J = From or else (J > From) = (Going = Forward) then + (Test = Inside) /= Ada.Strings.Maps.Is_In (Source (J), Set))) + => + Index'Result = 0, + + -- Otherwise, a index in the considered range of Source is returned + + others => + + -- The result is in the considered range of Source + + Index'Result in Source'Range + and then (Index'Result = From + or else + (Index'Result > From) = (Going = Forward)) + + -- The character at the returned index satisfies the property + -- Test on Set + + and then + (Test = Inside) + = Ada.Strings.Maps.Is_In (Source (Index'Result), Set) + + -- The result is the smallest or largest index which satisfies + -- the property, respectively when Going = Forward and Going = + -- Backward. + + and then + (for all J in Source'Range => + (if J /= Index'Result + and then (J < Index'Result) = (Going = Forward) + and then (J = From + or else (J > From) = (Going = Forward)) + then (Test = Inside) + /= Ada.Strings.Maps.Is_In (Source (J), Set)))), + Global => null; function Index_Non_Blank (Source : String; - Going : Direction := Forward) return Natural; + Going : Direction := Forward) return Natural + with + Post => Index_Non_Blank'Result in 0 | Source'Range, + Contract_Cases => + + -- If all characters of Source are Space characters, then 0 is + -- returned. + + ((for all C of Source => C = ' ') => Index_Non_Blank'Result = 0, + + -- Otherwise, a valid index is returned + + others => + + -- The result is in the range of Source + + Index_Non_Blank'Result in Source'Range + + -- The character at the returned index is not a Space character + + and then Source (Index_Non_Blank'Result) /= ' ' + + -- The result is the smallest or largest index which is not a + -- Space character, respectively when Going = Forward and + -- Going = Backward. + + and then + (for all J in Source'Range => + (if J /= Index_Non_Blank'Result + and then (J < Index_Non_Blank'Result) + = (Going = Forward) + then Source (J) = ' '))), + Global => null; function Index_Non_Blank (Source : String; From : Positive; - Going : Direction := Forward) return Natural; + Going : Direction := Forward) return Natural + with + Pre => (if Source'Length /= 0 then From in Source'Range), + Post => Index_Non_Blank'Result in 0 | Source'Range, + Contract_Cases => + + -- If Source is the null string, or all characters in the considered + -- slice of Source are Space characters, then 0 is returned. + + (Source'Length = 0 + or else + (for all J in Source'Range => + (if J = From or else (J > From) = (Going = Forward) then + Source (J) = ' ')) + => + Index_Non_Blank'Result = 0, + + -- Otherwise, a valid index is returned + + others => + + -- The result is in the considered range of Source + + Index_Non_Blank'Result in Source'Range + and then (Index_Non_Blank'Result = From + or else (Index_Non_Blank'Result > From) + = (Going = Forward)) + + -- The character at the returned index is not a Space character + + and then Source (Index_Non_Blank'Result) /= ' ' + + -- The result is the smallest or largest index which is not a + -- Space character, respectively when Going = Forward and + -- Going = Backward. + + and then + (for all J in Source'Range => + (if J /= Index_Non_Blank'Result + and then (J < Index_Non_Blank'Result) + = (Going = Forward) + and then (J = From or else (J > From) + = (Going = Forward)) + then Source (J) = ' '))), + Global => null; function Count (Source : String; Pattern : String; - Mapping : Maps.Character_Mapping := Maps.Identity) return Natural; + Mapping : Maps.Character_Mapping := Maps.Identity) return Natural + with + Pre => Pattern'Length > 0, + Global => null; function Count (Source : String; Pattern : String; - Mapping : Maps.Character_Mapping_Function) return Natural; + Mapping : Maps.Character_Mapping_Function) return Natural + with + Pre => Pattern'Length > 0 and then Mapping /= null, + Global => null; function Count (Source : String; - Set : Maps.Character_Set) return Natural; + Set : Maps.Character_Set) return Natural + with + Global => null; procedure Find_Token (Source : String; @@ -109,13 +522,104 @@ private package Ada.Strings.Search is From : Positive; Test : Membership; First : out Positive; - Last : out Natural); + Last : out Natural) + with + Pre => (if Source'Length /= 0 then From in Source'Range), + Contract_Cases => + + -- If Source is the empty string, or if no character of the considered + -- slice of Source satisfies the property Test on Set, then First is + -- set to From and Last is set to 0. + + (Source'Length = 0 + or else + (for all C of Source (From .. Source'Last) => + (Test = Inside) /= Ada.Strings.Maps.Is_In (C, Set)) + => + First = From and then Last = 0, + + -- Otherwise, First and Last are set to valid indexes + + others => + + -- First and Last are in the considered range of Source + + First in From .. Source'Last + and then Last in First .. Source'Last + + -- No character between From and First satisfies the property Test + -- on Set. + + and then + (for all C of Source (From .. First - 1) => + (Test = Inside) /= Ada.Strings.Maps.Is_In (C, Set)) + + -- All characters between First and Last satisfy the property Test + -- on Set. + + and then + (for all C of Source (First .. Last) => + (Test = Inside) = Ada.Strings.Maps.Is_In (C, Set)) + + -- If Last is not Source'Last, then the character at position + -- Last + 1 does not satify the property Test on Set. + + and then + (if Last < Source'Last + then (Test = Inside) + /= Ada.Strings.Maps.Is_In (Source (Last + 1), Set))), + Global => null; procedure Find_Token (Source : String; Set : Maps.Character_Set; Test : Membership; First : out Positive; - Last : out Natural); + Last : out Natural) + with + Pre => Source'First > 0, + Contract_Cases => + + -- If Source is the empty string, or if no character of Source + -- satisfies the property Test on Set, then First is set to From + -- and Last is set to 0. + + (Source'Length = 0 + or else + (for all C of Source => + (Test = Inside) /= Ada.Strings.Maps.Is_In (C, Set)) + => + First = Source'First and then Last = 0, + + -- Otherwise, First and Last are set to valid indexes + + others => + + -- First and Last are in the considered range of Source + + First in Source'Range + and then Last in First .. Source'Last + + -- No character before First satisfies the property Test on Set + + and then + (for all C of Source (Source'First .. First - 1) => + (Test = Inside) /= Ada.Strings.Maps.Is_In (C, Set)) + + -- All characters between First and Last satisfy the property Test + -- on Set. + + and then + (for all C of Source (First .. Last) => + (Test = Inside) = Ada.Strings.Maps.Is_In (C, Set)) + + -- If Last is not Source'Last, then the character at position + -- Last + 1 does not satify the property Test on Set. + + and then + (if Last < Source'Last + then (Test = Inside) + /= Ada.Strings.Maps.Is_In (Source (Last + 1), Set))), + Global => null; end Ada.Strings.Search; diff --git a/gcc/ada/libgnat/s-dwalin.adb b/gcc/ada/libgnat/s-dwalin.adb index 4a9d538..e02b0fd 100644 --- a/gcc/ada/libgnat/s-dwalin.adb +++ b/gcc/ada/libgnat/s-dwalin.adb @@ -31,7 +31,6 @@ with Ada.Characters.Handling; with Ada.Containers.Generic_Array_Sort; -with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback; with Ada.Unchecked_Deallocation; with Interfaces; use Interfaces; @@ -42,13 +41,16 @@ with System.Bounded_Strings; use System.Bounded_Strings; with System.IO; use System.IO; with System.Mmap; use System.Mmap; with System.Object_Reader; use System.Object_Reader; -with System.Traceback_Entries; use System.Traceback_Entries; with System.Storage_Elements; use System.Storage_Elements; package body System.Dwarf_Lines is SSU : constant := System.Storage_Unit; + function Get_Load_Displacement (C : Dwarf_Context) return Storage_Offset; + -- Return the displacement between the load address present in the binary + -- and the run-time address at which it is loaded (i.e. non-zero for PIE). + function String_Length (Str : Str_Access) return Natural; -- Return the length of the C string Str @@ -76,7 +78,7 @@ package body System.Dwarf_Lines is procedure Read_Aranges_Entry (C : in out Dwarf_Context; - Start : out Storage_Offset; + Start : out Address; Len : out Storage_Count); -- Read a single .debug_aranges pair @@ -88,7 +90,7 @@ package body System.Dwarf_Lines is procedure Aranges_Lookup (C : in out Dwarf_Context; - Addr : Storage_Offset; + Addr : Address; Info_Offset : out Offset; Success : out Boolean); -- Search for Addr in .debug_aranges and return offset Info_Offset in @@ -153,7 +155,7 @@ package body System.Dwarf_Lines is procedure Symbolic_Address (C : in out Dwarf_Context; - Addr : Storage_Offset; + Addr : Address; Dir_Name : out Str_Access; File_Name : out Str_Access; Subprg_Name : out String_Ptr_Len; @@ -370,6 +372,19 @@ package body System.Dwarf_Lines is end loop; end For_Each_Row; + --------------------------- + -- Get_Load_Displacement -- + --------------------------- + + function Get_Load_Displacement (C : Dwarf_Context) return Storage_Offset is + begin + if C.Load_Address /= Null_Address then + return C.Load_Address - Address (Get_Load_Address (C.Obj.all)); + else + return 0; + end if; + end Get_Load_Displacement; + --------------------- -- Initialize_Pass -- --------------------- @@ -405,18 +420,19 @@ package body System.Dwarf_Lines is --------------- function Is_Inside (C : Dwarf_Context; Addr : Address) return Boolean is + Disp : constant Storage_Offset := Get_Load_Displacement (C); + begin - return (Addr >= C.Low + C.Load_Address - and then Addr <= C.High + C.Load_Address); + return Addr >= C.Low + Disp and then Addr <= C.High + Disp; end Is_Inside; ----------------- -- Low_Address -- ----------------- - function Low_Address (C : Dwarf_Context) return System.Address is + function Low_Address (C : Dwarf_Context) return Address is begin - return C.Load_Address + C.Low; + return C.Low + Get_Load_Displacement (C); end Low_Address; ---------- @@ -450,12 +466,12 @@ package body System.Dwarf_Lines is Success := True; - -- Get memory bounds for executable code. Note that such code + -- Get address bounds for executable code. Note that such code -- might come from multiple sections. Get_Xcode_Bounds (C.Obj.all, Lo, Hi); - C.Low := Storage_Offset (Lo); - C.High := Storage_Offset (Hi); + C.Low := Address (Lo); + C.High := Address (Hi); -- Create a stream for debug sections @@ -568,10 +584,10 @@ package body System.Dwarf_Lines is Standard_Opcode_Lengths (J) := Read (C.Lines); end loop; - -- The directories table follows. Up to DWARF 4, this is a list of null + -- The Directories table follows. Up to DWARF 4, this is a list of null -- terminated strings terminated by a null byte. In DWARF 5, this is a - -- sequence of Directories_Count entries encoded as described by the - -- Directory_Entry_Format field. We store its offset for later decoding. + -- sequence of Directories_Count entries which are encoded as described + -- by the Directory_Entry_Format field. We store its offset for later. if Header.Version <= 4 then Tell (C.Lines, Header.Directories); @@ -603,12 +619,12 @@ package body System.Dwarf_Lines is end loop; end if; - -- The file_names table is next. Up to DWARF 4, this is a list of record + -- The File_Names table is next. Up to DWARF 4, this is a list of record -- containing a null terminated string for the file name, an unsigned -- LEB128 directory index in the Directories table, an unsigned LEB128 -- modification time, and an unsigned LEB128 for the file length; the -- table is terminated by a null byte. In DWARF 5, this is a sequence - -- of File_Names_Count entries encoded as described by the + -- of File_Names_Count entries which are encoded as described by the -- File_Name_Entry_Format field. We store its offset for later decoding. if Header.Version <= 4 then @@ -941,8 +957,10 @@ package body System.Dwarf_Lines is when DW_FORM_line_strp => Read_Section_Offset (C.Lines, Off, C.Header.Is64); - Seek (C.Line_Str, Off); - Read_C_String (C.Line_Str, Buf); + if J = File then + Seek (C.Line_Str, Off); + Read_C_String (C.Line_Str, Buf); + end if; when others => raise Dwarf_Error with "DWARF form not implemented"; @@ -1027,7 +1045,7 @@ package body System.Dwarf_Lines is case C_Type is when DW_LNCT_path .. DW_LNCT_MD5 => if N not in A'Range then - raise Dwarf_Error with "DWARF duplicate content type"; + raise Dwarf_Error with "duplicate DWARF content type"; end if; A (N) := (C_Type, Form); @@ -1048,7 +1066,7 @@ package body System.Dwarf_Lines is procedure Aranges_Lookup (C : in out Dwarf_Context; - Addr : Storage_Offset; + Addr : Address; Info_Offset : out Offset; Success : out Boolean) is @@ -1062,7 +1080,7 @@ package body System.Dwarf_Lines is loop declare - Start : Storage_Offset; + Start : Address; Len : Storage_Count; begin Read_Aranges_Entry (C, Start, Len); @@ -1098,8 +1116,6 @@ package body System.Dwarf_Lines is case Form is when DW_FORM_addr => Skip := Offset (Ptr_Sz); - when DW_FORM_addrx => - Skip := Offset (uint32'(Read_LEB128 (S))); when DW_FORM_block1 => Skip := Offset (uint8'(Read (S))); when DW_FORM_block2 => @@ -1145,11 +1161,12 @@ package body System.Dwarf_Lines is begin return; end; - when DW_FORM_udata - | DW_FORM_ref_udata + when DW_FORM_addrx | DW_FORM_loclistx + | DW_FORM_ref_udata | DW_FORM_rnglistx | DW_FORM_strx + | DW_FORM_udata => declare Val : constant uint32 := Read_LEB128 (S); @@ -1157,7 +1174,7 @@ package body System.Dwarf_Lines is begin return; end; - when DW_FORM_flag_present => + when DW_FORM_flag_present | DW_FORM_implicit_const => return; when DW_FORM_ref_addr | DW_FORM_sec_offset @@ -1171,10 +1188,10 @@ package body System.Dwarf_Lines is null; end loop; return; - when DW_FORM_implicit_const | DW_FORM_indirect => - raise Constraint_Error; + when DW_FORM_indirect => + raise Dwarf_Error with "DW_FORM_indirect not implemented"; when others => - raise Constraint_Error; + raise Dwarf_Error with "DWARF form not implemented"; end case; Seek (S, Tell (S) + Skip); @@ -1393,7 +1410,7 @@ package body System.Dwarf_Lines is procedure Read_Aranges_Entry (C : in out Dwarf_Context; - Start : out Storage_Offset; + Start : out Address; Len : out Storage_Count) is begin @@ -1405,7 +1422,7 @@ package body System.Dwarf_Lines is begin S := Read (C.Aranges); L := Read (C.Aranges); - Start := Storage_Offset (S); + Start := Address (S); Len := Storage_Count (L); end; @@ -1415,7 +1432,7 @@ package body System.Dwarf_Lines is begin S := Read (C.Aranges); L := Read (C.Aranges); - Start := Storage_Offset (S); + Start := Address (S); Len := Storage_Count (L); end; @@ -1505,11 +1522,12 @@ package body System.Dwarf_Lines is Info_Offset : Offset; Line_Offset : Offset; Success : Boolean; - Ar_Start : Storage_Offset; + Ar_Start : Address; Ar_Len : Storage_Count; Start, Len : uint32; First, Last : Natural; Mid : Natural; + begin Seek (C.Aranges, 0); @@ -1524,7 +1542,7 @@ package body System.Dwarf_Lines is loop Read_Aranges_Entry (C, Ar_Start, Ar_Len); - exit when Ar_Start = 0 and Ar_Len = 0; + exit when Ar_Start = Null_Address and Ar_Len = 0; Len := uint32 (Ar_Len); Start := uint32 (Ar_Start - C.Low); @@ -1580,7 +1598,7 @@ package body System.Dwarf_Lines is procedure Symbolic_Address (C : in out Dwarf_Context; - Addr : Storage_Offset; + Addr : Address; Dir_Name : out Str_Access; File_Name : out Str_Access; Subprg_Name : out String_Ptr_Len; @@ -1658,8 +1676,10 @@ package body System.Dwarf_Lines is when DW_FORM_line_strp => Read_Section_Offset (C.Lines, Off, C.Header.Is64); - Seek (C.Line_Str, Off); - File_Name := Read_C_String (C.Line_Str); + if J = Match.File then + Seek (C.Line_Str, Off); + File_Name := Read_C_String (C.Line_Str); + end if; when others => raise Dwarf_Error with "DWARF form not implemented"; @@ -1678,7 +1698,8 @@ package body System.Dwarf_Lines is Dir_Idx := Read_LEB128 (C.Lines); when others => - raise Dwarf_Error with "invalid DWARF"; + raise Dwarf_Error with + "invalid DWARF form for DW_LNCT_directory_index"; end case; else @@ -1702,8 +1723,10 @@ package body System.Dwarf_Lines is when DW_FORM_line_strp => Read_Section_Offset (C.Lines, Off, C.Header.Is64); - Seek (C.Line_Str, Off); - Dir_Name := Read_C_String (C.Line_Str); + if J = Dir_Idx then + Seek (C.Line_Str, Off); + Dir_Name := Read_C_String (C.Line_Str); + end if; when others => raise Dwarf_Error with "DWARF form not implemented"; @@ -1864,7 +1887,7 @@ package body System.Dwarf_Lines is procedure Symbolic_Traceback (Cin : Dwarf_Context; - Traceback : AET.Tracebacks_Array; + Traceback : STE.Tracebacks_Array; Suppress_Hex : Boolean; Symbol_Found : out Boolean; Res : in out System.Bounded_Strings.Bounded_String) @@ -1873,7 +1896,6 @@ package body System.Dwarf_Lines is C : Dwarf_Context := Cin; Addr_In_Traceback : Address; - Offset_To_Lookup : Storage_Offset; Dir_Name : Str_Access; File_Name : Str_Access; @@ -1893,13 +1915,11 @@ package body System.Dwarf_Lines is -- If the buffer is full, no need to do any useless work exit when Is_Full (Res); - Addr_In_Traceback := PC_For (Traceback (J)); - - Offset_To_Lookup := Addr_In_Traceback - C.Load_Address; + Addr_In_Traceback := STE.PC_For (Traceback (J)); Symbolic_Address (C, - Offset_To_Lookup, + Addr_In_Traceback - Get_Load_Displacement (C), Dir_Name, File_Name, Subprg_Name, diff --git a/gcc/ada/libgnat/s-dwalin.ads b/gcc/ada/libgnat/s-dwalin.ads index 132d3e1..bd86e5e 100644 --- a/gcc/ada/libgnat/s-dwalin.ads +++ b/gcc/ada/libgnat/s-dwalin.ads @@ -35,15 +35,13 @@ -- -- Files must be compiled with at least minimal debugging information (-g1). -with Ada.Exceptions.Traceback; - -with System.Object_Reader; -with System.Storage_Elements; with System.Bounded_Strings; +with System.Object_Reader; +with System.Traceback_Entries; package System.Dwarf_Lines is - package AET renames Ada.Exceptions.Traceback; + package STE renames System.Traceback_Entries; package SOR renames System.Object_Reader; type Dwarf_Context (In_Exception : Boolean := False) is private; @@ -58,19 +56,19 @@ package System.Dwarf_Lines is C : out Dwarf_Context; Success : out Boolean); procedure Close (C : in out Dwarf_Context); - -- Open and close files + -- Open and close a file procedure Set_Load_Address (C : in out Dwarf_Context; Addr : Address); - -- Set the load address of a file. This is used to rebase PIE (Position + -- Set the run-time load address of a file. Used to rebase PIE (Position -- Independent Executable) binaries. function Is_Inside (C : Dwarf_Context; Addr : Address) return Boolean; pragma Inline (Is_Inside); - -- Return true iff a run-time address Addr is within the module + -- Return whether a run-time address Addr lies within the file - function Low_Address (C : Dwarf_Context) return System.Address; + function Low_Address (C : Dwarf_Context) return Address; pragma Inline (Low_Address); - -- Return the lowest address of C, accounting for the module load address + -- Return the lowest run-time address of the file procedure Dump (C : in out Dwarf_Context); -- Dump each row found in the object's .debug_lines section to standard out @@ -83,7 +81,7 @@ package System.Dwarf_Lines is procedure Symbolic_Traceback (Cin : Dwarf_Context; - Traceback : AET.Tracebacks_Array; + Traceback : STE.Tracebacks_Array; Suppress_Hex : Boolean; Symbol_Found : out Boolean; Res : in out System.Bounded_Strings.Bounded_String); @@ -175,13 +173,13 @@ private type Search_Array_Access is access Search_Array; type Dwarf_Context (In_Exception : Boolean := False) is record - Low, High : System.Storage_Elements.Storage_Offset; - -- Bounds of the module, per the module object file + Low, High : Address; + -- Address bounds for executable code Obj : SOR.Object_File_Access; -- The object file containing dwarf sections - Load_Address : System.Address := System.Null_Address; + Load_Address : Address := Null_Address; -- The address at which the object file was loaded at run time Has_Debug : Boolean; diff --git a/gcc/ada/libgnat/s-ficobl.ads b/gcc/ada/libgnat/s-ficobl.ads index 6fff2da..4e97079 100644 --- a/gcc/ada/libgnat/s-ficobl.ads +++ b/gcc/ada/libgnat/s-ficobl.ads @@ -39,7 +39,7 @@ with Ada.Streams; with Interfaces.C_Streams; with System.CRTL; -package System.File_Control_Block is +package System.File_Control_Block with SPARK_Mode => Off is pragma Preelaborate; ---------------------------- diff --git a/gcc/ada/libgnat/s-objrea.adb b/gcc/ada/libgnat/s-objrea.adb index 9dd8c1f..e1bc677 100644 --- a/gcc/ada/libgnat/s-objrea.adb +++ b/gcc/ada/libgnat/s-objrea.adb @@ -36,6 +36,7 @@ with Interfaces.C; with System.CRTL; package body System.Object_Reader is + use Interfaces; use Interfaces.C; use System.Mmap; @@ -220,7 +221,6 @@ package body System.Object_Reader is Characteristics : uint16; Variant : uint16; end record; - pragma Pack (Header); type Optional_Header_PE32 is record @@ -306,7 +306,6 @@ package body System.Object_Reader is NumberOfLinenumbers : uint16; Characteristics : uint32; end record; - pragma Pack (Section_Header); IMAGE_SCN_CNT_CODE : constant := 16#0020#; @@ -319,7 +318,6 @@ package body System.Object_Reader is StorageClass : uint8; NumberOfAuxSymbols : uint8; end record; - pragma Pack (Symtab_Entry); type Auxent_Section is record @@ -435,7 +433,6 @@ package body System.Object_Reader is s_nlnno : uint16; s_flags : uint32; end record; - pragma Pack (Section_Header); STYP_TEXT : constant := 16#0020#; @@ -460,7 +457,6 @@ package body System.Object_Reader is x_snstab : uint16; end record; for Aux_Entry'Size use 18 * 8; - pragma Pack (Aux_Entry); C_EXT : constant := 2; @@ -549,6 +545,7 @@ package body System.Object_Reader is Shnum : uint32) return Object_Section is SHdr : constant Section_Header := Read_Section_Header (Obj, Shnum); + begin return (Shnum, Offset (SHdr.Sh_Offset), @@ -680,6 +677,7 @@ package body System.Object_Reader is function Read_Header (F : in out Mapped_Stream) return Header is Hdr : Header; + begin Seek (F, 0); Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU)); @@ -695,6 +693,7 @@ package body System.Object_Reader is Shnum : uint32) return Section_Header is Shdr : Section_Header; + begin Seek (Obj.Sectab_Stream, Offset (Shnum * Section_Header'Size / SSU)); Read_Raw (Obj.Sectab_Stream, Shdr'Address, Section_Header'Size / SSU); @@ -749,6 +748,7 @@ package body System.Object_Reader is Sec : Object_Section) return String is SHdr : Section_Header; + begin SHdr := Read_Section_Header (Obj, Sec.Num); return Offset_To_String (Obj.Secstr_Stream, Offset (SHdr.Sh_Name)); @@ -861,7 +861,8 @@ package body System.Object_Reader is ------------------ function First_Symbol - (Obj : in out PECOFF_Object_File) return Object_Symbol is + (Obj : in out PECOFF_Object_File) return Object_Symbol + is begin -- Return Null_Symbol in the case that the symbol table is empty @@ -881,6 +882,7 @@ package body System.Object_Reader is Index : uint32) return Object_Section is Sec : constant Section_Header := Read_Section_Header (Obj, Index); + begin -- Use VirtualSize instead of SizeOfRawData. The latter is rounded to -- the page size, so it may add garbage to the content. On the other @@ -938,6 +940,7 @@ package body System.Object_Reader is Hdr_Offset : Offset; Opt_Offset : File_Size; Opt_Stream : Mapped_Stream; + begin Res.MF := F; Res.In_Exception := In_Exception; @@ -1180,7 +1183,8 @@ package body System.Object_Reader is function String_Table (Obj : in out PECOFF_Object_File; - Index : Offset) return String is + Index : Offset) return String + is begin -- An index of zero is used to represent an empty string, as the -- first word of the string table is specified to contain the length @@ -1361,6 +1365,7 @@ package body System.Object_Reader is is Res : XCOFF32_Object_File (Format => XCOFF32); Strtab_Sz : uint32; + begin Res.Mf := F; Res.In_Exception := In_Exception; @@ -1401,6 +1406,7 @@ package body System.Object_Reader is Index : uint32) return Object_Section is Sec : constant Section_Header := Read_Section_Header (Obj, Index); + begin return (Index, Offset (Sec.s_scnptr), uint64 (Sec.s_vaddr), @@ -1414,6 +1420,7 @@ package body System.Object_Reader is function Read_Header (F : in out Mapped_Stream) return Header is Hdr : Header; + begin Seek (F, 0); Read_Raw (F, Hdr'Address, uint32 (Hdr'Size / SSU)); @@ -1428,7 +1435,7 @@ package body System.Object_Reader is (Obj : in out XCOFF32_Object_File; Index : uint32) return Section_Header is - Sec : Section_Header; + Sec : Section_Header; begin -- Seek to the end of the object header @@ -1451,6 +1458,7 @@ package body System.Object_Reader is Sec : Object_Section) return String is Hdr : Section_Header; + begin Hdr := Read_Section_Header (Obj, Sec.Num); return Trim_Trailing_Nuls (Hdr.s_name); @@ -1520,7 +1528,8 @@ package body System.Object_Reader is function Create_Stream (Obj : Object_File; - Sec : Object_Section) return Mapped_Stream is + Sec : Object_Section) return Mapped_Stream + is begin return Create_Stream (Obj.Mf, File_Size (Sec.Off), File_Size (Sec.Size)); end Create_Stream; @@ -1573,7 +1582,8 @@ package body System.Object_Reader is function Strip_Leading_Char (Obj : in out Object_File; - Sym : String_Ptr_Len) return Positive is + Sym : String_Ptr_Len) return Positive + is begin if (Obj.Format = PECOFF and then Sym.Ptr (1) = '_') or else @@ -1605,6 +1615,7 @@ package body System.Object_Reader is String (Sym.Ptr (1 .. Sym.Len)) & ASCII.NUL; Decoded : char_array (0 .. size_t (Sym.Len) * 2 + 60); Off : Natural; + begin -- In the PECOFF case most but not all symbol table entries have an -- extra leading underscore. In this case we trim it. @@ -1645,8 +1656,11 @@ package body System.Object_Reader is function Get_Load_Address (Obj : Object_File) return uint64 is begin - raise Format_Error with "Get_Load_Address not implemented"; - return 0; + case Obj.Format is + when ELF => return 0; + when Any_PECOFF => return Obj.ImageBase; + when XCOFF32 => raise Format_Error; + end case; end Get_Load_Address; ----------------- @@ -1655,7 +1669,8 @@ package body System.Object_Reader is function Get_Section (Obj : in out Object_File; - Shnum : uint32) return Object_Section is + Shnum : uint32) return Object_Section + is begin case Obj.Format is when ELF32 => return ELF32_Ops.Get_Section (Obj, Shnum); @@ -1692,9 +1707,11 @@ package body System.Object_Reader is ---------------------- procedure Get_Xcode_Bounds - (Obj : in out Object_File; - Low, High : out uint64) is + (Obj : in out Object_File; + Low, High : out uint64) + is Sec : Object_Section; + begin -- First set as an empty range Low := uint64'Last; @@ -1721,7 +1738,8 @@ package body System.Object_Reader is function Name (Obj : in out Object_File; - Sec : Object_Section) return String is + Sec : Object_Section) return String + is begin case Obj.Format is when ELF32 => return ELF32_Ops.Name (Obj, Sec); @@ -1733,7 +1751,8 @@ package body System.Object_Reader is function Name (Obj : in out Object_File; - Sym : Object_Symbol) return String_Ptr_Len is + Sym : Object_Symbol) return String_Ptr_Len + is begin case Obj.Format is when ELF32 => return ELF32_Ops.Name (Obj, Sym); @@ -1749,7 +1768,8 @@ package body System.Object_Reader is function Next_Symbol (Obj : in out Object_File; - Prev : Object_Symbol) return Object_Symbol is + Prev : Object_Symbol) return Object_Symbol + is begin -- Test whether we've reached the end of the symbol table @@ -1801,6 +1821,7 @@ package body System.Object_Reader is Off : Offset) return String is Buf : Buffer; + begin Seek (S, Off); Read_C_String (S, Buf); @@ -1922,10 +1943,10 @@ package body System.Object_Reader is -- Read -- ---------- - function Read (S : in out Mapped_Stream) return Mmap.Str_Access - is + function Read (S : in out Mapped_Stream) return Mmap.Str_Access is function To_Str_Access is new Ada.Unchecked_Conversion (Address, Str_Access); + begin return To_Str_Access (Data (S.Region) (Natural (S.Off + 1))'Address); end Read; @@ -1949,8 +1970,8 @@ package body System.Object_Reader is is function To_Str_Access is new Ada.Unchecked_Conversion (Address, Str_Access); - Sz : constant Offset := Offset (Size); + begin -- Check size @@ -2027,7 +2048,8 @@ package body System.Object_Reader is ------------------ function Read_Address - (Obj : Object_File; S : in out Mapped_Stream) return uint64 is + (Obj : Object_File; S : in out Mapped_Stream) return uint64 + is Address_32 : uint32; Address_64 : uint64; @@ -2147,7 +2169,8 @@ package body System.Object_Reader is function Read_Symbol (Obj : in out Object_File; - Off : Offset) return Object_Symbol is + Off : Offset) return Object_Symbol + is begin case Obj.Format is when ELF32 => return ELF32_Ops.Read_Symbol (Obj, Off); @@ -2221,7 +2244,8 @@ package body System.Object_Reader is function To_String_Ptr_Len (Ptr : Mmap.Str_Access; - Max_Len : Natural := Natural'Last) return String_Ptr_Len is + Max_Len : Natural := Natural'Last) return String_Ptr_Len + is begin for I in 1 .. Max_Len loop if Ptr (I) = ASCII.NUL then diff --git a/gcc/ada/libgnat/s-objrea.ads b/gcc/ada/libgnat/s-objrea.ads index a83ca53..d20a53d 100644 --- a/gcc/ada/libgnat/s-objrea.ads +++ b/gcc/ada/libgnat/s-objrea.ads @@ -287,7 +287,7 @@ package System.Object_Reader is (Obj : in out Object_File; Low, High : out uint64); -- Return the low and high addresses of the code for the object file. Can - -- be used to check if an address in within this object file. This + -- be used to check if an address lies within this object file. This -- procedure is not efficient and the result should be saved to avoid -- recomputation. @@ -381,9 +381,8 @@ private subtype Any_PECOFF is Object_Format range PECOFF .. PECOFF_PLUS; type Object_File (Format : Object_Format) is record - Mf : System.Mmap.Mapped_File := - System.Mmap.Invalid_Mapped_File; - Arch : Object_Arch := Unknown; + Mf : System.Mmap.Mapped_File := System.Mmap.Invalid_Mapped_File; + Arch : Object_Arch := Unknown; Num_Sections : uint32 := 0; -- Number of sections @@ -406,6 +405,7 @@ private when ELF => Secstr_Stream : Mapped_Stream; -- Section strings + when Any_PECOFF => ImageBase : uint64; -- ImageBase value from header @@ -413,19 +413,20 @@ private GSVA_Sec : uint32 := uint32'Last; GSVA_Addr : uint64; + when XCOFF32 => null; end case; end record; - subtype ELF_Object_File is Object_File; -- with - -- Predicate => ELF_Object_File.Format in ELF; - subtype PECOFF_Object_File is Object_File; -- with - -- Predicate => PECOFF_Object_File.Format in Any_PECOFF; - subtype XCOFF32_Object_File is Object_File; -- with - -- Predicate => XCOFF32_Object_File.Format in XCOFF32; - -- ???Above predicates cause the compiler to crash when instantiating - -- ELF64_Ops (see package body). + subtype ELF_Object_File is Object_File + with Predicate => ELF_Object_File.Format in ELF; + + subtype PECOFF_Object_File is Object_File + with Predicate => PECOFF_Object_File.Format in Any_PECOFF; + + subtype XCOFF32_Object_File is Object_File + with Predicate => XCOFF32_Object_File.Format in XCOFF32; type Object_Section is record Num : uint32 := 0; diff --git a/gcc/ada/libgnat/s-os_lib.ads b/gcc/ada/libgnat/s-os_lib.ads index 2049e38..139d2e0 100644 --- a/gcc/ada/libgnat/s-os_lib.ads +++ b/gcc/ada/libgnat/s-os_lib.ads @@ -169,16 +169,15 @@ package System.OS_Lib is ------------------ -- Note: Do not use time_t in the compiler and host-based tools; instead - -- use OS_Time. These 3 declarations are intended for use only by consumers - -- of the GNAT.OS_Lib renaming of this package. + -- use OS_Time. subtype time_t is Long_Long_Integer; - -- C time_t can be either long or long long, but this is a subtype not used - -- in the compiler or tools, but only for user applications, so we choose - -- the Ada equivalent of the latter because eventually that will be the + -- C time_t can be either long or long long, so we choose the Ada + -- equivalent of the latter because eventually that will be the -- type used out of necessity. This may affect some user code on 32-bit -- targets that have not yet migrated to the Posix 2008 standard, - -- particularly pre version 5 32-bit Linux. + -- particularly pre version 5 32-bit Linux. Do not change this + -- declaration without coordinating it with conversions in Ada.Calendar. function To_C (Time : OS_Time) return time_t; -- Convert OS_Time to C time_t type diff --git a/gcc/ada/libgnat/s-osprim__vxworks.adb b/gcc/ada/libgnat/s-osprim__vxworks.adb deleted file mode 100644 index ad2ac40..0000000 --- a/gcc/ada/libgnat/s-osprim__vxworks.adb +++ /dev/null @@ -1,162 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- --- -- --- S Y S T E M . O S _ P R I M I T I V E S -- --- -- --- B o d y -- --- -- --- Copyright (C) 1998-2021, Free Software Foundation, Inc. -- --- -- --- GNARL is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNARL was developed by the GNARL team at Florida State University. -- --- Extensive contributions were provided by Ada Core Technologies, Inc. -- --- -- ------------------------------------------------------------------------------- - --- This version is for VxWorks targets - -with System.OS_Interface; --- Since the thread library is part of the VxWorks kernel, using OS_Interface --- is not a problem here, as long as we only use System.OS_Interface as a --- set of C imported routines: using Ada routines from this package would --- create a dependency on libgnarl in libgnat, which is not desirable. - -with System.OS_Constants; -with Interfaces.C; - -package body System.OS_Primitives is - - use System.OS_Interface; - use type Interfaces.C.int; - - package OSC renames System.OS_Constants; - - ------------------------ - -- Internal functions -- - ------------------------ - - function To_Clock_Ticks (D : Duration) return int; - -- Convert a duration value (in seconds) into clock ticks. - -- Note that this routine is duplicated from System.OS_Interface since - -- as explained above, we do not want to depend on libgnarl - - function To_Clock_Ticks (D : Duration) return int is - Ticks : Long_Long_Integer; - Rate_Duration : Duration; - Ticks_Duration : Duration; - - begin - if D < 0.0 then - return -1; - end if; - - -- Ensure that the duration can be converted to ticks - -- at the current clock tick rate without overflowing. - - Rate_Duration := Duration (sysClkRateGet); - - if D > (Duration'Last / Rate_Duration) then - Ticks := Long_Long_Integer (int'Last); - else - Ticks_Duration := D * Rate_Duration; - Ticks := Long_Long_Integer (Ticks_Duration); - - if Ticks_Duration > Duration (Ticks) then - Ticks := Ticks + 1; - end if; - - if Ticks > Long_Long_Integer (int'Last) then - Ticks := Long_Long_Integer (int'Last); - end if; - end if; - - return int (Ticks); - end To_Clock_Ticks; - - ----------- - -- Clock -- - ----------- - - function Clock return Duration is - TS : aliased timespec; - Result : int; - begin - Result := clock_gettime (OSC.CLOCK_RT_Ada, TS'Unchecked_Access); - pragma Assert (Result = 0); - return Duration (TS.ts_sec) + Duration (TS.ts_nsec) / 10#1#E9; - end Clock; - - ----------------- - -- Timed_Delay -- - ----------------- - - procedure Timed_Delay - (Time : Duration; - Mode : Integer) - is - Rel_Time : Duration; - Abs_Time : Duration; - Base_Time : constant Duration := Clock; - Check_Time : Duration := Base_Time; - Ticks : int; - - Result : int; - pragma Unreferenced (Result); - - begin - if Mode = Relative then - Rel_Time := Time; - Abs_Time := Time + Check_Time; - else - Rel_Time := Time - Check_Time; - Abs_Time := Time; - end if; - - if Rel_Time > 0.0 then - loop - Ticks := To_Clock_Ticks (Rel_Time); - - if Mode = Relative and then Ticks < int'Last then - -- The first tick will delay anytime between 0 and - -- 1 / sysClkRateGet seconds, so we need to add one to - -- be on the safe side. - - Ticks := Ticks + 1; - end if; - - Result := taskDelay (Ticks); - Check_Time := Clock; - - exit when Abs_Time <= Check_Time or else Check_Time < Base_Time; - - Rel_Time := Abs_Time - Check_Time; - end loop; - end if; - end Timed_Delay; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize is - begin - null; - end Initialize; - -end System.OS_Primitives; diff --git a/gcc/ada/libgnat/s-osvers__vxworks-653.ads b/gcc/ada/libgnat/s-osvers__vxworks-653.ads deleted file mode 100644 index e180e7c..0000000 --- a/gcc/ada/libgnat/s-osvers__vxworks-653.ads +++ /dev/null @@ -1,38 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME LIBRARY COMPONENTS -- --- -- --- S Y S T E M . O S _ V E R S I O N -- --- -- --- S p e c -- --- -- --- Copyright (C) 2010-2021, AdaCore -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- ------------------------------------------------------------------------------- - --- This is the VxWorks 653 Partition OS version of this file. If you add an OS --- variant please be sure to update type OS_Version in all variants of this --- file, which is part of the Level A certified run-time libraries. - -package System.OS_Versions is - pragma Pure (System.OS_Versions); - type OS_Version is - (LynxOS_178, VxWorks_Cert, VxWorks_Cert_RTP, VxWorks_653, VxWorks_MILS); - OS : constant OS_Version := VxWorks_653; -end System.OS_Versions; diff --git a/gcc/ada/libgnat/system-vxworks-e500-vthread.ads b/gcc/ada/libgnat/system-vxworks-e500-vthread.ads deleted file mode 100644 index 0857c67..0000000 --- a/gcc/ada/libgnat/system-vxworks-e500-vthread.ads +++ /dev/null @@ -1,162 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME COMPONENTS -- --- -- --- S Y S T E M -- --- -- --- S p e c -- --- (VxWorks e500 AE653 vThreads) -- --- -- --- Copyright (C) 1992-2021, Free Software Foundation, Inc. -- --- -- --- This specification is derived from the Ada Reference Manual for use with -- --- GNAT. The copyright notice above, and the license provisions that follow -- --- apply solely to the contents of the part following the private keyword. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - --- This version is for the AE653/e500v2 vThreads full run-time - -package System is - pragma Pure; - -- Note that we take advantage of the implementation permission to make - -- this unit Pure instead of Preelaborable; see RM 13.7.1(15). In Ada - -- 2005, this is Pure in any case (AI-362). - - pragma No_Elaboration_Code_All; - -- Allow the use of that restriction in units that WITH this unit - - type Name is (SYSTEM_NAME_GNAT); - System_Name : constant Name := SYSTEM_NAME_GNAT; - - -- System-Dependent Named Numbers - - Min_Int : constant := -2 ** (Standard'Max_Integer_Size - 1); - Max_Int : constant := 2 ** (Standard'Max_Integer_Size - 1) - 1; - - Max_Binary_Modulus : constant := 2 ** Standard'Max_Integer_Size; - Max_Nonbinary_Modulus : constant := 2 ** Integer'Size - 1; - - Max_Base_Digits : constant := Long_Long_Float'Digits; - Max_Digits : constant := Long_Long_Float'Digits; - - Max_Mantissa : constant := Standard'Max_Integer_Size - 1; - Fine_Delta : constant := 2.0 ** (-Max_Mantissa); - - Tick : constant := 1.0 / 60.0; - - -- Storage-related Declarations - - type Address is private; - pragma Preelaborable_Initialization (Address); - Null_Address : constant Address; - - Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; - - -- Address comparison - - function "<" (Left, Right : Address) return Boolean; - function "<=" (Left, Right : Address) return Boolean; - function ">" (Left, Right : Address) return Boolean; - function ">=" (Left, Right : Address) return Boolean; - function "=" (Left, Right : Address) return Boolean; - - pragma Import (Intrinsic, "<"); - pragma Import (Intrinsic, "<="); - pragma Import (Intrinsic, ">"); - pragma Import (Intrinsic, ">="); - pragma Import (Intrinsic, "="); - - -- Other System-Dependent Declarations - - type Bit_Order is (High_Order_First, Low_Order_First); - Default_Bit_Order : constant Bit_Order := High_Order_First; - pragma Warnings (Off, Default_Bit_Order); -- kill constant condition warning - - -- Priority-related Declarations (RM D.1) - - -- Ada priorities are mapped to VxWorks priorities using the following - -- transformation: 255 - Ada Priority - - -- Ada priorities are used as follows: - - -- 256 is reserved for the VxWorks kernel - -- 248 - 255 correspond to hardware interrupt levels 0 .. 7 - -- 247 is a catchall default "interrupt" priority for signals, - -- allowing higher priority than normal tasks, but lower than - -- hardware priority levels. Protected Object ceilings can - -- override these values. - -- 246 is used by the Interrupt_Manager task - - Max_Priority : constant Positive := 245; - Max_Interrupt_Priority : constant Positive := 255; - - subtype Any_Priority is Integer range 0 .. 255; - subtype Priority is Any_Priority range 0 .. 245; - subtype Interrupt_Priority is Any_Priority range 246 .. 255; - - Default_Priority : constant Priority := 122; - -private - - type Address is mod Memory_Size; - Null_Address : constant Address := 0; - - -------------------------------------- - -- System Implementation Parameters -- - -------------------------------------- - - -- These parameters provide information about the target that is used - -- by the compiler. They are in the private part of System, where they - -- can be accessed using the special circuitry in the Targparm unit - -- whose source should be consulted for more detailed descriptions - -- of the individual switch values. - - Backend_Divide_Checks : constant Boolean := False; - Backend_Overflow_Checks : constant Boolean := True; - Command_Line_Args : constant Boolean := False; - Configurable_Run_Time : constant Boolean := False; - Denorm : constant Boolean := True; - Duration_32_Bits : constant Boolean := False; - Exit_Status_Supported : constant Boolean := True; - Machine_Overflows : constant Boolean := False; - Machine_Rounds : constant Boolean := True; - Preallocated_Stacks : constant Boolean := False; - Signed_Zeros : constant Boolean := True; - Stack_Check_Default : constant Boolean := False; - Stack_Check_Probes : constant Boolean := True; - Stack_Check_Limits : constant Boolean := False; - Support_Aggregates : constant Boolean := True; - Support_Composite_Assign : constant Boolean := True; - Support_Composite_Compare : constant Boolean := True; - Support_Long_Shifts : constant Boolean := True; - Always_Compatible_Rep : constant Boolean := False; - Suppress_Standard_Library : constant Boolean := False; - Use_Ada_Main_Program_Name : constant Boolean := True; - Frontend_Exceptions : constant Boolean := False; - ZCX_By_Default : constant Boolean := False; - - Executable_Extension : constant String := ".out"; - -end System; diff --git a/gcc/ada/libgnat/system-vxworks-ppc-vthread.ads b/gcc/ada/libgnat/system-vxworks-ppc-vthread.ads deleted file mode 100644 index 64f1303..0000000 --- a/gcc/ada/libgnat/system-vxworks-ppc-vthread.ads +++ /dev/null @@ -1,162 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME COMPONENTS -- --- -- --- S Y S T E M -- --- -- --- S p e c -- --- (VxWorks PPC AE653 vThreads) -- --- -- --- Copyright (C) 1992-2021, Free Software Foundation, Inc. -- --- -- --- This specification is derived from the Ada Reference Manual for use with -- --- GNAT. The copyright notice above, and the license provisions that follow -- --- apply solely to the contents of the part following the private keyword. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - --- This version is for the AE653 vThreads full run-time - -package System is - pragma Pure; - -- Note that we take advantage of the implementation permission to make - -- this unit Pure instead of Preelaborable; see RM 13.7.1(15). In Ada - -- 2005, this is Pure in any case (AI-362). - - pragma No_Elaboration_Code_All; - -- Allow the use of that restriction in units that WITH this unit - - type Name is (SYSTEM_NAME_GNAT); - System_Name : constant Name := SYSTEM_NAME_GNAT; - - -- System-Dependent Named Numbers - - Min_Int : constant := -2 ** (Standard'Max_Integer_Size - 1); - Max_Int : constant := 2 ** (Standard'Max_Integer_Size - 1) - 1; - - Max_Binary_Modulus : constant := 2 ** Standard'Max_Integer_Size; - Max_Nonbinary_Modulus : constant := 2 ** Integer'Size - 1; - - Max_Base_Digits : constant := Long_Long_Float'Digits; - Max_Digits : constant := Long_Long_Float'Digits; - - Max_Mantissa : constant := Standard'Max_Integer_Size - 1; - Fine_Delta : constant := 2.0 ** (-Max_Mantissa); - - Tick : constant := 1.0 / 60.0; - - -- Storage-related Declarations - - type Address is private; - pragma Preelaborable_Initialization (Address); - Null_Address : constant Address; - - Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; - - -- Address comparison - - function "<" (Left, Right : Address) return Boolean; - function "<=" (Left, Right : Address) return Boolean; - function ">" (Left, Right : Address) return Boolean; - function ">=" (Left, Right : Address) return Boolean; - function "=" (Left, Right : Address) return Boolean; - - pragma Import (Intrinsic, "<"); - pragma Import (Intrinsic, "<="); - pragma Import (Intrinsic, ">"); - pragma Import (Intrinsic, ">="); - pragma Import (Intrinsic, "="); - - -- Other System-Dependent Declarations - - type Bit_Order is (High_Order_First, Low_Order_First); - Default_Bit_Order : constant Bit_Order := High_Order_First; - pragma Warnings (Off, Default_Bit_Order); -- kill constant condition warning - - -- Priority-related Declarations (RM D.1) - - -- Ada priorities are mapped to VxWorks priorities using the following - -- transformation: 255 - Ada Priority - - -- Ada priorities are used as follows: - - -- 256 is reserved for the VxWorks kernel - -- 248 - 255 correspond to hardware interrupt levels 0 .. 7 - -- 247 is a catchall default "interrupt" priority for signals, - -- allowing higher priority than normal tasks, but lower than - -- hardware priority levels. Protected Object ceilings can - -- override these values. - -- 246 is used by the Interrupt_Manager task - - Max_Priority : constant Positive := 245; - Max_Interrupt_Priority : constant Positive := 255; - - subtype Any_Priority is Integer range 0 .. 255; - subtype Priority is Any_Priority range 0 .. 245; - subtype Interrupt_Priority is Any_Priority range 246 .. 255; - - Default_Priority : constant Priority := 122; - -private - - type Address is mod Memory_Size; - Null_Address : constant Address := 0; - - -------------------------------------- - -- System Implementation Parameters -- - -------------------------------------- - - -- These parameters provide information about the target that is used - -- by the compiler. They are in the private part of System, where they - -- can be accessed using the special circuitry in the Targparm unit - -- whose source should be consulted for more detailed descriptions - -- of the individual switch values. - - Backend_Divide_Checks : constant Boolean := False; - Backend_Overflow_Checks : constant Boolean := True; - Command_Line_Args : constant Boolean := False; - Configurable_Run_Time : constant Boolean := False; - Denorm : constant Boolean := True; - Duration_32_Bits : constant Boolean := False; - Exit_Status_Supported : constant Boolean := True; - Machine_Overflows : constant Boolean := True; - Machine_Rounds : constant Boolean := True; - Preallocated_Stacks : constant Boolean := False; - Signed_Zeros : constant Boolean := True; - Stack_Check_Default : constant Boolean := False; - Stack_Check_Probes : constant Boolean := True; - Stack_Check_Limits : constant Boolean := False; - Support_Aggregates : constant Boolean := True; - Support_Composite_Assign : constant Boolean := True; - Support_Composite_Compare : constant Boolean := True; - Support_Long_Shifts : constant Boolean := True; - Always_Compatible_Rep : constant Boolean := False; - Suppress_Standard_Library : constant Boolean := False; - Use_Ada_Main_Program_Name : constant Boolean := True; - Frontend_Exceptions : constant Boolean := False; - ZCX_By_Default : constant Boolean := False; - - Executable_Extension : constant String := ".out"; - -end System; diff --git a/gcc/ada/libgnat/system-vxworks-x86-vthread.ads b/gcc/ada/libgnat/system-vxworks-x86-vthread.ads deleted file mode 100644 index 3b78e7e..0000000 --- a/gcc/ada/libgnat/system-vxworks-x86-vthread.ads +++ /dev/null @@ -1,163 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME COMPONENTS -- --- -- --- S Y S T E M -- --- -- --- S p e c -- --- (VxWorks 653 x86 vThreads) -- --- -- --- Copyright (C) 1992-2021, Free Software Foundation, Inc. -- --- -- --- This specification is derived from the Ada Reference Manual for use with -- --- GNAT. The copyright notice above, and the license provisions that follow -- --- apply solely to the contents of the part following the private keyword. -- --- -- --- GNAT is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNAT was originally developed by the GNAT team at New York University. -- --- Extensive contributions were provided by Ada Core Technologies Inc. -- --- -- ------------------------------------------------------------------------------- - --- This version is for the AE653 vThreads full run-time - -package System is - pragma Pure; - -- Note that we take advantage of the implementation permission to make - -- this unit Pure instead of Preelaborable; see RM 13.7.1(15). In Ada - -- 2005, this is Pure in any case (AI-362). - - pragma No_Elaboration_Code_All; - -- Allow the use of that restriction in units that WITH this unit - - type Name is (SYSTEM_NAME_GNAT); - System_Name : constant Name := SYSTEM_NAME_GNAT; - - -- System-Dependent Named Numbers - - Min_Int : constant := -2 ** (Standard'Max_Integer_Size - 1); - Max_Int : constant := 2 ** (Standard'Max_Integer_Size - 1) - 1; - - Max_Binary_Modulus : constant := 2 ** Standard'Max_Integer_Size; - Max_Nonbinary_Modulus : constant := 2 ** Integer'Size - 1; - - Max_Base_Digits : constant := Long_Long_Float'Digits; - Max_Digits : constant := Long_Long_Float'Digits; - - Max_Mantissa : constant := Standard'Max_Integer_Size - 1; - Fine_Delta : constant := 2.0 ** (-Max_Mantissa); - - Tick : constant := 1.0 / 60.0; - - -- Storage-related Declarations - - type Address is private; - pragma Preelaborable_Initialization (Address); - Null_Address : constant Address; - - Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; - - -- Address comparison - - function "<" (Left, Right : Address) return Boolean; - function "<=" (Left, Right : Address) return Boolean; - function ">" (Left, Right : Address) return Boolean; - function ">=" (Left, Right : Address) return Boolean; - function "=" (Left, Right : Address) return Boolean; - - pragma Import (Intrinsic, "<"); - pragma Import (Intrinsic, "<="); - pragma Import (Intrinsic, ">"); - pragma Import (Intrinsic, ">="); - pragma Import (Intrinsic, "="); - - -- Other System-Dependent Declarations - - type Bit_Order is (High_Order_First, Low_Order_First); - Default_Bit_Order : constant Bit_Order := Low_Order_First; - pragma Warnings (Off, Default_Bit_Order); -- kill constant condition warning - - -- Priority-related Declarations (RM D.1) - - -- Ada priorities are mapped to VxWorks priorities using the following - -- transformation: 255 - Ada Priority - - -- Ada priorities are used as follows: - - -- 256 is reserved for the VxWorks kernel - -- 248 - 255 correspond to hardware interrupt levels 0 .. 7 - -- 247 is a catchall default "interrupt" priority for signals, - -- allowing higher priority than normal tasks, but lower than - -- hardware priority levels. Protected Object ceilings can - -- override these values. - -- 246 is used by the Interrupt_Manager task - - Max_Priority : constant Positive := 245; - Max_Interrupt_Priority : constant Positive := 255; - - subtype Any_Priority is Integer range 0 .. 255; - subtype Priority is Any_Priority range 0 .. 245; - subtype Interrupt_Priority is Any_Priority range 246 .. 255; - - Default_Priority : constant Priority := 122; - -private - - type Address is mod Memory_Size; - Null_Address : constant Address := 0; - - -------------------------------------- - -- System Implementation Parameters -- - -------------------------------------- - - -- These parameters provide information about the target that is used - -- by the compiler. They are in the private part of System, where they - -- can be accessed using the special circuitry in the Targparm unit - -- whose source should be consulted for more detailed descriptions - -- of the individual switch values. - - Backend_Divide_Checks : constant Boolean := False; - Backend_Overflow_Checks : constant Boolean := True; - Command_Line_Args : constant Boolean := False; - Configurable_Run_Time : constant Boolean := False; - Denorm : constant Boolean := True; - Duration_32_Bits : constant Boolean := False; - Exit_Status_Supported : constant Boolean := True; - Machine_Overflows : constant Boolean := True; - Machine_Rounds : constant Boolean := True; - Preallocated_Stacks : constant Boolean := False; - Signed_Zeros : constant Boolean := True; - Stack_Check_Default : constant Boolean := False; - Stack_Check_Probes : constant Boolean := True; - Stack_Check_Limits : constant Boolean := False; - Support_Aggregates : constant Boolean := True; - Support_Atomic_Primitives : constant Boolean := True; - Support_Composite_Assign : constant Boolean := True; - Support_Composite_Compare : constant Boolean := True; - Support_Long_Shifts : constant Boolean := True; - Always_Compatible_Rep : constant Boolean := False; - Suppress_Standard_Library : constant Boolean := False; - Use_Ada_Main_Program_Name : constant Boolean := True; - Frontend_Exceptions : constant Boolean := False; - ZCX_By_Default : constant Boolean := False; - - Executable_Extension : constant String := ".out"; - -end System; diff --git a/gcc/ada/par_sco.adb b/gcc/ada/par_sco.adb index b4f7609..513275a 100644 --- a/gcc/ada/par_sco.adb +++ b/gcc/ada/par_sco.adb @@ -2248,6 +2248,8 @@ package body Par_SCO is | Name_Loop_Invariant | Name_Postcondition | Name_Precondition + | Name_Type_Invariant + | Name_Invariant => -- For Assert/Check/Precondition/Postcondition, we -- must generate a P entry for the decision. Note @@ -2256,7 +2258,10 @@ package body Par_SCO is -- on when we output the decision line in Put_SCOs, -- depending on setting by Set_SCO_Pragma_Enabled. - if Nam = Name_Check then + if Nam = Name_Check + or else Nam = Name_Type_Invariant + or else Nam = Name_Invariant + then Next (Arg); end if; @@ -2285,8 +2290,7 @@ package body Par_SCO is -- never disabled. -- Should generate P decisions (not X) for assertion - -- related pragmas: [Type_]Invariant, - -- [{Static,Dynamic}_]Predicate??? + -- related pragmas: [{Static,Dynamic}_]Predicate??? when others => Process_Decisions_Defer (N, 'X'); diff --git a/gcc/ada/repinfo-input.adb b/gcc/ada/repinfo-input.adb index 5d85040..7e250a4 100644 --- a/gcc/ada/repinfo-input.adb +++ b/gcc/ada/repinfo-input.adb @@ -776,7 +776,7 @@ package body Repinfo.Input is -- Compute Component_Bit_Offset from Position and First_Bit, -- either symbolically or literally depending on Position. - if Position = No_Uint or else First_Bit = No_Uint then + if No (Position) or else No (First_Bit) then Error ("bit offset expected"); end if; diff --git a/gcc/ada/repinfo.adb b/gcc/ada/repinfo.adb index 148de53..58e0161 100644 --- a/gcc/ada/repinfo.adb +++ b/gcc/ada/repinfo.adb @@ -422,7 +422,8 @@ package body Repinfo is Write_Line (";"); end if; - -- Alignment is not always set for task and protected types + -- Alignment is not always set for task, protected, and class-wide + -- types. else pragma Assert @@ -807,7 +808,7 @@ package body Repinfo is -- Start of processing for List_GCC_Expression begin - if U = No_Uint then + if No (U) then Write_Unknown_Val; else Print_Expr (U); @@ -1188,13 +1189,7 @@ package body Repinfo is Write_Str (" .. "); end if; - -- Allowing Uint_0 here is an annoying special case. Really this - -- should be a fine Esize value but currently it means unknown, - -- except that we know after gigi has back annotated that a size - -- of zero is real, since otherwise gigi back annotates using - -- No_Uint as the value to indicate unknown. - - if (Esize (Ent) = Uint_0 or else Known_Static_Esize (Ent)) + if Known_Static_Esize (Ent) and then Known_Static_Normalized_First_Bit (Ent) then Lbit := Sbit + Esiz - 1; @@ -1209,14 +1204,7 @@ package body Repinfo is UI_Write (Lbit, Decimal); end if; - -- The test for Esize (Ent) not Uint_0 here is an annoying special - -- case. Officially a value of zero for Esize means unknown, but - -- here we use the fact that we know that gigi annotates Esize with - -- No_Uint, not Uint_0. Really everyone should use No_Uint??? - - elsif List_Representation_Info < 3 - or else (Esize (Ent) /= Uint_0 and then not Known_Esize (Ent)) - then + elsif List_Representation_Info < 3 or else not Known_Esize (Ent) then Write_Unknown_Val; -- List_Representation >= 3 and Known_Esize (Ent) @@ -2116,7 +2104,7 @@ package body Repinfo is function Rep_Not_Constant (Val : Node_Ref_Or_Val) return Boolean is begin - if Val = No_Uint or else Val < 0 then + if No (Val) or else Val < 0 then return True; else return False; @@ -2315,7 +2303,7 @@ package body Repinfo is -- Start of processing for Rep_Value begin - if Val = No_Uint then + if No (Val) then return No_Uint; else @@ -2401,7 +2389,7 @@ package body Repinfo is procedure Write_Val (Val : Node_Ref_Or_Val; Paren : Boolean := False) is begin if Rep_Not_Constant (Val) then - if List_Representation_Info < 3 or else Val = No_Uint then + if List_Representation_Info < 3 or else No (Val) then Write_Unknown_Val; else diff --git a/gcc/ada/scn.adb b/gcc/ada/scn.adb index ad53279..e81985f 100644 --- a/gcc/ada/scn.adb +++ b/gcc/ada/scn.adb @@ -159,7 +159,7 @@ package body Scn is -- Int_Literal_Value can be No_Uint in some cases in syntax-only -- mode (see Scng.Scan.Nlit). - if Int_Literal_Value /= No_Uint then + if Present (Int_Literal_Value) then Set_Intval (Token_Node, Int_Literal_Value); end if; diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index d1a91d8..b44bbe3 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -175,6 +175,7 @@ package body Sem_Attr is Attribute_22 : constant Attribute_Class_Array := Attribute_Class_Array'( Attribute_Enum_Rep | Attribute_Enum_Val => True, + Attribute_Preelaborable_Initialization => True, others => False); -- The following array contains all attributes that imply a modification @@ -5408,6 +5409,45 @@ package body Sem_Attr is end if; end if; + ---------------------------------- + -- Preelaborable_Initialization -- + ---------------------------------- + + when Attribute_Preelaborable_Initialization => + Check_E0; + Check_Type; + + -- If we're in an instance, we know that the legality of the + -- attribute prefix type was already checked in the generic. + + if not In_Instance then + + -- If the prefix type is a generic formal type, then it must be + -- either a formal private type or a formal derived type. + + if Is_Generic_Type (P_Type) then + if not Is_Private_Type (P_Type) + and then not Is_Derived_Type (P_Type) + then + Error_Attr_P ("formal type prefix of % attribute must be " + & "formal private or formal derived type"); + end if; + + -- Otherwise, the prefix type must be a nonformal composite + -- type declared within the visible part of a package or + -- generic package. + + elsif not Is_Composite_Type (P_Type) + or else not Original_View_In_Visible_Part (P_Type) + then + Error_Attr_P + ("prefix of % attribute must be composite type declared " + & "in visible part of a package or generic package"); + end if; + end if; + + Set_Etype (N, Standard_Boolean); + -------------- -- Priority -- -------------- @@ -8084,13 +8124,13 @@ package body Sem_Attr is end if; -- If we are asked to evaluate an attribute where the prefix is a - -- non-frozen generic actual type whose RM_Size is still set to zero, + -- non-frozen generic actual type whose RM_Size has not been set, -- then abandon the effort. if Is_Type (P_Entity) and then (not Is_Frozen (P_Entity) and then Is_Generic_Actual_Type (P_Entity) - and then RM_Size (P_Entity) = 0) + and then not Known_RM_Size (P_Entity)) -- However, the attribute Unconstrained_Array must be evaluated, -- since it is documented to be a static attribute (and can for @@ -8182,15 +8222,16 @@ package body Sem_Attr is -- is to say if we are within an instantiation. Same processing applies -- to selected GNAT attributes. - elsif (Id = Attribute_Atomic_Always_Lock_Free or else - Id = Attribute_Definite or else - Id = Attribute_Descriptor_Size or else - Id = Attribute_Has_Access_Values or else - Id = Attribute_Has_Discriminants or else - Id = Attribute_Has_Tagged_Values or else - Id = Attribute_Lock_Free or else - Id = Attribute_Type_Class or else - Id = Attribute_Unconstrained_Array or else + elsif (Id = Attribute_Atomic_Always_Lock_Free or else + Id = Attribute_Definite or else + Id = Attribute_Descriptor_Size or else + Id = Attribute_Has_Access_Values or else + Id = Attribute_Has_Discriminants or else + Id = Attribute_Has_Tagged_Values or else + Id = Attribute_Lock_Free or else + Id = Attribute_Preelaborable_Initialization or else + Id = Attribute_Type_Class or else + Id = Attribute_Unconstrained_Array or else Id = Attribute_Max_Alignment_For_Allocation) and then not Is_Generic_Type (P_Entity) then @@ -8315,15 +8356,20 @@ package body Sem_Attr is -- unconstrained arrays. Furthermore, it is essential to fold this -- in the packed case, since otherwise the value will be incorrect. - elsif Id = Attribute_Atomic_Always_Lock_Free or else - Id = Attribute_Definite or else - Id = Attribute_Descriptor_Size or else - Id = Attribute_Has_Access_Values or else - Id = Attribute_Has_Discriminants or else - Id = Attribute_Has_Tagged_Values or else - Id = Attribute_Lock_Free or else - Id = Attribute_Type_Class or else - Id = Attribute_Unconstrained_Array or else + -- Folding can also be done for Preelaborable_Initialization based on + -- whether the prefix type has preelaborable initialization, even though + -- the attribute is nonstatic. + + elsif Id = Attribute_Atomic_Always_Lock_Free or else + Id = Attribute_Definite or else + Id = Attribute_Descriptor_Size or else + Id = Attribute_Has_Access_Values or else + Id = Attribute_Has_Discriminants or else + Id = Attribute_Has_Tagged_Values or else + Id = Attribute_Lock_Free or else + Id = Attribute_Preelaborable_Initialization or else + Id = Attribute_Type_Class or else + Id = Attribute_Unconstrained_Array or else Id = Attribute_Component_Size then Static := False; @@ -9143,7 +9189,7 @@ package body Sem_Attr is Fold_Uint (N, Uint_0, Static); when LT => - if Diff /= No_Uint then + if Present (Diff) then Fold_Uint (N, Diff + 1, Static); end if; @@ -9609,6 +9655,17 @@ package body Sem_Attr is Fold_Uint (N, Expr_Value (E1) - 1, Static); end if; + ---------------------------------- + -- Preelaborable_Initialization -- + ---------------------------------- + + when Attribute_Preelaborable_Initialization => + Fold_Uint + (N, + UI_From_Int + (Boolean'Pos (Has_Preelaborable_Initialization (P_Type))), + Static); + ----------- -- Range -- ----------- @@ -9653,7 +9710,7 @@ package body Sem_Attr is Fold_Uint (N, Uint_0, Static); when LT => - if Diff /= No_Uint then + if Present (Diff) then Fold_Uint (N, Diff + 1, Static); end if; @@ -9824,9 +9881,9 @@ package body Sem_Attr is P_TypeA : constant Entity_Id := Underlying_Type (P_Type); begin - if Is_Scalar_Type (P_TypeA) - or else RM_Size (P_TypeA) /= Uint_0 - then + pragma Assert + (if Is_Scalar_Type (P_TypeA) then Known_RM_Size (P_TypeA)); + if Known_RM_Size (P_TypeA) then -- VADS_Size case if Id = Attribute_VADS_Size or else Use_VADS_Size then @@ -10102,7 +10159,9 @@ package body Sem_Attr is P_TypeA : constant Entity_Id := Underlying_Type (P_Type); begin - if Is_Scalar_Type (P_TypeA) or else RM_Size (P_TypeA) /= Uint_0 then + pragma Assert + (if Is_Scalar_Type (P_TypeA) then Known_RM_Size (P_TypeA)); + if Known_RM_Size (P_TypeA) then Fold_Uint (N, RM_Size (P_TypeA), Static); end if; end Value_Size; diff --git a/gcc/ada/sem_aux.adb b/gcc/ada/sem_aux.adb index ea3b59c..bce7c38 100644 --- a/gcc/ada/sem_aux.adb +++ b/gcc/ada/sem_aux.adb @@ -846,10 +846,7 @@ package body Sem_Aux is Btype : constant Entity_Id := Base_Type (Ent); begin - if Error_Posted (Ent) or else Error_Posted (Btype) then - return False; - - elsif Is_Private_Type (Btype) then + if Is_Private_Type (Btype) then declare Utyp : constant Entity_Id := Underlying_Type (Btype); begin diff --git a/gcc/ada/sem_ch10.adb b/gcc/ada/sem_ch10.adb index 1e7b93c..dd78501 100644 --- a/gcc/ada/sem_ch10.adb +++ b/gcc/ada/sem_ch10.adb @@ -5825,7 +5825,7 @@ package body Sem_Ch10 is Set_Is_First_Subtype (Ent); Set_Scope (Ent, Scop); Set_Stored_Constraint (Ent, No_Elist); - Init_Size_Align (Ent); + Reinit_Size_Align (Ent); if From_Limited_With (Ent) then Set_Private_Dependents (Ent, New_Elmt_List); @@ -5865,7 +5865,7 @@ package body Sem_Ch10 is Set_Is_Tagged_Type (CW_Typ); Set_Materialize_Entity (CW_Typ, Materialize); Set_Scope (CW_Typ, Scop); - Init_Size_Align (CW_Typ); + Reinit_Size_Align (CW_Typ); end if; end Decorate_Type; diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 85c854f..eca2abf 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -2495,7 +2495,7 @@ package body Sem_Ch12 is Mutate_Ekind (T, E_Enumeration_Subtype); Set_Etype (T, Base); Init_Size (T, 8); - Init_Alignment (T); + Reinit_Alignment (T); Set_Is_Generic_Type (T); Set_Is_Constrained (T); @@ -2524,7 +2524,7 @@ package body Sem_Ch12 is Mutate_Ekind (Base, E_Enumeration_Type); Set_Etype (Base, Base); Init_Size (Base, 8); - Init_Alignment (Base); + Reinit_Alignment (Base); Set_Is_Generic_Type (Base); Set_Scalar_Range (Base, Scalar_Range (T)); Set_Parent (Base, Parent (Def)); @@ -7112,8 +7112,8 @@ package body Sem_Ch12 is Astype := First_Subtype (E); end if; - Set_Size_Info (E, (Astype)); - Set_RM_Size (E, RM_Size (Astype)); + Set_Size_Info (E, (Astype)); + Copy_RM_Size (To => E, From => Astype); Set_First_Rep_Item (E, First_Rep_Item (Astype)); if Is_Discrete_Or_Fixed_Point_Type (E) then diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb index 76859c5..228fd39 100644 --- a/gcc/ada/sem_ch13.adb +++ b/gcc/ada/sem_ch13.adb @@ -862,7 +862,7 @@ package body Sem_Ch13 is and then not Has_Alignment_Clause (Typ) and then Size mod (Alignment (Typ) * SSU) /= 0 then - Init_Alignment (Typ); + Reinit_Alignment (Typ); end if; end Alignment_Check_For_Size_Change; @@ -1455,9 +1455,17 @@ package body Sem_Ch13 is -- Aspect Full_Access_Only must be analyzed last so that -- aspects Volatile and Atomic, if any, are analyzed. + -- Skip creation of pragma Preelaborable_Initialization + -- in the case where the aspect has an expression, + -- because the pragma is only needed for setting flag + -- Known_To_Have_Preelab_Init, which is set by other + -- means following resolution of the aspect expression. + if A_Id not in Aspect_Export | Aspect_Full_Access_Only | Aspect_Import + and then (A_Id /= Aspect_Preelaborable_Initialization + or else not Present (Expression (ASN))) then Make_Pragma_From_Boolean_Aspect (ASN); end if; @@ -1876,6 +1884,11 @@ package body Sem_Ch13 is -- expression is allowed. Includes checking that the expression -- does not raise Constraint_Error. + function Directly_Specified + (Id : Entity_Id; A : Aspect_Id) return Boolean; + -- Returns True if the given aspect is directly (as opposed to + -- via any form of inheritance) specified for the given entity. + function Make_Aitem_Pragma (Pragma_Argument_Associations : List_Id; Pragma_Name : Name_Id) return Node_Id; @@ -2769,6 +2782,18 @@ package body Sem_Ch13 is end if; end Check_Expr_Is_OK_Static_Expression; + ------------------------ + -- Directly_Specified -- + ------------------------ + + function Directly_Specified + (Id : Entity_Id; A : Aspect_Id) return Boolean + is + Aspect_Spec : constant Node_Id := Find_Aspect (Id, A); + begin + return Present (Aspect_Spec) and then Entity (Aspect_Spec) = Id; + end Directly_Specified; + ----------------------- -- Make_Aitem_Pragma -- ----------------------- @@ -2915,6 +2940,7 @@ package body Sem_Ch13 is | Aspect_Async_Writers | Aspect_Effective_Reads | Aspect_Effective_Writes + | Aspect_Preelaborable_Initialization then Error_Msg_Name_1 := Nam; @@ -2951,6 +2977,7 @@ package body Sem_Ch13 is | Aspect_Async_Writers | Aspect_Effective_Reads | Aspect_Effective_Writes + | Aspect_Preelaborable_Initialization then Error_Msg_N ("aspect % not allowed for formal type declaration", @@ -3332,6 +3359,15 @@ package body Sem_Ch13 is ("Predicate_Failure requires previous predicate" & " specification", Aspect); goto Continue; + + elsif not (Directly_Specified (E, Aspect_Dynamic_Predicate) + or else Directly_Specified (E, Aspect_Static_Predicate) + or else Directly_Specified (E, Aspect_Predicate)) + then + Error_Msg_N + ("Predicate_Failure requires accompanying" & + " noninherited predicate specification", Aspect); + goto Continue; end if; -- Construct the pragma @@ -6621,7 +6657,7 @@ package body Sem_Ch13 is elsif Duplicate_Clause then null; - elsif Align /= No_Uint then + elsif Present (Align) then Set_Has_Alignment_Clause (U_Ent); -- Tagged type case, check for attempt to set alignment to a @@ -6711,7 +6747,7 @@ package body Sem_Ch13 is elsif Rep_Item_Too_Early (Btype, N) then null; - elsif Csize /= No_Uint then + elsif Present (Csize) then Check_Size (Expr, Ctyp, Csize, Biased); -- For the biased case, build a declaration for a subtype that @@ -6736,9 +6772,9 @@ package body Sem_Ch13 is Analyze (Decl, Suppress => All_Checks); Set_Has_Delayed_Freeze (New_Ctyp, False); - Init_Esize (New_Ctyp); + Reinit_Esize (New_Ctyp); Set_RM_Size (New_Ctyp, Csize); - Init_Alignment (New_Ctyp); + Reinit_Alignment (New_Ctyp); Set_Is_Itype (New_Ctyp, True); Set_Associated_Node_For_Itype (New_Ctyp, U_Ent); @@ -7051,7 +7087,7 @@ package body Sem_Ch13 is elsif Duplicate_Clause then null; - elsif Radix /= No_Uint then + elsif Present (Radix) then Set_Has_Machine_Radix_Clause (U_Ent); Set_Has_Non_Standard_Rep (Base_Type (U_Ent)); @@ -7264,7 +7300,7 @@ package body Sem_Ch13 is Error_Msg_N (Attr_Name & " cannot be given for unconstrained array", Nam); - elsif Size /= No_Uint then + elsif Present (Size) then declare Etyp : constant Entity_Id := (if Is_Type (U_Ent) then U_Ent else Etype (U_Ent)); @@ -7312,13 +7348,14 @@ package body Sem_Ch13 is if Is_First_Subtype (U_Ent) then if Is_Elementary_Type (U_Ent) then if Size <= System_Storage_Unit then - Init_Esize (U_Ent, System_Storage_Unit); + Set_Esize + (U_Ent, UI_From_Int (System_Storage_Unit)); elsif Size <= 16 then - Init_Esize (U_Ent, 16); + Set_Esize (U_Ent, Uint_16); elsif Size <= 32 then - Init_Esize (U_Ent, 32); + Set_Esize (U_Ent, Uint_32); else - Set_Esize (U_Ent, (Size + 63) / 64 * 64); + Set_Esize (U_Ent, (Size + 63) / 64 * 64); end if; Alignment_Check_For_Size_Change @@ -7788,11 +7825,16 @@ package body Sem_Ch13 is null; elsif Is_Elementary_Type (U_Ent) then - if Size /= System_Storage_Unit - and then Size /= System_Storage_Unit * 2 - and then Size /= System_Storage_Unit * 3 - and then Size /= System_Storage_Unit * 4 - and then Size /= System_Storage_Unit * 8 + -- Size will be empty if we already detected an error + -- (e.g. Expr is of the wrong type); we might as well + -- give the useful hint below even in that case. + + if No (Size) or else + (Size /= System_Storage_Unit + and then Size /= System_Storage_Unit * 2 + and then Size /= System_Storage_Unit * 3 + and then Size /= System_Storage_Unit * 4 + and then Size /= System_Storage_Unit * 8) then Error_Msg_N ("stream size for elementary type must be 8, 16, 24, " & @@ -8095,7 +8137,7 @@ package body Sem_Ch13 is -- the list. The final checks for completeness and ordering are -- skipped in this case. - if Val = No_Uint then + if No (Val) then Err := True; elsif Val < Lo or else Hi < Val then @@ -8174,7 +8216,7 @@ package body Sem_Ch13 is Expr := Expression (Assoc); Val := Static_Integer (Expr); - if Val = No_Uint then + if No (Val) then Err := True; elsif Val < Lo or else Hi < Val then @@ -8209,12 +8251,12 @@ package body Sem_Ch13 is else Val := Enumeration_Rep (Elit); - if Min = No_Uint then + if No (Min) then Min := Val; end if; - if Val /= No_Uint then - if Max /= No_Uint and then Val <= Max then + if Present (Val) then + if Present (Max) and then Val <= Max then Error_Msg_NE ("enumeration value for& not ordered!", Enumeration_Rep_Expr (Elit), Elit); @@ -8499,9 +8541,9 @@ package body Sem_Ch13 is Fbit := Static_Integer (First_Bit (CC)); Lbit := Static_Integer (Last_Bit (CC)); - if Posit /= No_Uint - and then Fbit /= No_Uint - and then Lbit /= No_Uint + if Present (Posit) + and then Present (Fbit) + and then Present (Lbit) then if Posit < 0 then Error_Msg_N ("position cannot be negative", Position (CC)); @@ -8642,9 +8684,6 @@ package body Sem_Ch13 is Set_Normalized_First_Bit (Comp, Fbit mod SSU); Set_Normalized_Position (Comp, Fbit / SSU); - Set_Normalized_Position_Max - (Comp, Normalized_Position (Comp)); - if Warn_On_Overridden_Size and then Has_Size_Clause (Etype (Comp)) and then RM_Size (Etype (Comp)) /= Esize (Comp) @@ -8676,9 +8715,6 @@ package body Sem_Ch13 is Set_Normalized_First_Bit (Ocomp, Fbit mod SSU); Set_Normalized_Position (Ocomp, Fbit / SSU); - Set_Normalized_Position_Max - (Ocomp, Normalized_Position (Ocomp)); - -- Note: we don't use Set_Biased here, because we -- already gave a warning above if needed, and we -- would get a duplicate for the same name here. @@ -11872,9 +11908,23 @@ package body Sem_Ch13 is -------- function Lt (Op1, Op2 : Natural) return Boolean is + K1 : constant Boolean := + Known_Component_Bit_Offset (Comps (Op1)); + K2 : constant Boolean := + Known_Component_Bit_Offset (Comps (Op2)); + -- Record representation clauses can be incomplete, so the + -- Component_Bit_Offsets can be unknown. begin - return Component_Bit_Offset (Comps (Op1)) - < Component_Bit_Offset (Comps (Op2)); + if K1 then + if K2 then + return Component_Bit_Offset (Comps (Op1)) + < Component_Bit_Offset (Comps (Op2)); + else + return True; + end if; + else + return K2; + end if; end Lt; ---------- @@ -11938,7 +11988,7 @@ package body Sem_Ch13 is begin -- Skip components with unknown offsets - if CBO /= No_Uint and then CBO >= 0 then + if Present (CBO) and then CBO >= 0 then Error_Msg_Uint_1 := CBO - Nbit; if Warn and then Error_Msg_Uint_1 > 0 then @@ -12053,7 +12103,7 @@ package body Sem_Ch13 is Pcomp := First_Entity (Tagged_Parent); while Present (Pcomp) loop if Ekind (Pcomp) in E_Discriminant | E_Component then - if Component_Bit_Offset (Pcomp) /= No_Uint + if Present (Component_Bit_Offset (Pcomp)) and then Known_Static_Esize (Pcomp) then Parent_Last_Bit := @@ -12094,8 +12144,7 @@ package body Sem_Ch13 is Set_Component_Bit_Offset (Fent, Uint_0); Set_Normalized_Position (Fent, Uint_0); Set_Normalized_First_Bit (Fent, Uint_0); - Set_Normalized_Position_Max (Fent, Uint_0); - Init_Esize (Fent, System_Address_Size); + Set_Esize (Fent, UI_From_Int (System_Address_Size)); Set_Component_Clause (Fent, Make_Component_Clause (Loc, @@ -13123,7 +13172,7 @@ package body Sem_Ch13 is Align : constant Uint := Static_Integer (Expr); begin - if Align = No_Uint then + if No (Align) then return No_Uint; elsif Align < 0 then @@ -13700,6 +13749,7 @@ package body Sem_Ch13 is | Attribute_Iterable | Attribute_Iterator_Element | Attribute_Output + | Attribute_Put_Image | Attribute_Read | Attribute_Variable_Indexing | Attribute_Write; @@ -13979,7 +14029,7 @@ package body Sem_Ch13 is function Minimum_Size (T : Entity_Id; - Biased : Boolean := False) return Nat + Biased : Boolean := False) return Int is Lo : Uint := No_Uint; Hi : Uint := No_Uint; @@ -13993,17 +14043,17 @@ package body Sem_Ch13 is R_Typ : constant Entity_Id := Root_Type (T); begin - -- If bad type, return 0 + -- Bad type if T = Any_Type then - return 0; + return Unknown_Minimum_Size; - -- For generic types, just return zero. There cannot be any legitimate - -- need to know such a size, but this routine may be called with a - -- generic type as part of normal processing. + -- For generic types, just return unknown. There cannot be any + -- legitimate need to know such a size, but this routine may be + -- called with a generic type as part of normal processing. elsif Is_Generic_Type (R_Typ) or else R_Typ = Any_Type then - return 0; + return Unknown_Minimum_Size; -- Access types (cannot have size smaller than System.Address) @@ -14026,7 +14076,7 @@ package body Sem_Ch13 is Ancest := T; loop if Ancest = Any_Type or else Etype (Ancest) = Any_Type then - return 0; + return Unknown_Minimum_Size; end if; if not LoSet then @@ -14051,7 +14101,7 @@ package body Sem_Ch13 is Ancest := Base_Type (T); if Is_Generic_Type (Ancest) then - return 0; + return Unknown_Minimum_Size; end if; end if; end loop; @@ -14072,7 +14122,7 @@ package body Sem_Ch13 is Ancest := T; loop if Ancest = Any_Type or else Etype (Ancest) = Any_Type then - return 0; + return Unknown_Minimum_Size; end if; -- Note: In the following two tests for LoSet and HiSet, it may @@ -14112,7 +14162,7 @@ package body Sem_Ch13 is Ancest := Base_Type (T); if Is_Generic_Type (Ancest) then - return 0; + return Unknown_Minimum_Size; end if; end if; end loop; @@ -14142,7 +14192,7 @@ package body Sem_Ch13 is -- type case, since that's the odd case that came up. Probably we should -- also do this in the fixed-point case, but doing so causes peculiar -- gigi failures, and it is not worth worrying about this incredibly - -- marginal case (explicit null-range fixed-point type declarations)??? + -- marginal case (explicit null-range fixed-point type declarations). if Lo > Hi and then Is_Discrete_Type (T) then S := 0; @@ -15681,18 +15731,17 @@ package body Sem_Ch13 is ------------------------------ procedure Resolve_Aspect_Aggregate - (Typ : Entity_Id; + (Typ : Entity_Id; Expr : Node_Id) is + function Valid_Empty (E : Entity_Id) return Boolean; + function Valid_Add_Named (E : Entity_Id) return Boolean; + function Valid_Add_Unnamed (E : Entity_Id) return Boolean; + function Valid_New_Indexed (E : Entity_Id) return Boolean; + function Valid_Assign_Indexed (E : Entity_Id) return Boolean; -- Predicates that establish the legality of each possible operation in -- an Aggregate aspect. - function Valid_Empty (E : Entity_Id) return Boolean; - function Valid_Add_Named (E : Entity_Id) return Boolean; - function Valid_Add_Unnamed (E : Entity_Id) return Boolean; - function Valid_New_Indexed (E : Entity_Id) return Boolean; - function Valid_Assign_Indexed (E : Entity_Id) return Boolean; - generic with function Pred (Id : Node_Id) return Boolean; procedure Resolve_Operation (Subp_Id : Node_Id); @@ -15715,7 +15764,7 @@ package body Sem_Ch13 is end Valid_Assign_Indexed; ----------------- - -- Valid_Emoty -- + -- Valid_Empty -- ----------------- function Valid_Empty (E : Entity_Id) return Boolean is @@ -15740,7 +15789,7 @@ package body Sem_Ch13 is -- Valid_Add_Named -- --------------------- - function Valid_Add_Named (E : Entity_Id) return Boolean is + function Valid_Add_Named (E : Entity_Id) return Boolean is F2, F3 : Entity_Id; begin if Ekind (E) = E_Procedure @@ -15839,6 +15888,9 @@ package body Sem_Ch13 is procedure Resolve_Assign_Indexed is new Resolve_Operation (Valid_Assign_Indexed); + + -- Start of processing for Resolve_Aspect_Aggregate + begin Assoc := First (Component_Associations (Expr)); @@ -16120,10 +16172,10 @@ package body Sem_Ch13 is procedure Set_Enum_Esize (T : Entity_Id) is Lo : Uint; Hi : Uint; - Sz : Nat; + Sz : Unat; begin - Init_Alignment (T); + Reinit_Alignment (T); -- Find the minimum standard size (8,16,32,64,128) that fits @@ -16131,37 +16183,38 @@ package body Sem_Ch13 is Hi := Enumeration_Rep (Entity (Type_High_Bound (T))); if Lo < 0 then - if Lo >= -Uint_2**07 and then Hi < Uint_2**07 then - Sz := Standard_Character_Size; -- May be > 8 on some targets + if Lo >= -Uint_2**7 and then Hi < Uint_2**7 then + Sz := UI_From_Int (Standard_Character_Size); + -- Might be > 8 on some targets elsif Lo >= -Uint_2**15 and then Hi < Uint_2**15 then - Sz := 16; + Sz := Uint_16; elsif Lo >= -Uint_2**31 and then Hi < Uint_2**31 then - Sz := 32; + Sz := Uint_32; elsif Lo >= -Uint_2**63 and then Hi < Uint_2**63 then - Sz := 64; + Sz := Uint_64; else pragma Assert (Lo >= -Uint_2**127 and then Hi < Uint_2**127); - Sz := 128; + Sz := Uint_128; end if; else - if Hi < Uint_2**08 then - Sz := Standard_Character_Size; -- May be > 8 on some targets + if Hi < Uint_2**8 then + Sz := UI_From_Int (Standard_Character_Size); elsif Hi < Uint_2**16 then - Sz := 16; + Sz := Uint_16; elsif Hi < Uint_2**32 then - Sz := 32; + Sz := Uint_32; elsif Hi < Uint_2**64 then - Sz := 64; + Sz := Uint_64; else pragma Assert (Hi < Uint_2**128); - Sz := 128; + Sz := Uint_128; end if; end if; @@ -16177,9 +16230,9 @@ package body Sem_Ch13 is and then not Target_Short_Enums then - Init_Esize (T, Standard_Integer_Size); + Set_Esize (T, UI_From_Int (Standard_Integer_Size)); else - Init_Esize (T, Sz); + Set_Esize (T, Sz); end if; end Set_Enum_Esize; @@ -16262,7 +16315,7 @@ package body Sem_Ch13 is elsif Nkind (N) = N_Selected_Component then Off := Component_Bit_Offset (Entity (Selector_Name (N))); - if Off /= No_Uint and then Off >= Uint_0 then + if Present (Off) and then Off >= Uint_0 then Val := Val + Off; N := Prefix (N); else @@ -16271,7 +16324,7 @@ package body Sem_Ch13 is elsif Nkind (N) = N_Indexed_Component then Off := Indexed_Component_Bit_Offset (N); - if Off /= No_Uint then + if Present (Off) then Val := Val + Off; N := Prefix (N); else @@ -16319,7 +16372,8 @@ package body Sem_Ch13 is if Present (ACCR.Y) then Y_Alignment := Alignment (ACCR.Y); - Y_Size := Esize (ACCR.Y); + Y_Size := + (if Known_Esize (ACCR.Y) then Esize (ACCR.Y) else Uint_0); end if; if ACCR.Off diff --git a/gcc/ada/sem_ch13.ads b/gcc/ada/sem_ch13.ads index 3b21484..0d3b041 100644 --- a/gcc/ada/sem_ch13.ads +++ b/gcc/ada/sem_ch13.ads @@ -81,9 +81,11 @@ package Sem_Ch13 is -- the setting of the RM_Size field is not affected. This routine also -- initializes the alignment field to zero. + Unknown_Minimum_Size : constant Nonzero_Int := -1; + function Minimum_Size (T : Entity_Id; - Biased : Boolean := False) return Nat; + Biased : Boolean := False) return Int; -- Given an elementary type, determines the minimum number of bits required -- to represent all values of the type. This function may not be called -- with any other types. If the flag Biased is set True, then the minimum @@ -96,7 +98,7 @@ package Sem_Ch13 is -- the type is already biased, then Minimum_Size returns the biased size, -- regardless of the setting of Biased. Also, fixed-point types are never -- biased in the current implementation. If the size is not known at - -- compile time, this function returns 0. + -- compile time, this function returns Unknown_Minimum_Size. procedure Check_Constant_Address_Clause (Expr : Node_Id; U_Ent : Entity_Id); -- Expr is an expression for an address clause. This procedure checks diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index e9b4456..cc8a9b7 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -1299,7 +1299,7 @@ package body Sem_Ch3 is Set_Can_Use_Internal_Rep (T_Name, not Always_Compatible_Rep_On_Target); Set_Etype (T_Name, T_Name); - Init_Size_Align (T_Name); + Reinit_Size_Align (T_Name); Set_Directly_Designated_Type (T_Name, Desig_Type); -- If the access_to_subprogram is not declared at the library level, @@ -1465,7 +1465,7 @@ package body Sem_Ch3 is -- and the pointer size is already set. Else, initialize. if not From_Limited_With (T) then - Init_Size_Align (T); + Reinit_Size_Align (T); end if; -- Note that Has_Task is always false, since the access type itself @@ -1551,7 +1551,7 @@ package body Sem_Ch3 is Set_Is_Aliased (Tag); Set_Is_Independent (Tag); Set_Related_Type (Tag, Iface); - Init_Component_Location (Tag); + Reinit_Component_Location (Tag); pragma Assert (Is_Frozen (Iface)); @@ -1591,7 +1591,7 @@ package body Sem_Ch3 is Set_Is_Aliased (Offset); Set_Is_Independent (Offset); Set_Related_Type (Offset, Iface); - Init_Component_Location (Offset); + Reinit_Component_Location (Offset); Insert_After (Last_Tag, Decl); Last_Tag := Decl; end if; @@ -2648,6 +2648,48 @@ package body Sem_Ch3 is E := First_Entity (Current_Scope); while Present (E) loop Resolve_Aspect_Expressions (E); + + -- Now that the aspect expressions have been resolved, if this is + -- at the end of the visible declarations, we can set the flag + -- Known_To_Have_Preelab_Init properly on types declared in the + -- visible part, which is needed for checking whether full types + -- in the private part satisfy the Preelaborable_Initialization + -- aspect of the partial view. We can't wait for the creation of + -- the pragma by Analyze_Aspects_At_Freeze_Point, because the + -- freeze point may occur after the end of the package declaration + -- (in the case of nested packages). + + if Is_Type (E) + and then L = Visible_Declarations (Parent (L)) + and then Has_Aspect (E, Aspect_Preelaborable_Initialization) + then + declare + ASN : constant Node_Id := + Find_Aspect (E, Aspect_Preelaborable_Initialization); + Expr : constant Node_Id := Expression (ASN); + begin + -- Set Known_To_Have_Preelab_Init to True if aspect has no + -- expression, or if the expression is True (or was folded + -- to True), or if the expression is a conjunction of one or + -- more Preelaborable_Initialization attributes applied to + -- formal types and wasn't folded to False. (Note that + -- Is_Conjunction_Of_Formal_Preelab_Init_Attributes goes to + -- Original_Node if needed, hence test for Standard_False.) + + if not Present (Expr) + or else (Is_Entity_Name (Expr) + and then Entity (Expr) = Standard_True) + or else + (Is_Conjunction_Of_Formal_Preelab_Init_Attributes (Expr) + and then + not (Is_Entity_Name (Expr) + and then Entity (Expr) = Standard_False)) + then + Set_Known_To_Have_Preelab_Init (E); + end if; + end; + end if; + Next_Entity (E); end loop; end Resolve_Aspects; @@ -3450,7 +3492,7 @@ package body Sem_Ch3 is Mutate_Ekind (T, E_Incomplete_Type); Set_Etype (T, T); Set_Is_First_Subtype (T); - Init_Size_Align (T); + Reinit_Size_Align (T); -- Set the SPARK mode from the current context @@ -4849,8 +4891,8 @@ package body Sem_Ch3 is -- Initialize alignment and size and capture alignment setting - Init_Alignment (Id); - Init_Esize (Id); + Reinit_Alignment (Id); + Reinit_Esize (Id); Set_Optimize_Alignment_Flags (Id); -- Deal with aliased case @@ -5183,7 +5225,7 @@ package body Sem_Ch3 is Set_Is_Pure (T, Is_Pure (Current_Scope)); Set_Scope (T, Current_Scope); Mutate_Ekind (T, E_Record_Type_With_Private); - Init_Size_Align (T); + Reinit_Size_Align (T); Set_Default_SSO (T); Set_No_Reordering (T, No_Component_Reordering); @@ -5348,7 +5390,7 @@ package body Sem_Ch3 is begin Generate_Definition (Id); Set_Is_Pure (Id, Is_Pure (Current_Scope)); - Init_Size_Align (Id); + Reinit_Size_Align (Id); -- The following guard condition on Enter_Name is to handle cases where -- the defining identifier has already been entered into the scope but @@ -5466,7 +5508,7 @@ package body Sem_Ch3 is Set_Machine_Radix_10 (Id, Machine_Radix_10 (T)); Set_Is_Constrained (Id, Is_Constrained (T)); Set_Is_Known_Valid (Id, Is_Known_Valid (T)); - Set_RM_Size (Id, RM_Size (T)); + Copy_RM_Size (To => Id, From => T); when Enumeration_Kind => Mutate_Ekind (Id, E_Enumeration_Subtype); @@ -5475,7 +5517,7 @@ package body Sem_Ch3 is Set_Is_Character_Type (Id, Is_Character_Type (T)); Set_Is_Constrained (Id, Is_Constrained (T)); Set_Is_Known_Valid (Id, Is_Known_Valid (T)); - Set_RM_Size (Id, RM_Size (T)); + Copy_RM_Size (To => Id, From => T); when Ordinary_Fixed_Point_Kind => Mutate_Ekind (Id, E_Ordinary_Fixed_Point_Subtype); @@ -5484,7 +5526,7 @@ package body Sem_Ch3 is Set_Delta_Value (Id, Delta_Value (T)); Set_Is_Constrained (Id, Is_Constrained (T)); Set_Is_Known_Valid (Id, Is_Known_Valid (T)); - Set_RM_Size (Id, RM_Size (T)); + Copy_RM_Size (To => Id, From => T); when Float_Kind => Mutate_Ekind (Id, E_Floating_Point_Subtype); @@ -5500,14 +5542,14 @@ package body Sem_Ch3 is Set_Scalar_Range (Id, Scalar_Range (T)); Set_Is_Constrained (Id, Is_Constrained (T)); Set_Is_Known_Valid (Id, Is_Known_Valid (T)); - Set_RM_Size (Id, RM_Size (T)); + Copy_RM_Size (To => Id, From => T); when Modular_Integer_Kind => Mutate_Ekind (Id, E_Modular_Integer_Subtype); Set_Scalar_Range (Id, Scalar_Range (T)); Set_Is_Constrained (Id, Is_Constrained (T)); Set_Is_Known_Valid (Id, Is_Known_Valid (T)); - Set_RM_Size (Id, RM_Size (T)); + Copy_RM_Size (To => Id, From => T); when Class_Wide_Kind => Mutate_Ekind (Id, E_Class_Wide_Subtype); @@ -5534,7 +5576,7 @@ package body Sem_Ch3 is -- the type they rename. if Present (Generic_Parent_Type (N)) then - Set_RM_Size (Id, RM_Size (T)); + Copy_RM_Size (To => Id, From => T); end if; if Ekind (T) = E_Record_Subtype @@ -6290,7 +6332,7 @@ package body Sem_Ch3 is -- The constrained array type is a subtype of the unconstrained one Mutate_Ekind (T, E_Array_Subtype); - Init_Size_Align (T); + Reinit_Size_Align (T); Set_Etype (T, Implicit_Base); Set_Scope (T, Current_Scope); Set_Is_Constrained (T); @@ -6326,7 +6368,7 @@ package body Sem_Ch3 is end if; Mutate_Ekind (T, E_Array_Type); - Init_Size_Align (T); + Reinit_Size_Align (T); Set_Etype (T, T); Set_Scope (T, Current_Scope); Set_Component_Size (T, Uint_0); @@ -6813,8 +6855,8 @@ package body Sem_Ch3 is Set_Is_Constrained (Derived_Type, Is_Constrained (Subt)); Set_Is_Access_Constant (Derived_Type, Is_Access_Constant (Parent_Type)); - Set_Size_Info (Derived_Type, Parent_Type); - Set_RM_Size (Derived_Type, RM_Size (Parent_Type)); + Set_Size_Info (Derived_Type, Parent_Type); + Copy_RM_Size (To => Derived_Type, From => Parent_Type); Set_Depends_On_Private (Derived_Type, Has_Private_Component (Derived_Type)); Conditional_Delay (Derived_Type, Subt); @@ -8945,7 +8987,7 @@ package body Sem_Ch3 is if Is_Tagged then Set_Is_Tagged_Type (Derived_Type); - Init_Size_Align (Derived_Type); + Reinit_Size_Align (Derived_Type); end if; -- STEP 0a: figure out what kind of derived type declaration we have @@ -9854,8 +9896,8 @@ package body Sem_Ch3 is Mutate_Ekind (Derived_Type, Ekind (Parent_Base)); Propagate_Concurrent_Flags (Derived_Type, Parent_Base); - Set_Size_Info (Derived_Type, Parent_Type); - Set_RM_Size (Derived_Type, RM_Size (Parent_Type)); + Set_Size_Info (Derived_Type, Parent_Type); + Copy_RM_Size (To => Derived_Type, From => Parent_Type); Set_Is_Controlled_Active (Derived_Type, Is_Controlled_Active (Parent_Type)); @@ -10392,6 +10434,7 @@ package body Sem_Ch3 is (Discr_Expr (J), Check_Concurrent => True) then Discrim_Present := True; + exit; end if; end loop; @@ -10449,7 +10492,43 @@ package body Sem_Ch3 is Apply_Range_Check (Discr_Expr (J), Etype (Discr)); end if; - Force_Evaluation (Discr_Expr (J)); + -- If the value of the discriminant may be visible in + -- another unit or child unit, create an external name + -- for it. We use the name of the object or component + -- that carries the discriminated subtype. The code + -- below may generate external symbols for the discriminant + -- expression when not strictly needed, which is harmless. + + if Expander_Active + and then Comes_From_Source (Def) + and then not Is_Subprogram (Current_Scope) + then + declare + Id : Entity_Id := Empty; + begin + if Nkind (Parent (Def)) = N_Object_Declaration then + Id := Defining_Identifier (Parent (Def)); + + elsif Nkind (Parent (Def)) = N_Component_Definition + and then + Nkind (Parent (Parent (Def))) + = N_Component_Declaration + then + Id := Defining_Identifier (Parent (Parent (Def))); + end if; + + if Present (Id) then + Force_Evaluation ( + Discr_Expr (J), + Related_Id => Id, + Discr_Number => J); + else + Force_Evaluation (Discr_Expr (J)); + end if; + end; + else + Force_Evaluation (Discr_Expr (J)); + end if; end if; -- Check that the designated type of an access discriminant's @@ -10554,7 +10633,7 @@ package body Sem_Ch3 is end if; Set_Etype (Def_Id, T); - Init_Size_Align (Def_Id); + Reinit_Size_Align (Def_Id); Set_Has_Discriminants (Def_Id, Has_Discrs); Set_Is_Constrained (Def_Id, Constrained); @@ -12689,7 +12768,7 @@ package body Sem_Ch3 is Set_Is_First_Subtype (Full, False); Set_Scope (Full, Scope (Priv)); Set_Size_Info (Full, Full_Base); - Set_RM_Size (Full, RM_Size (Full_Base)); + Copy_RM_Size (To => Full, From => Full_Base); Set_Is_Itype (Full); -- A subtype of a private-type-without-discriminants, whose full-view @@ -14516,7 +14595,7 @@ package body Sem_Ch3 is end if; Set_Size_Info (Def_Id, (T)); - Set_RM_Size (Def_Id, RM_Size (T)); + Copy_RM_Size (To => Def_Id, From => T); Set_First_Rep_Item (Def_Id, First_Rep_Item (T)); -- If this is a range for a fixed-lower-bound subtype, then set the @@ -15320,12 +15399,12 @@ package body Sem_Ch3 is Set_Fixed_Range (Implicit_Base, Loc, -Bound_Val, Bound_Val); - -- Note: We leave size as zero for now, size will be set at freeze + -- Note: We leave Esize unset for now, size will be set at freeze -- time. We have to do this for ordinary fixed-point, because the size -- depends on the specified small, and we might as well do the same for -- decimal fixed-point. - pragma Assert (Esize (Implicit_Base) = Uint_0); + pragma Assert (not Known_Esize (Implicit_Base)); -- If there are bounds given in the declaration use them as the -- bounds of the first named subtype. @@ -15676,7 +15755,7 @@ package body Sem_Ch3 is -- Set remaining characterstics of anonymous access type - Init_Alignment (Acc_Type); + Reinit_Alignment (Acc_Type); Set_Directly_Designated_Type (Acc_Type, Derived_Type); Set_Etype (New_Id, Acc_Type); @@ -19750,10 +19829,10 @@ package body Sem_Ch3 is Siz := Siz * 2; end loop; - Init_Esize (T, Siz); + Set_Esize (T, UI_From_Int (Siz)); else - Init_Esize (T, System_Max_Binary_Modulus_Power); + Set_Esize (T, UI_From_Int (System_Max_Binary_Modulus_Power)); end if; if not Non_Binary_Modulus (T) and then Esize (T) = RM_Size (T) then @@ -19788,7 +19867,7 @@ package body Sem_Ch3 is Set_Etype (T, T); Mutate_Ekind (T, E_Modular_Integer_Type); - Init_Alignment (T); + Reinit_Alignment (T); Set_Is_Constrained (T); if not Is_OK_Static_Expression (Mod_Expr) then @@ -19867,7 +19946,7 @@ package body Sem_Ch3 is Error_Msg_F ("modulus exceeds limit (2 '*'*^)", Mod_Expr); Set_Modular_Size (System_Max_Binary_Modulus_Power); - Init_Alignment (T); + Reinit_Alignment (T); end Modular_Type_Declaration; @@ -20189,7 +20268,7 @@ package body Sem_Ch3 is Mutate_Ekind (T, E_Ordinary_Fixed_Point_Subtype); Set_Etype (T, Implicit_Base); - Init_Size_Align (T); + Reinit_Size_Align (T); Inherit_Rep_Item_Chain (T, Implicit_Base); Set_Small_Value (T, Small_Val); Set_Delta_Value (T, Delta_Val); @@ -20591,8 +20670,8 @@ package body Sem_Ch3 is end if; Mutate_Ekind (Id, E_Discriminant); - Init_Component_Location (Id); - Init_Esize (Id); + Reinit_Component_Location (Id); + Reinit_Esize (Id); Set_Discriminant_Number (Id, Discr_Number); -- Make sure this is always set, even in illegal programs @@ -22260,7 +22339,7 @@ package body Sem_Ch3 is Mutate_Ekind (T, E_Record_Type); Set_Etype (T, T); - Init_Size_Align (T); + Reinit_Size_Align (T); Set_Interfaces (T, No_Elist); Set_Stored_Constraint (T, No_Elist); Set_Default_SSO (T); @@ -22369,7 +22448,7 @@ package body Sem_Ch3 is Set_Etype (Tag_Comp, RTE (RE_Tag)); Set_DT_Entry_Count (Tag_Comp, No_Uint); Set_Original_Record_Component (Tag_Comp, Tag_Comp); - Init_Component_Location (Tag_Comp); + Reinit_Component_Location (Tag_Comp); -- Ada 2005 (AI-251): Addition of the Tag corresponding to all the -- implemented interfaces. @@ -22473,7 +22552,7 @@ package body Sem_Ch3 is and then not Is_Itype (Component) then Mutate_Ekind (Component, E_Component); - Init_Component_Location (Component); + Reinit_Component_Location (Component); end if; Propagate_Concurrent_Flags (T, Etype (Component)); diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb index c052022..543ba12 100644 --- a/gcc/ada/sem_ch4.adb +++ b/gcc/ada/sem_ch4.adb @@ -6626,7 +6626,7 @@ package body Sem_Ch4 is Get_Next_Interp (Index, It); end loop; end if; - else + elsif Has_Compatible_Type (R, T1) or else Covers (Etype (R), T1) then Add_One_Interp (N, Op_Id, Standard_Boolean, Base_Type (T1)); end if; end Find_Non_Universal_Interpretations; @@ -8029,6 +8029,7 @@ package body Sem_Ch4 is while Present (It.Nam) loop if Is_Numeric_Type (It.Typ) and then Scope (It.Typ) = Standard_Standard + and then Ekind (It.Nam) = E_Operator then Set_Abstract_Op (I, Abstract_Op); end if; diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb index f30a9aa..095bcda 100644 --- a/gcc/ada/sem_ch7.adb +++ b/gcc/ada/sem_ch7.adb @@ -1768,11 +1768,16 @@ package body Sem_Ch7 is end if; -- Check preelaborable initialization for full type completing a - -- private type for which pragma Preelaborable_Initialization given. + -- private type when aspect Preelaborable_Initialization is True. + -- We pass True for the parameter Formal_Types_Have_Preelab_Init + -- to take into account the rule that presumes that subcomponents + -- of generic formal types mentioned in the type's P_I aspect have + -- preelaborable initialization (see RM 10.2.1(11.8/5)). if Is_Type (E) and then Must_Have_Preelab_Init (E) - and then not Has_Preelaborable_Initialization (E) + and then not Has_Preelaborable_Initialization + (E, Formal_Types_Have_Preelab_Init => True) then Error_Msg_N ("full view of & does not have preelaborable initialization", E); @@ -1891,7 +1896,7 @@ package body Sem_Ch7 is begin Generate_Definition (Id); Set_Is_Pure (Id, PF); - Init_Size_Align (Id); + Reinit_Size_Align (Id); if not Is_Package_Or_Generic_Package (Current_Scope) or else In_Private_Part (Current_Scope) @@ -2568,7 +2573,7 @@ package body Sem_Ch7 is Set_Etype (Id, Id); Set_Has_Delayed_Freeze (Id); Set_Is_First_Subtype (Id); - Init_Size_Align (Id); + Reinit_Size_Align (Id); Set_Is_Constrained (Id, No (Discriminant_Specifications (N)) @@ -2728,7 +2733,7 @@ package body Sem_Ch7 is begin Set_Size_Info (Priv, Full); - Set_RM_Size (Priv, RM_Size (Full)); + Copy_RM_Size (To => Priv, From => Full); Set_Size_Known_At_Compile_Time (Priv, Size_Known_At_Compile_Time (Full)); Set_Is_Volatile (Priv, Is_Volatile (Full)); diff --git a/gcc/ada/sem_ch8.adb b/gcc/ada/sem_ch8.adb index 78d2426..a9f0f13 100644 --- a/gcc/ada/sem_ch8.adb +++ b/gcc/ada/sem_ch8.adb @@ -1461,7 +1461,7 @@ package body Sem_Ch8 is Mutate_Ekind (Id, E_Variable); end if; - Init_Object_Size_Align (Id); + Reinit_Object_Size_Align (Id); -- If N comes from source then check that the original node is an -- object reference since there may have been several rewritting and diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb index ab25dd0..5293efb 100644 --- a/gcc/ada/sem_ch9.adb +++ b/gcc/ada/sem_ch9.adb @@ -2024,7 +2024,7 @@ package body Sem_Ch9 is Mutate_Ekind (T, E_Protected_Type); Set_Is_First_Subtype (T); - Init_Size_Align (T); + Reinit_Size_Align (T); Set_Etype (T, T); Set_Has_Delayed_Freeze (T); Set_Stored_Constraint (T, No_Elist); @@ -2143,7 +2143,7 @@ package body Sem_Ch9 is while Present (E) loop if Ekind (E) = E_Void then Mutate_Ekind (E, E_Component); - Init_Component_Location (E); + Reinit_Component_Location (E); end if; Next_Entity (E); @@ -3151,7 +3151,7 @@ package body Sem_Ch9 is Mutate_Ekind (T, E_Task_Type); Set_Is_First_Subtype (T, True); Set_Has_Task (T, True); - Init_Size_Align (T); + Reinit_Size_Align (T); Set_Etype (T, T); Set_Has_Delayed_Freeze (T, True); Set_Stored_Constraint (T, No_Elist); diff --git a/gcc/ada/sem_dim.adb b/gcc/ada/sem_dim.adb index b303229..538da57 100644 --- a/gcc/ada/sem_dim.adb +++ b/gcc/ada/sem_dim.adb @@ -318,7 +318,7 @@ package body Sem_Dim is (N : Node_Id; Description_Needed : Boolean := False) return String; -- Given a node N, return the dimension symbols of N, preceded by "has - -- dimension" if Description_Needed. if N is dimensionless, return "'[']", + -- dimension" if Description_Needed. If N is dimensionless, return "'[']", -- or "is dimensionless" if Description_Needed. function Dimension_System_Root (T : Entity_Id) return Entity_Id; diff --git a/gcc/ada/sem_eval.adb b/gcc/ada/sem_eval.adb index a3a2864..6f81406 100644 --- a/gcc/ada/sem_eval.adb +++ b/gcc/ada/sem_eval.adb @@ -3069,7 +3069,7 @@ package body Sem_Eval is -- Note that in this case, both Right_Int and Left_Int are set -- to No_Uint, so need to test for both. - if Right_Int = No_Uint then + if No (Right_Int) then Fold_Uint (N, Uint_0, Stat); else Fold_Uint (N, @@ -3083,7 +3083,7 @@ package body Sem_Eval is -- Note that in this case, both Right_Int and Left_Int are set -- to No_Uint, so need to test for both. - if Right_Int = No_Uint then + if No (Right_Int) then Fold_Uint (N, Uint_1, Stat); else Fold_Uint (N, @@ -5063,12 +5063,20 @@ package body Sem_Eval is -- result is always positive, even if the original operand was -- negative. - Fold_Uint - (N, - (Expr_Value (Left) + - (if Expr_Value (Left) >= Uint_0 then Uint_0 else Modulus)) - / (Uint_2 ** Expr_Value (Right)), - Static => Static); + declare + M : Unat; + begin + if Expr_Value (Left) >= Uint_0 then + M := Uint_0; + else + M := Modulus; + end if; + + Fold_Uint + (N, + (Expr_Value (Left) + M) / (Uint_2 ** Expr_Value (Right)), + Static => Static); + end; end if; elsif Op = N_Op_Shift_Right_Arithmetic then Check_Elab_Call; @@ -5741,6 +5749,8 @@ package body Sem_Eval is elsif Has_Dynamic_Predicate_Aspect (Typ) or else (Is_Derived_Type (Typ) and then Has_Aspect (Typ, Aspect_Dynamic_Predicate)) + or else (Has_Aspect (Typ, Aspect_Predicate) + and then not Has_Static_Predicate (Typ)) then return False; diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 0ff4e49..9cad55d 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -7562,7 +7562,7 @@ package body Sem_Prag is end if; if not Has_Alignment_Clause (Ent) then - Init_Alignment (Ent); + Reinit_Alignment (Ent); end if; end Set_Atomic_VFA; @@ -13400,11 +13400,11 @@ package body Sem_Prag is Obj_Or_Type_Id := Defining_Entity (Obj_Or_Type_Decl); -- Perform minimal verification to ensure that the argument is at - -- least a variable or a type. Subsequent finer grained checks - -- will be done at the end of the declarative region that - -- contains the pragma. + -- least an object or a type. Subsequent finer grained checks will + -- be done at the end of the declarative region that contains the + -- pragma. - if Ekind (Obj_Or_Type_Id) = E_Variable + if Ekind (Obj_Or_Type_Id) in E_Constant | E_Variable or else Is_Type (Obj_Or_Type_Id) then diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb index 03d747e..12b3295 100644 --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -3454,7 +3454,6 @@ package body Sem_Res is procedure Resolve_Actuals (N : Node_Id; Nam : Entity_Id) is Loc : constant Source_Ptr := Sloc (N); A : Node_Id; - A_Id : Entity_Id; A_Typ : Entity_Id := Empty; -- init to avoid warning F : Entity_Id; F_Typ : Entity_Id; @@ -4969,31 +4968,6 @@ package body Sem_Res is -- must be resolved first. Flag_Effectively_Volatile_Objects (A); - - -- An effectively volatile variable cannot act as an actual - -- parameter in a procedure call when the variable has enabled - -- property Effective_Reads and the corresponding formal is of - -- mode IN (SPARK RM 7.1.3(10)). - - if Ekind (Nam) = E_Procedure - and then Ekind (F) = E_In_Parameter - and then Is_Entity_Name (A) - then - A_Id := Entity (A); - - if Ekind (A_Id) = E_Variable - and then Is_Effectively_Volatile_For_Reading (Etype (A_Id)) - and then Effective_Reads_Enabled (A_Id) - then - Error_Msg_NE - ("effectively volatile variable & cannot appear as " - & "actual in procedure call", A, A_Id); - - Error_Msg_Name_1 := Name_Effective_Reads; - Error_Msg_N ("\\variable has enabled property %", A); - Error_Msg_N ("\\corresponding formal has mode IN", A); - end if; - end if; end if; -- A formal parameter of a specific tagged type whose related diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index 01a4e2b..45a338a 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -728,17 +728,6 @@ package body Sem_Util is return Make_Level_Literal (Typ_Access_Level (Etype (E))); - -- When E is a component of the current instance of a - -- protected type, we assume the level to be deeper than that of - -- the type itself. - - elsif not Is_Overloadable (E) - and then Ekind (Scope (E)) = E_Protected_Type - and then Comes_From_Source (Scope (E)) - then - return Make_Level_Literal - (Scope_Depth (Enclosing_Dynamic_Scope (E)) + 1); - -- Check if E is an expansion-generated renaming of an iterator -- by examining Related_Expression. If so, determine the -- accessibility level based on the original expression. @@ -11802,7 +11791,7 @@ package body Sem_Util is -- Set to a factor of the offset from the base object when Expr is a -- selected or indexed component, based on Component_Bit_Offset and -- Component_Size respectively. A negative value is used to represent - -- a value which is not known at compile time. + -- a value that is not known at compile time. procedure Check_Prefix; -- Checks the prefix recursively in the case where the expression @@ -11901,7 +11890,7 @@ package body Sem_Util is Check_Prefix; Offs := Indexed_Component_Bit_Offset (Expr); - if Offs = No_Uint then + if No (Offs) then Offs := Component_Size (Typ); end if; end; @@ -11910,7 +11899,7 @@ package body Sem_Util is -- If we have a null offset, the result is entirely determined by -- the base object and has already been computed recursively. - if Offs = Uint_0 then + if Present (Offs) and then Offs = Uint_0 then null; -- Case where we know the alignment of the object @@ -11932,7 +11921,7 @@ package body Sem_Util is else -- If we have an offset, see if it is compatible - if Offs /= No_Uint and Offs > Uint_0 then + if Present (Offs) and then Offs > Uint_0 then if Offs mod (System_Storage_Unit * ObjA) /= 0 then Set_Result (Known_Incompatible); end if; @@ -11961,7 +11950,7 @@ package body Sem_Util is -- If we got an alignment, see if it is acceptable - if ExpA /= No_Uint and then ExpA < ObjA then + if Present (ExpA) and then ExpA < ObjA then Set_Result (Known_Incompatible); end if; @@ -11969,7 +11958,7 @@ package body Sem_Util is -- alignment, then we are fine. Otherwise, if its size is -- known, it must be big enough for the required alignment. - if Offs /= No_Uint then + if Present (Offs) then null; -- See if Expr is an object with known size @@ -11990,7 +11979,7 @@ package body Sem_Util is -- acceptable, since the size is always a multiple of the -- alignment. - if SizA /= No_Uint then + if Present (SizA) then if SizA mod (ObjA * Ttypes.System_Storage_Unit) /= 0 then Set_Result (Known_Incompatible); end if; @@ -12001,7 +11990,7 @@ package body Sem_Util is -- If we do not know required alignment, any non-zero offset is a -- potential problem (but certainly may be OK, so result is unknown). - elsif Offs /= No_Uint then + elsif Present (Offs) then Set_Result (Unknown); -- If we can't find the result by direct comparison of alignment @@ -13399,7 +13388,10 @@ package body Sem_Util is -- Has_Preelaborable_Initialization -- -------------------------------------- - function Has_Preelaborable_Initialization (E : Entity_Id) return Boolean is + function Has_Preelaborable_Initialization + (E : Entity_Id; + Formal_Types_Have_Preelab_Init : Boolean := False) return Boolean + is Has_PE : Boolean; procedure Check_Components (E : Entity_Id); @@ -13453,7 +13445,9 @@ package body Sem_Util is -- component type has PI. if No (Exp) then - if not Has_Preelaborable_Initialization (Etype (Ent)) then + if not Has_Preelaborable_Initialization + (Etype (Ent), Formal_Types_Have_Preelab_Init) + then Has_PE := False; exit; end if; @@ -13499,7 +13493,8 @@ package body Sem_Util is -- Array types have PI if the component type has PI elsif Is_Array_Type (E) then - Has_PE := Has_Preelaborable_Initialization (Component_Type (E)); + Has_PE := Has_Preelaborable_Initialization + (Component_Type (E), Formal_Types_Have_Preelab_Init); -- A derived type has preelaborable initialization if its parent type -- has preelaborable initialization and (in the case of a derived record @@ -13510,6 +13505,14 @@ package body Sem_Util is elsif Is_Derived_Type (E) then + -- When the rule of RM 10.2.1(11.8/5) applies, we presume a component + -- of a generic formal derived type has preelaborable initialization. + -- (See comment on spec of Has_Preelaborable_Initialization.) + + if Is_Generic_Type (E) and then Formal_Types_Have_Preelab_Init then + return True; + end if; + -- If the derived type is a private extension then it doesn't have -- preelaborable initialization. @@ -13545,7 +13548,16 @@ package body Sem_Util is -- have preelaborable initialization. elsif Is_Private_Type (E) then - return False; + + -- When the rule of RM 10.2.1(11.8/5) applies, we presume a component + -- of a generic formal private type has preelaborable initialization. + -- (See comment on spec of Has_Preelaborable_Initialization.) + + if Is_Generic_Type (E) and then Formal_Types_Have_Preelab_Init then + return True; + else + return False; + end if; -- Record type has PI if it is non private and all components have PI @@ -15021,7 +15033,7 @@ package body Sem_Util is begin -- Return early if the component size is not known or variable - if Off = No_Uint or else Off < Uint_0 then + if No (Off) or else Off < Uint_0 then return No_Uint; end if; @@ -15544,7 +15556,7 @@ package body Sem_Util is -- Pragma Invalid_Scalars did not specify an invalid value for this -- type. Fall back to the value provided by the binder. - if Value = No_Uint then + if No (Value) then return Invalid_Binder_Value; else return Make_Integer_Literal (Loc, Intval => Value); @@ -16277,6 +16289,49 @@ package body Sem_Util is or else Is_Task_Interface (T); end Is_Concurrent_Interface; + ------------------------------------------------------ + -- Is_Conjunction_Of_Formal_Preelab_Init_Attributes -- + ------------------------------------------------------ + + function Is_Conjunction_Of_Formal_Preelab_Init_Attributes + (Expr : Node_Id) return Boolean + is + + function Is_Formal_Preelab_Init_Attribute + (N : Node_Id) return Boolean; + -- Returns True if N is a Preelaborable_Initialization attribute + -- applied to a generic formal type, or N's Original_Node is such + -- an attribute. + + -------------------------------------- + -- Is_Formal_Preelab_Init_Attribute -- + -------------------------------------- + + function Is_Formal_Preelab_Init_Attribute + (N : Node_Id) return Boolean + is + Orig_N : constant Node_Id := Original_Node (N); + + begin + return Nkind (Orig_N) = N_Attribute_Reference + and then Attribute_Name (Orig_N) = Name_Preelaborable_Initialization + and then Is_Entity_Name (Prefix (Orig_N)) + and then Is_Generic_Type (Entity (Prefix (Orig_N))); + end Is_Formal_Preelab_Init_Attribute; + + -- Start of Is_Conjunction_Of_Formal_Preelab_Init_Attributes + + begin + return Is_Formal_Preelab_Init_Attribute (Expr) + or else (Nkind (Expr) = N_Op_And + and then + Is_Conjunction_Of_Formal_Preelab_Init_Attributes + (Left_Opnd (Expr)) + and then + Is_Conjunction_Of_Formal_Preelab_Init_Attributes + (Right_Opnd (Expr))); + end Is_Conjunction_Of_Formal_Preelab_Init_Attributes; + ----------------------- -- Is_Constant_Bound -- ----------------------- @@ -17483,9 +17538,9 @@ package body Sem_Util is -- Is_False -- -------------- - function Is_False (U : Uint) return Boolean is + function Is_False (U : Opt_Ubool) return Boolean is begin - return (U = 0); + return not Is_True (U); end Is_False; --------------------------- @@ -20981,9 +21036,9 @@ package body Sem_Util is -- Is_True -- ------------- - function Is_True (U : Uint) return Boolean is + function Is_True (U : Opt_Ubool) return Boolean is begin - return U /= 0; + return No (U) or else U = Uint_1; end Is_True; -------------------------------------- @@ -24920,7 +24975,7 @@ package body Sem_Util is Set_Public_Status (N); if Kind in Type_Kind then - Init_Size_Align (N); + Reinit_Size_Align (N); end if; return N; @@ -24944,7 +24999,7 @@ package body Sem_Util is Append_Entity (N, Scope_Id); if Kind in Type_Kind then - Init_Size_Align (N); + Reinit_Size_Align (N); end if; return N; @@ -25996,6 +26051,33 @@ package body Sem_Util is end if; end Original_Corresponding_Operation; + ----------------------------------- + -- Original_View_In_Visible_Part -- + ----------------------------------- + + function Original_View_In_Visible_Part + (Typ : Entity_Id) return Boolean + is + Scop : constant Entity_Id := Scope (Typ); + + begin + -- The scope must be a package + + if not Is_Package_Or_Generic_Package (Scop) then + return False; + end if; + + -- A type with a private declaration has a private view declared in + -- the visible part. + + if Has_Private_Declaration (Typ) then + return True; + end if; + + return List_Containing (Parent (Typ)) = + Visible_Declarations (Package_Specification (Scop)); + end Original_View_In_Visible_Part; + ------------------- -- Output_Entity -- ------------------- @@ -28178,7 +28260,7 @@ package body Sem_Util is begin -- Detect an attempt to set a different value for the same scalar type - pragma Assert (Slot = No_Uint); + pragma Assert (No (Slot)); Slot := Value; end Set_Invalid_Scalar_Value; @@ -28356,7 +28438,7 @@ package body Sem_Util is -- We copy Esize, but not RM_Size, since in general RM_Size is -- subtype specific and does not get inherited by all subtypes. - Set_Esize (T1, Esize (T2)); + Copy_Esize (To => T1, From => T2); Set_Has_Biased_Representation (T1, Has_Biased_Representation (T2)); if Is_Discrete_Or_Fixed_Point_Type (T1) @@ -28405,7 +28487,7 @@ package body Sem_Util is -- Static_Boolean -- -------------------- - function Static_Boolean (N : Node_Id) return Uint is + function Static_Boolean (N : Node_Id) return Opt_Ubool is begin Analyze_And_Resolve (N, Standard_Boolean); diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index b0d6a2a..7c89585 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -1530,9 +1530,18 @@ package Sem_Util is -- non-null), which causes the type to not have preelaborable -- initialization. - function Has_Preelaborable_Initialization (E : Entity_Id) return Boolean; + function Has_Preelaborable_Initialization + (E : Entity_Id; + Formal_Types_Have_Preelab_Init : Boolean := False) return Boolean; -- Return True iff type E has preelaborable initialization as defined in -- Ada 2005 (see AI-161 for details of the definition of this attribute). + -- If Formal_Types_Have_Preelab_Init is True, indicates that the function + -- should presume that for any subcomponents of formal private or derived + -- types, the types have preelaborable initialization (RM 10.2.1(11.8/5)). + -- NOTE: The treatment of subcomponents of formal types should only apply + -- for types actually specified in the P_I aspect of the outer type, but + -- for now we take a more liberal interpretation. This needs addressing, + -- perhaps by passing the outermost type instead of the simple flag. ??? function Has_Prefix (N : Node_Id) return Boolean; -- Return True if N has attribute Prefix @@ -1828,6 +1837,13 @@ package Sem_Util is -- Returns true if the two specifications of the given -- nonoverridable aspect are compatible. + function Is_Conjunction_Of_Formal_Preelab_Init_Attributes + (Expr : Node_Id) return Boolean; + -- Returns True if Expr is a Preelaborable_Initialization attribute applied + -- to a formal type, or a sequence of two or more such attributes connected + -- by "and" operators, or if the Original_Node of Expr or its constituents + -- is such an attribute. + function Is_Constant_Bound (Exp : Node_Id) return Boolean; -- Exp is the expression for an array bound. Determines whether the -- bound is a compile-time known value, or a constant entity, or an @@ -2038,11 +2054,17 @@ package Sem_Util is -- 3) An if expression with at least one EVF dependent_expression -- 4) A case expression with at least one EVF dependent_expression - function Is_False (U : Uint) return Boolean; + function Is_False (U : Opt_Ubool) return Boolean; pragma Inline (Is_False); - -- The argument is a Uint value which is the Boolean'Pos value of a Boolean - -- operand (i.e. is either 0 for False, or 1 for True). This function tests - -- if it is False (i.e. zero). + -- True if U is Boolean'Pos (False) (i.e. Uint_0) + + function Is_True (U : Opt_Ubool) return Boolean; + pragma Inline (Is_True); + -- True if U is Boolean'Pos (True) (i.e. Uint_1). Also True if U is + -- No_Uint; we allow No_Uint because Static_Boolean returns that in + -- case of error. It doesn't really matter whether the error case is + -- considered True or False, but we don't want this to blow up in that + -- case. function Is_Fixed_Model_Number (U : Ureal; T : Entity_Id) return Boolean; -- Returns True iff the number U is a model number of the fixed-point type @@ -2406,12 +2428,6 @@ package Sem_Util is -- unconditional transfer of control at run time, i.e. the following -- statement definitely will not be executed. - function Is_True (U : Uint) return Boolean; - pragma Inline (Is_True); - -- The argument is a Uint value which is the Boolean'Pos value of a Boolean - -- operand (i.e. is either 0 for False, or 1 for True). This function tests - -- if it is True (i.e. non-zero). - function Is_Unchecked_Conversion_Instance (Id : Entity_Id) return Boolean; -- Determine whether an arbitrary entity denotes an instance of function -- Ada.Unchecked_Conversion. @@ -2845,6 +2861,10 @@ package Sem_Util is -- corresponding operation of S is the original corresponding operation of -- S2. Otherwise, it is S itself. + function Original_View_In_Visible_Part (Typ : Entity_Id) return Boolean; + -- Returns True if the type Typ has a private view or if the public view + -- appears in the visible part of a package spec. + procedure Output_Entity (Id : Entity_Id); -- Print entity Id to standard output. The name of the entity appears in -- fully qualified form. @@ -3199,7 +3219,7 @@ package Sem_Util is -- predefined unit. The _Par version should be called only from the parser; -- the _Sem version should be called only during semantic analysis. - function Static_Boolean (N : Node_Id) return Uint; + function Static_Boolean (N : Node_Id) return Opt_Ubool; -- This function analyzes the given expression node and then resolves it -- as Standard.Boolean. If the result is static, then Uint_1 or Uint_0 is -- returned corresponding to the value, otherwise an error message is diff --git a/gcc/ada/sinfo-utils.adb b/gcc/ada/sinfo-utils.adb index 7f9bb89..083c12e 100644 --- a/gcc/ada/sinfo-utils.adb +++ b/gcc/ada/sinfo-utils.adb @@ -191,7 +191,7 @@ package body Sinfo.Utils is function End_Location (N : Node_Id) return Source_Ptr is L : constant Uint := End_Span (N); begin - if L = No_Uint then + if No (L) then return No_Location; else return Source_Ptr (Int (Sloc (N)) + UI_To_Int (L)); diff --git a/gcc/ada/snames.adb-tmpl b/gcc/ada/snames.adb-tmpl index a1ea3ee..8701ea9 100644 --- a/gcc/ada/snames.adb-tmpl +++ b/gcc/ada/snames.adb-tmpl @@ -258,6 +258,8 @@ package body Snames is return Pragma_Interrupt_Priority; when Name_Lock_Free => return Pragma_Lock_Free; + when Name_Preelaborable_Initialization => + return Pragma_Preelaborable_Initialization; when Name_Priority => return Pragma_Priority; when Name_Secondary_Stack_Size => @@ -488,6 +490,7 @@ package body Snames is or else N = Name_Interface or else N = Name_Interrupt_Priority or else N = Name_Lock_Free + or else N = Name_Preelaborable_Initialization or else N = Name_Priority or else N = Name_Secondary_Stack_Size or else N = Name_Storage_Size diff --git a/gcc/ada/snames.ads-tmpl b/gcc/ada/snames.ads-tmpl index a67623b..34f1cef 100644 --- a/gcc/ada/snames.ads-tmpl +++ b/gcc/ada/snames.ads-tmpl @@ -37,6 +37,17 @@ package Snames is -- some exceptions). See the body of Get_Attribute_Id for details. The -- same is true of other enumeration types declared in this package. + -- ALSO NOTE: In the case of a name that corresponds to both an attribute + -- and a pragma, the Name_Id must be defined in the attribute section + -- (between First_Attribute_Name and Last_Attribute_Name). Also, please + -- add a comment in the list of Name_Ids at the point where the name would + -- normally appear alphabetically (for an example, see comment starting + -- "Note: CPU ..."). The Pragma_Id with that name must be defined in the + -- last section of literals for type Pragma_Id (see set of Pragma_Ids that + -- require special processing due to matching an attribute name). Finally, + -- the bodies of functions Get_Pragma_Id and Is_Pragma_Name must be updated + -- to test for each such pragma that shares a name with an attribute. + ------------------ -- Preset Names -- ------------------ @@ -624,7 +635,13 @@ package Snames is Name_Precondition : constant Name_Id := N + $; -- GNAT Name_Predicate : constant Name_Id := N + $; -- GNAT Name_Predicate_Failure : constant Name_Id := N + $; -- Ada 12 - Name_Preelaborable_Initialization : constant Name_Id := N + $; -- Ada 05 + + -- Note: Preelaborable_Initialization is not in this list because its name + -- matches the name of the corresponding attribute. However, it is included + -- in the definition of the type Pragma_Id, and the functions Get_Pragma_Id + -- and Is_Pragma_Name correctly recognize and process that pragma name. + -- Preelaborable_Initialization is a standard Ada 2005 pragma. + Name_Preelaborate : constant Name_Id := N + $; Name_Pre_Class : constant Name_Id := N + $; -- GNAT @@ -1007,6 +1024,7 @@ package Snames is Name_Pool_Address : constant Name_Id := N + $; -- GNAT Name_Pos : constant Name_Id := N + $; Name_Position : constant Name_Id := N + $; + Name_Preelaborable_Initialization : constant Name_Id := N + $; -- Ada 22 Name_Priority : constant Name_Id := N + $; -- Ada 05 Name_Range : constant Name_Id := N + $; Name_Range_Length : constant Name_Id := N + $; -- GNAT @@ -1536,6 +1554,7 @@ package Snames is Attribute_Pool_Address, Attribute_Pos, Attribute_Position, + Attribute_Preelaborable_Initialization, Attribute_Priority, Attribute_Range, Attribute_Range_Length, @@ -1921,7 +1940,6 @@ package Snames is Pragma_Precondition, Pragma_Predicate, Pragma_Predicate_Failure, - Pragma_Preelaborable_Initialization, Pragma_Preelaborate, Pragma_Pre_Class, Pragma_Provide_Shift_Operators, @@ -1974,7 +1992,9 @@ package Snames is -- The following pragmas are on their own, out of order, because of the -- special processing required to deal with the fact that their names - -- match existing attribute names. + -- match existing attribute names. Note that when a pragma is added in + -- this section, functions Get_Pragma_Id and Is_Pragma_Name must be + -- updated to account for the new pragma. Pragma_CPU, Pragma_Default_Scalar_Storage_Order, @@ -1983,6 +2003,7 @@ package Snames is Pragma_Interface, Pragma_Interrupt_Priority, Pragma_Lock_Free, + Pragma_Preelaborable_Initialization, Pragma_Priority, Pragma_Secondary_Stack_Size, Pragma_Storage_Size, diff --git a/gcc/ada/sprint.adb b/gcc/ada/sprint.adb index c1f1ede..8dc96a4 100644 --- a/gcc/ada/sprint.adb +++ b/gcc/ada/sprint.adb @@ -4222,7 +4222,7 @@ package body Sprint is -- Itype to be printed declare - B : constant Node_Id := Etype (Typ); + B : constant Entity_Id := Etype (Typ); P : constant Node_Id := Parent (Typ); S : constant Saved_Output_Buffer := Save_Output_Buffer; -- Save current output buffer diff --git a/gcc/ada/sysdep.c b/gcc/ada/sysdep.c index aa38c5c..ee951e3 100644 --- a/gcc/ada/sysdep.c +++ b/gcc/ada/sysdep.c @@ -643,11 +643,11 @@ long __gnat_invalid_tzoff = 259273; /* Reentrant localtime for Windows. */ extern void -__gnat_localtime_tzoff (const time_t *, const int *, long *); +__gnat_localtime_tzoff (const OS_Time *, const int *, long *); static const unsigned long long w32_epoch_offset = 11644473600ULL; void -__gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off) +__gnat_localtime_tzoff (const OS_Time *timer, const int *is_historic, long *off) { TIME_ZONE_INFORMATION tzi; @@ -737,10 +737,10 @@ __gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off) the Lynx convention when building against the legacy API. */ extern void -__gnat_localtime_tzoff (const time_t *, const int *, long *); +__gnat_localtime_tzoff (const OS_Time *, const int *, long *); void -__gnat_localtime_tzoff (const time_t *timer, const int *is_historic, long *off) +__gnat_localtime_tzoff (const OS_Time *timer, const int *is_historic, long *off) { *off = 0; } @@ -756,21 +756,22 @@ extern void (*Lock_Task) (void); extern void (*Unlock_Task) (void); extern void -__gnat_localtime_tzoff (const time_t *, const int *, long *); +__gnat_localtime_tzoff (const OS_Time *, const int *, long *); void -__gnat_localtime_tzoff (const time_t *timer ATTRIBUTE_UNUSED, +__gnat_localtime_tzoff (const OS_Time *timer ATTRIBUTE_UNUSED, const int *is_historic ATTRIBUTE_UNUSED, long *off ATTRIBUTE_UNUSED) { struct tm tp ATTRIBUTE_UNUSED; + const time_t time = (time_t) *timer; /* AIX, HPUX, Sun Solaris */ #if defined (_AIX) || defined (__hpux__) || defined (__sun__) { (*Lock_Task) (); - localtime_r (timer, &tp); + localtime_r (&time, &tp); *off = (long) -timezone; (*Unlock_Task) (); @@ -787,7 +788,7 @@ __gnat_localtime_tzoff (const time_t *timer ATTRIBUTE_UNUSED, { (*Lock_Task) (); - localtime_r (timer, &tp); + localtime_r (&time, &tp); /* Try to read the environment variable TIMEZONE. The variable may not have been initialize, in that case return an offset of zero (0) for UTC. */ @@ -833,7 +834,7 @@ __gnat_localtime_tzoff (const time_t *timer ATTRIBUTE_UNUSED, || defined (__GLIBC__) || defined (__DragonFly__) || defined (__OpenBSD__) \ || defined (__DJGPP__) || defined (__QNX__) { - localtime_r (timer, &tp); + localtime_r (&time, &tp); *off = tp.tm_gmtoff; } diff --git a/gcc/ada/treepr.adb b/gcc/ada/treepr.adb index 054d06c..48f76cb 100644 --- a/gcc/ada/treepr.adb +++ b/gcc/ada/treepr.adb @@ -614,7 +614,7 @@ package body Treepr is Write_Str (UI_Image (Val)); Write_Str (") "); - if Val /= No_Uint then + if Present (Val) then Write_Location (End_Location (N)); end if; end Print_End_Span; diff --git a/gcc/ada/ttypes.ads b/gcc/ada/ttypes.ads index 5f59607..62a1c4f 100644 --- a/gcc/ada/ttypes.ads +++ b/gcc/ada/ttypes.ads @@ -25,7 +25,7 @@ -- This package contains constants describing target properties -with Types; use Types; +with Types; use Types; with Set_Targ; package Ttypes is diff --git a/gcc/ada/types.ads b/gcc/ada/types.ads index a74bfb6..2caaf50 100644 --- a/gcc/ada/types.ads +++ b/gcc/ada/types.ads @@ -59,6 +59,8 @@ package Types is subtype Pos is Int range 1 .. Int'Last; -- Positive Int values + subtype Nonzero_Int is Int with Predicate => Nonzero_Int /= 0; + type Word is mod 2 ** 32; -- Unsigned 32-bit integer diff --git a/gcc/ada/uintp.adb b/gcc/ada/uintp.adb index 8183469..29d409b 100644 --- a/gcc/ada/uintp.adb +++ b/gcc/ada/uintp.adb @@ -73,6 +73,18 @@ package body Uintp is -- These values are used in some cases where the use of numeric literals -- would cause ambiguities (integer vs Uint). + type UI_Vector is array (Pos range <>) of Int; + -- Vector containing the integer values of a Uint value + + -- Note: An earlier version of this package used pointers of arrays of Ints + -- (dynamically allocated) for the Uint type. The change leads to a few + -- less natural idioms used throughout this code, but eliminates all uses + -- of the heap except for the table package itself. For example, Uint + -- parameters are often converted to UI_Vectors for internal manipulation. + -- This is done by creating the local UI_Vector using the function N_Digits + -- on the Uint to find the size needed for the vector, and then calling + -- Init_Operand to copy the values out of the table into the vector. + ---------------------------- -- UI_From_Int Hash Table -- ---------------------------- @@ -98,12 +110,12 @@ package body Uintp is -- Local Subprograms -- ----------------------- - function Direct (U : Uint) return Boolean; + function Direct (U : Valid_Uint) return Boolean; pragma Inline (Direct); -- Returns True if U is represented directly - function Direct_Val (U : Uint) return Int; - -- U is a Uint for is represented directly. The returned result is the + function Direct_Val (U : Valid_Uint) return Int; + -- U is a Uint that is represented directly. The returned result is the -- value represented. function GCD (Jin, Kin : Int) return Int; @@ -117,7 +129,7 @@ package body Uintp is -- UI_Image, and false for UI_Write, and Format is copied from the Format -- parameter to UI_Image or UI_Write. - procedure Init_Operand (UI : Uint; Vec : out UI_Vector); + procedure Init_Operand (UI : Valid_Uint; Vec : out UI_Vector); pragma Inline (Init_Operand); -- This procedure puts the value of UI into the vector in canonical -- multiple precision format. The parameter should be of the correct size @@ -127,7 +139,23 @@ package body Uintp is -- contain the corresponding one or two digit value. The low bound of Vec -- is always 1. - function Least_Sig_Digit (Arg : Uint) return Int; + function Vector_To_Uint + (In_Vec : UI_Vector; + Negative : Boolean) return Valid_Uint; + -- Functions that calculate values in UI_Vectors, call this function to + -- create and return the Uint value. In_Vec contains the multiple precision + -- (Base) representation of a non-negative value. Leading zeroes are + -- permitted. Negative is set if the desired result is the negative of the + -- given value. The result will be either the appropriate directly + -- represented value, or a table entry in the proper canonical format is + -- created and returned. + -- + -- Note that Init_Operand puts a signed value in the result vector, but + -- Vector_To_Uint is always presented with a non-negative value. The + -- processing of signs is something that is done by the caller before + -- calling Vector_To_Uint. + + function Least_Sig_Digit (Arg : Valid_Uint) return Int; pragma Inline (Least_Sig_Digit); -- Returns the Least Significant Digit of Arg quickly. When the given Uint -- is less than 2**15, the value returned is the input value, in this case @@ -137,8 +165,8 @@ package body Uintp is -- two. procedure Most_Sig_2_Digits - (Left : Uint; - Right : Uint; + (Left : Valid_Uint; + Right : Valid_Uint; Left_Hat : out Int; Right_Hat : out Int); -- Returns leading two significant digits from the given pair of Uint's. @@ -146,29 +174,40 @@ package body Uintp is -- K is as small as possible S.T. Right_Hat < Base * Base. It is required -- that Left >= Right for the algorithm to work. - function N_Digits (Input : Uint) return Int; + function N_Digits (Input : Valid_Uint) return Int; pragma Inline (N_Digits); -- Returns number of "digits" in a Uint procedure UI_Div_Rem - (Left, Right : Uint; + (Left, Right : Valid_Uint; Quotient : out Uint; Remainder : out Uint; Discard_Quotient : Boolean := False; Discard_Remainder : Boolean := False); -- Compute Euclidean division of Left by Right. If Discard_Quotient is - -- False then the quotient is returned in Quotient (otherwise Quotient is - -- set to No_Uint). If Discard_Remainder is False, then the remainder is - -- returned in Remainder (otherwise Remainder is set to No_Uint). + -- False then the quotient is returned in Quotient. If Discard_Remainder + -- is False, then the remainder is returned in Remainder. -- - -- If Discard_Quotient is True, Quotient is set to No_Uint - -- If Discard_Remainder is True, Remainder is set to No_Uint + -- If Discard_Quotient is True, Quotient is set to No_Uint. + -- If Discard_Remainder is True, Remainder is set to No_Uint. + + function UI_Modular_Exponentiation + (B : Valid_Uint; + E : Valid_Uint; + Modulo : Valid_Uint) return Valid_Uint with Unreferenced; + -- Efficiently compute (B**E) rem Modulo + + function UI_Modular_Inverse + (N : Valid_Uint; Modulo : Valid_Uint) return Valid_Uint with Unreferenced; + -- Compute the multiplicative inverse of N in modular arithmetics with the + -- given Modulo (uses Euclid's algorithm). Note: the call is considered + -- to be erroneous (and the behavior is undefined) if n is not invertible. ------------ -- Direct -- ------------ - function Direct (U : Uint) return Boolean is + function Direct (U : Valid_Uint) return Boolean is begin return Int (U) <= Int (Uint_Direct_Last); end Direct; @@ -177,7 +216,7 @@ package body Uintp is -- Direct_Val -- ---------------- - function Direct_Val (U : Uint) return Int is + function Direct_Val (U : Valid_Uint) return Int is begin pragma Assert (Direct (U)); return Int (U) - Int (Uint_Direct_Bias); @@ -224,8 +263,8 @@ package body Uintp is Format : UI_Format) is Marks : constant Uintp.Save_Mark := Uintp.Mark; - Base : Uint; - Ainput : Uint; + Base : Valid_Uint; + Ainput : Valid_Uint; Digs_Output : Natural := 0; -- Counts digits output. In hex mode, but not in decimal mode, we @@ -249,7 +288,7 @@ package body Uintp is -- Output non-zero exponent. Note that we only use the exponent form in -- the buffer case, so we know that To_Buffer is true. - procedure Image_Uint (U : Uint); + procedure Image_Uint (U : Valid_Uint); -- Internal procedure to output characters of non-negative Uint ------------------- @@ -257,8 +296,8 @@ package body Uintp is ------------------- function Better_In_Hex return Boolean is - T16 : constant Uint := Uint_2**Int'(16); - A : Uint; + T16 : constant Valid_Uint := Uint_2**Int'(16); + A : Valid_Uint; begin A := UI_Abs (Input); @@ -336,11 +375,11 @@ package body Uintp is -- Image_Uint -- ---------------- - procedure Image_Uint (U : Uint) is + procedure Image_Uint (U : Valid_Uint) is H : constant array (Int range 0 .. 15) of Character := "0123456789ABCDEF"; - Q, R : Uint; + Q, R : Valid_Uint; begin UI_Div_Rem (U, Base, Q, R); @@ -361,7 +400,7 @@ package body Uintp is -- Start of processing for Image_Out begin - if Input = No_Uint then + if No (Input) then Image_Char ('?'); return; end if; @@ -403,7 +442,7 @@ package body Uintp is -- Init_Operand -- ------------------- - procedure Init_Operand (UI : Uint; Vec : out UI_Vector) is + procedure Init_Operand (UI : Valid_Uint; Vec : out UI_Vector) is Loc : Int; pragma Assert (Vec'First = Int'(1)); @@ -454,7 +493,7 @@ package body Uintp is -- Least_Sig_Digit -- --------------------- - function Least_Sig_Digit (Arg : Uint) return Int is + function Least_Sig_Digit (Arg : Valid_Uint) return Int is V : Int; begin @@ -490,8 +529,8 @@ package body Uintp is ----------------------- procedure Most_Sig_2_Digits - (Left : Uint; - Right : Uint; + (Left : Valid_Uint; + Right : Valid_Uint; Left_Hat : out Int; Right_Hat : out Int) is @@ -552,9 +591,7 @@ package body Uintp is -- N_Digits -- --------------- - -- Note: N_Digits returns 1 for No_Uint - - function N_Digits (Input : Uint) return Int is + function N_Digits (Input : Valid_Uint) return Int is begin if Direct (Input) then if Direct_Val (Input) >= Base then @@ -572,7 +609,7 @@ package body Uintp is -- Num_Bits -- -------------- - function Num_Bits (Input : Uint) return Nat is + function Num_Bits (Input : Valid_Uint) return Nat is Bits : Nat; Num : Nat; @@ -633,7 +670,7 @@ package body Uintp is procedure Release (M : Save_Mark) is begin - Uints.Set_Last (Uint'Max (M.Save_Uint, Uints_Min)); + Uints.Set_Last (Valid_Uint'Max (M.Save_Uint, Uints_Min)); Udigits.Set_Last (Int'Max (M.Save_Udigit, Udigits_Min)); end Release; @@ -641,7 +678,7 @@ package body Uintp is -- Release_And_Save -- ---------------------- - procedure Release_And_Save (M : Save_Mark; UI : in out Uint) is + procedure Release_And_Save (M : Save_Mark; UI : in out Valid_Uint) is begin if Direct (UI) then Release (M); @@ -667,7 +704,7 @@ package body Uintp is end if; end Release_And_Save; - procedure Release_And_Save (M : Save_Mark; UI1, UI2 : in out Uint) is + procedure Release_And_Save (M : Save_Mark; UI1, UI2 : in out Valid_Uint) is begin if Direct (UI1) then Release_And_Save (M, UI2); @@ -713,7 +750,7 @@ package body Uintp is -- UI_Abs -- ------------- - function UI_Abs (Right : Uint) return Uint is + function UI_Abs (Right : Valid_Uint) return Unat is begin if Right < Uint_0 then return -Right; @@ -726,18 +763,23 @@ package body Uintp is -- UI_Add -- ------------- - function UI_Add (Left : Int; Right : Uint) return Uint is + function UI_Add (Left : Int; Right : Valid_Uint) return Valid_Uint is begin return UI_Add (UI_From_Int (Left), Right); end UI_Add; - function UI_Add (Left : Uint; Right : Int) return Uint is + function UI_Add (Left : Valid_Uint; Right : Int) return Valid_Uint is begin return UI_Add (Left, UI_From_Int (Right)); end UI_Add; - function UI_Add (Left : Uint; Right : Uint) return Uint is + function UI_Add (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint is begin + pragma Assert (Present (Left)); + pragma Assert (Present (Right)); + -- Assertions are here in case we're called from C++ code, which does + -- not check the predicates. + -- Simple cases of direct operands and addition of zero if Direct (Left) then @@ -902,7 +944,7 @@ package body Uintp is -- UI_Decimal_Digits_Hi -- -------------------------- - function UI_Decimal_Digits_Hi (U : Uint) return Nat is + function UI_Decimal_Digits_Hi (U : Valid_Uint) return Nat is begin -- The maximum value of a "digit" is 32767, which is 5 decimal digits, -- so an N_Digit number could take up to 5 times this number of digits. @@ -916,7 +958,7 @@ package body Uintp is -- UI_Decimal_Digits_Lo -- -------------------------- - function UI_Decimal_Digits_Lo (U : Uint) return Nat is + function UI_Decimal_Digits_Lo (U : Valid_Uint) return Nat is begin -- The maximum value of a "digit" is 32767, which is more than four -- decimal digits, but not a full five digits. The easily computed @@ -931,24 +973,27 @@ package body Uintp is -- UI_Div -- ------------ - function UI_Div (Left : Int; Right : Uint) return Uint is + function UI_Div (Left : Int; Right : Nonzero_Uint) return Valid_Uint is begin return UI_Div (UI_From_Int (Left), Right); end UI_Div; - function UI_Div (Left : Uint; Right : Int) return Uint is + function UI_Div + (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint + is begin return UI_Div (Left, UI_From_Int (Right)); end UI_Div; - function UI_Div (Left, Right : Uint) return Uint is - Quotient : Uint; - Remainder : Uint; - pragma Warnings (Off, Remainder); + function UI_Div + (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint + is + Quotient : Valid_Uint; + Ignored_Remainder : Uint; begin UI_Div_Rem (Left, Right, - Quotient, Remainder, + Quotient, Ignored_Remainder, Discard_Remainder => True); return Quotient; end UI_Div; @@ -958,7 +1003,7 @@ package body Uintp is ---------------- procedure UI_Div_Rem - (Left, Right : Uint; + (Left, Right : Valid_Uint; Quotient : out Uint; Remainder : out Uint; Discard_Quotient : Boolean := False; @@ -1232,14 +1277,13 @@ package body Uintp is if not Discard_Remainder then declare Remainder_V : UI_Vector (1 .. R_Length); - Discard_Int : Int; - pragma Warnings (Off, Discard_Int); + Ignore : Int; begin pragma Assert (D /= Int'(0)); UI_Div_Vector (Dividend (Dividend'Last - R_Length + 1 .. Dividend'Last), D, - Remainder_V, Discard_Int); + Remainder_V, Ignore); Remainder := Vector_To_Uint (Remainder_V, L_Vec (1) < Int_0); end; end if; @@ -1251,17 +1295,17 @@ package body Uintp is -- UI_Eq -- ------------ - function UI_Eq (Left : Int; Right : Uint) return Boolean is + function UI_Eq (Left : Int; Right : Valid_Uint) return Boolean is begin return not UI_Ne (UI_From_Int (Left), Right); end UI_Eq; - function UI_Eq (Left : Uint; Right : Int) return Boolean is + function UI_Eq (Left : Valid_Uint; Right : Int) return Boolean is begin return not UI_Ne (Left, UI_From_Int (Right)); end UI_Eq; - function UI_Eq (Left : Uint; Right : Uint) return Boolean is + function UI_Eq (Left : Valid_Uint; Right : Valid_Uint) return Boolean is begin return not UI_Ne (Left, Right); end UI_Eq; @@ -1270,22 +1314,24 @@ package body Uintp is -- UI_Expon -- -------------- - function UI_Expon (Left : Int; Right : Uint) return Uint is + function UI_Expon (Left : Int; Right : Unat) return Valid_Uint is begin return UI_Expon (UI_From_Int (Left), Right); end UI_Expon; - function UI_Expon (Left : Uint; Right : Int) return Uint is + function UI_Expon (Left : Valid_Uint; Right : Nat) return Valid_Uint is begin return UI_Expon (Left, UI_From_Int (Right)); end UI_Expon; - function UI_Expon (Left : Int; Right : Int) return Uint is + function UI_Expon (Left : Int; Right : Nat) return Valid_Uint is begin return UI_Expon (UI_From_Int (Left), UI_From_Int (Right)); end UI_Expon; - function UI_Expon (Left : Uint; Right : Uint) return Uint is + function UI_Expon + (Left : Valid_Uint; Right : Unat) return Valid_Uint + is begin pragma Assert (Right >= Uint_0); @@ -1358,9 +1404,9 @@ package body Uintp is -- If we fall through, then we have the general case (see Knuth 4.6.3) declare - N : Uint := Right; - Squares : Uint := Left; - Result : Uint := Uint_1; + N : Valid_Uint := Right; + Squares : Valid_Uint := Left; + Result : Valid_Uint := Uint_1; M : constant Uintp.Save_Mark := Uintp.Mark; begin @@ -1383,7 +1429,7 @@ package body Uintp is -- UI_From_CC -- ---------------- - function UI_From_CC (Input : Char_Code) return Uint is + function UI_From_CC (Input : Char_Code) return Valid_Uint is begin return UI_From_Int (Int (Input)); end UI_From_CC; @@ -1392,19 +1438,19 @@ package body Uintp is -- UI_From_Int -- ----------------- - function UI_From_Int (Input : Int) return Uint is + function UI_From_Int (Input : Int) return Valid_Uint is U : Uint; begin if Min_Direct <= Input and then Input <= Max_Direct then - return Uint (Int (Uint_Direct_Bias) + Input); + return Valid_Uint (Int (Uint_Direct_Bias) + Input); end if; -- If already in the hash table, return entry U := UI_Ints.Get (Input); - if U /= No_Uint then + if Present (U) then return U; end if; @@ -1438,7 +1484,7 @@ package body Uintp is -- UI_From_Integral -- ---------------------- - function UI_From_Integral (Input : In_T) return Uint is + function UI_From_Integral (Input : In_T) return Valid_Uint is begin -- If in range of our normal conversion function, use it so we can use -- direct access and our cache. @@ -1459,7 +1505,7 @@ package body Uintp is -- Base is defined so that 3 Uint digits is sufficient to hold the -- largest possible Int value. - U : Uint; + U : Valid_Uint; V : UI_Vector (1 .. Max_For_In_T); begin @@ -1489,8 +1535,8 @@ package body Uintp is -- We use the same notation as Knuth (U_Hat standing for the obvious) - function UI_GCD (Uin, Vin : Uint) return Uint is - U, V : Uint; + function UI_GCD (Uin, Vin : Valid_Uint) return Valid_Uint is + U, V : Valid_Uint; -- Copies of Uin and Vin U_Hat, V_Hat : Int; @@ -1498,7 +1544,7 @@ package body Uintp is A, B, C, D, T, Q, Den1, Den2 : Int; - Tmp_UI : Uint; + Tmp_UI : Valid_Uint; Marks : constant Uintp.Save_Mark := Uintp.Mark; Iterations : Integer := 0; @@ -1591,17 +1637,17 @@ package body Uintp is -- UI_Ge -- ------------ - function UI_Ge (Left : Int; Right : Uint) return Boolean is + function UI_Ge (Left : Int; Right : Valid_Uint) return Boolean is begin return not UI_Lt (UI_From_Int (Left), Right); end UI_Ge; - function UI_Ge (Left : Uint; Right : Int) return Boolean is + function UI_Ge (Left : Valid_Uint; Right : Int) return Boolean is begin return not UI_Lt (Left, UI_From_Int (Right)); end UI_Ge; - function UI_Ge (Left : Uint; Right : Uint) return Boolean is + function UI_Ge (Left : Valid_Uint; Right : Valid_Uint) return Boolean is begin return not UI_Lt (Left, Right); end UI_Ge; @@ -1610,17 +1656,17 @@ package body Uintp is -- UI_Gt -- ------------ - function UI_Gt (Left : Int; Right : Uint) return Boolean is + function UI_Gt (Left : Int; Right : Valid_Uint) return Boolean is begin return UI_Lt (Right, UI_From_Int (Left)); end UI_Gt; - function UI_Gt (Left : Uint; Right : Int) return Boolean is + function UI_Gt (Left : Valid_Uint; Right : Int) return Boolean is begin return UI_Lt (UI_From_Int (Right), Left); end UI_Gt; - function UI_Gt (Left : Uint; Right : Uint) return Boolean is + function UI_Gt (Left : Valid_Uint; Right : Valid_Uint) return Boolean is begin return UI_Lt (Left => Right, Right => Left); end UI_Gt; @@ -1647,7 +1693,10 @@ package body Uintp is -- UI_Is_In_Int_Range -- ------------------------- - function UI_Is_In_Int_Range (Input : Uint) return Boolean is + function UI_Is_In_Int_Range (Input : Valid_Uint) return Boolean is + pragma Assert (Present (Input)); + -- Assertion is here in case we're called from C++ code, which does + -- not check the predicates. begin -- Make sure we don't get called before Initialize @@ -1656,8 +1705,7 @@ package body Uintp is if Direct (Input) then return True; else - return Input >= Uint_Int_First - and then Input <= Uint_Int_Last; + return Input >= Uint_Int_First and then Input <= Uint_Int_Last; end if; end UI_Is_In_Int_Range; @@ -1665,17 +1713,17 @@ package body Uintp is -- UI_Le -- ------------ - function UI_Le (Left : Int; Right : Uint) return Boolean is + function UI_Le (Left : Int; Right : Valid_Uint) return Boolean is begin return not UI_Lt (Right, UI_From_Int (Left)); end UI_Le; - function UI_Le (Left : Uint; Right : Int) return Boolean is + function UI_Le (Left : Valid_Uint; Right : Int) return Boolean is begin return not UI_Lt (UI_From_Int (Right), Left); end UI_Le; - function UI_Le (Left : Uint; Right : Uint) return Boolean is + function UI_Le (Left : Valid_Uint; Right : Valid_Uint) return Boolean is begin return not UI_Lt (Left => Right, Right => Left); end UI_Le; @@ -1684,18 +1732,23 @@ package body Uintp is -- UI_Lt -- ------------ - function UI_Lt (Left : Int; Right : Uint) return Boolean is + function UI_Lt (Left : Int; Right : Valid_Uint) return Boolean is begin return UI_Lt (UI_From_Int (Left), Right); end UI_Lt; - function UI_Lt (Left : Uint; Right : Int) return Boolean is + function UI_Lt (Left : Valid_Uint; Right : Int) return Boolean is begin return UI_Lt (Left, UI_From_Int (Right)); end UI_Lt; - function UI_Lt (Left : Uint; Right : Uint) return Boolean is + function UI_Lt (Left : Valid_Uint; Right : Valid_Uint) return Boolean is begin + pragma Assert (Present (Left)); + pragma Assert (Present (Right)); + -- Assertions are here in case we're called from C++ code, which does + -- not check the predicates. + -- Quick processing for identical arguments if Int (Left) = Int (Right) then @@ -1777,17 +1830,17 @@ package body Uintp is -- UI_Max -- ------------ - function UI_Max (Left : Int; Right : Uint) return Uint is + function UI_Max (Left : Int; Right : Valid_Uint) return Valid_Uint is begin return UI_Max (UI_From_Int (Left), Right); end UI_Max; - function UI_Max (Left : Uint; Right : Int) return Uint is + function UI_Max (Left : Valid_Uint; Right : Int) return Valid_Uint is begin return UI_Max (Left, UI_From_Int (Right)); end UI_Max; - function UI_Max (Left : Uint; Right : Uint) return Uint is + function UI_Max (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint is begin if Left >= Right then return Left; @@ -1800,17 +1853,17 @@ package body Uintp is -- UI_Min -- ------------ - function UI_Min (Left : Int; Right : Uint) return Uint is + function UI_Min (Left : Int; Right : Valid_Uint) return Valid_Uint is begin return UI_Min (UI_From_Int (Left), Right); end UI_Min; - function UI_Min (Left : Uint; Right : Int) return Uint is + function UI_Min (Left : Valid_Uint; Right : Int) return Valid_Uint is begin return UI_Min (Left, UI_From_Int (Right)); end UI_Min; - function UI_Min (Left : Uint; Right : Uint) return Uint is + function UI_Min (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint is begin if Left <= Right then return Left; @@ -1823,18 +1876,22 @@ package body Uintp is -- UI_Mod -- ------------- - function UI_Mod (Left : Int; Right : Uint) return Uint is + function UI_Mod (Left : Int; Right : Nonzero_Uint) return Valid_Uint is begin return UI_Mod (UI_From_Int (Left), Right); end UI_Mod; - function UI_Mod (Left : Uint; Right : Int) return Uint is + function UI_Mod + (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint + is begin return UI_Mod (Left, UI_From_Int (Right)); end UI_Mod; - function UI_Mod (Left : Uint; Right : Uint) return Uint is - Urem : constant Uint := Left rem Right; + function UI_Mod + (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint + is + Urem : constant Valid_Uint := Left rem Right; begin if (Left < Uint_0) = (Right < Uint_0) @@ -1851,15 +1908,15 @@ package body Uintp is ------------------------------- function UI_Modular_Exponentiation - (B : Uint; - E : Uint; - Modulo : Uint) return Uint + (B : Valid_Uint; + E : Valid_Uint; + Modulo : Valid_Uint) return Valid_Uint is M : constant Save_Mark := Mark; - Result : Uint := Uint_1; - Base : Uint := B; - Exponent : Uint := E; + Result : Valid_Uint := Uint_1; + Base : Valid_Uint := B; + Exponent : Valid_Uint := E; begin while Exponent /= Uint_0 loop @@ -1879,15 +1936,17 @@ package body Uintp is -- UI_Modular_Inverse -- ------------------------ - function UI_Modular_Inverse (N : Uint; Modulo : Uint) return Uint is + function UI_Modular_Inverse + (N : Valid_Uint; Modulo : Valid_Uint) return Valid_Uint + is M : constant Save_Mark := Mark; - U : Uint; - V : Uint; - Q : Uint; - R : Uint; - X : Uint; - Y : Uint; - T : Uint; + U : Valid_Uint; + V : Valid_Uint; + Q : Valid_Uint; + R : Valid_Uint; + X : Valid_Uint; + Y : Valid_Uint; + T : Valid_Uint; S : Int := 1; begin @@ -1923,17 +1982,17 @@ package body Uintp is -- UI_Mul -- ------------ - function UI_Mul (Left : Int; Right : Uint) return Uint is + function UI_Mul (Left : Int; Right : Valid_Uint) return Valid_Uint is begin return UI_Mul (UI_From_Int (Left), Right); end UI_Mul; - function UI_Mul (Left : Uint; Right : Int) return Uint is + function UI_Mul (Left : Valid_Uint; Right : Int) return Valid_Uint is begin return UI_Mul (Left, UI_From_Int (Right)); end UI_Mul; - function UI_Mul (Left : Uint; Right : Uint) return Uint is + function UI_Mul (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint is begin -- Case where product fits in the range of a 32-bit integer @@ -1991,20 +2050,24 @@ package body Uintp is -- UI_Ne -- ------------ - function UI_Ne (Left : Int; Right : Uint) return Boolean is + function UI_Ne (Left : Int; Right : Valid_Uint) return Boolean is begin return UI_Ne (UI_From_Int (Left), Right); end UI_Ne; - function UI_Ne (Left : Uint; Right : Int) return Boolean is + function UI_Ne (Left : Valid_Uint; Right : Int) return Boolean is begin return UI_Ne (Left, UI_From_Int (Right)); end UI_Ne; - function UI_Ne (Left : Uint; Right : Uint) return Boolean is + function UI_Ne (Left : Valid_Uint; Right : Valid_Uint) return Boolean is begin - -- Quick processing for identical arguments. Note that this takes - -- care of the case of two No_Uint arguments. + pragma Assert (Present (Left)); + pragma Assert (Present (Right)); + -- Assertions are here in case we're called from C++ code, which does + -- not check the predicates. + + -- Quick processing for identical arguments if Int (Left) = Int (Right) then return False; @@ -2062,7 +2125,7 @@ package body Uintp is -- UI_Negate -- ---------------- - function UI_Negate (Right : Uint) return Uint is + function UI_Negate (Right : Valid_Uint) return Valid_Uint is begin -- Case where input is directly represented. Note that since the range -- of Direct values is non-symmetrical, the result may not be directly @@ -2095,20 +2158,23 @@ package body Uintp is -- UI_Rem -- ------------- - function UI_Rem (Left : Int; Right : Uint) return Uint is + function UI_Rem (Left : Int; Right : Nonzero_Uint) return Valid_Uint is begin return UI_Rem (UI_From_Int (Left), Right); end UI_Rem; - function UI_Rem (Left : Uint; Right : Int) return Uint is + function UI_Rem + (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint + is begin return UI_Rem (Left, UI_From_Int (Right)); end UI_Rem; - function UI_Rem (Left, Right : Uint) return Uint is - Remainder : Uint; - Quotient : Uint; - pragma Warnings (Off, Quotient); + function UI_Rem + (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint + is + Remainder : Valid_Uint; + Ignored_Quotient : Uint; begin pragma Assert (Right /= Uint_0); @@ -2118,7 +2184,8 @@ package body Uintp is else UI_Div_Rem - (Left, Right, Quotient, Remainder, Discard_Quotient => True); + (Left, Right, Ignored_Quotient, Remainder, + Discard_Quotient => True); return Remainder; end if; end UI_Rem; @@ -2127,17 +2194,17 @@ package body Uintp is -- UI_Sub -- ------------ - function UI_Sub (Left : Int; Right : Uint) return Uint is + function UI_Sub (Left : Int; Right : Valid_Uint) return Valid_Uint is begin return UI_Add (Left, -Right); end UI_Sub; - function UI_Sub (Left : Uint; Right : Int) return Uint is + function UI_Sub (Left : Valid_Uint; Right : Int) return Valid_Uint is begin return UI_Add (Left, -Right); end UI_Sub; - function UI_Sub (Left : Uint; Right : Uint) return Uint is + function UI_Sub (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint is begin if Direct (Left) and then Direct (Right) then return UI_From_Int (Direct_Val (Left) - Direct_Val (Right)); @@ -2150,7 +2217,7 @@ package body Uintp is -- UI_To_CC -- -------------- - function UI_To_CC (Input : Uint) return Char_Code is + function UI_To_CC (Input : Valid_Uint) return Char_Code is begin if Direct (Input) then return Char_Code (Direct_Val (Input)); @@ -2183,9 +2250,7 @@ package body Uintp is -- UI_To_Int -- --------------- - function UI_To_Int (Input : Uint) return Int is - pragma Assert (Input /= No_Uint); - + function UI_To_Int (Input : Valid_Uint) return Int is begin if Direct (Input) then return Direct_Val (Input); @@ -2234,9 +2299,7 @@ package body Uintp is -- UI_To_Uns64 -- ----------------- - function UI_To_Unsigned_64 (Input : Uint) return Unsigned_64 is - pragma Assert (Input /= No_Uint); - + function UI_To_Unsigned_64 (Input : Valid_Uint) return Unsigned_64 is begin if Input < Uint_0 then raise Constraint_Error; @@ -2285,8 +2348,7 @@ package body Uintp is function Vector_To_Uint (In_Vec : UI_Vector; - Negative : Boolean) - return Uint + Negative : Boolean) return Valid_Uint is Size : Int; Val : Int; @@ -2306,9 +2368,9 @@ package body Uintp is if Size = Int_1 then if Negative then - return Uint (Int (Uint_Direct_Bias) - In_Vec (J)); + return Valid_Uint (Int (Uint_Direct_Bias) - In_Vec (J)); else - return Uint (Int (Uint_Direct_Bias) + In_Vec (J)); + return Valid_Uint (Int (Uint_Direct_Bias) + In_Vec (J)); end if; -- Positive two digit values may be in direct representation range @@ -2317,7 +2379,7 @@ package body Uintp is Val := In_Vec (J) * Base + In_Vec (J + 1); if Val <= Max_Direct then - return Uint (Int (Uint_Direct_Bias) + Val); + return Valid_Uint (Int (Uint_Direct_Bias) + Val); end if; end if; diff --git a/gcc/ada/uintp.ads b/gcc/ada/uintp.ads index b2f2315..d9f1f8f 100644 --- a/gcc/ada/uintp.ads +++ b/gcc/ada/uintp.ads @@ -90,22 +90,23 @@ package Uintp is Uint_Minus_127 : constant Uint; Uint_Minus_128 : constant Uint; - subtype Valid_Uint is Uint with Predicate => Valid_Uint /= No_Uint; - subtype Unat is Valid_Uint with Predicate => Unat >= Uint_0; - subtype Upos is Valid_Uint with Predicate => Upos >= Uint_0; - subtype Nonzero_Uint is Valid_Uint with Predicate => Nonzero_Uint /= Uint_0; + -- Functions for detecting No_Uint. Note that clients of this package + -- cannot use "=" and "/=" to compare with No_Uint; they must use No + -- and Present instead. + + function No (X : Uint) return Boolean is (X = No_Uint); + -- Note that this is using the predefined "=", not the "=" declared below, + -- which would blow up on No_Uint. - type UI_Vector is array (Pos range <>) of Int; - -- Vector containing the integer values of a Uint value + function Present (X : Uint) return Boolean is (not No (X)); - -- Note: An earlier version of this package used pointers of arrays of Ints - -- (dynamically allocated) for the Uint type. The change leads to a few - -- less natural idioms used throughout this code, but eliminates all uses - -- of the heap except for the table package itself. For example, Uint - -- parameters are often converted to UI_Vectors for internal manipulation. - -- This is done by creating the local UI_Vector using the function N_Digits - -- on the Uint to find the size needed for the vector, and then calling - -- Init_Operand to copy the values out of the table into the vector. + subtype Valid_Uint is Uint with Predicate => Present (Valid_Uint); + subtype Unat is Valid_Uint with Predicate => Unat >= Uint_0; -- natural + subtype Upos is Valid_Uint with Predicate => Upos >= Uint_1; -- positive + subtype Nonzero_Uint is Valid_Uint with Predicate => Nonzero_Uint /= Uint_0; + subtype Ubool is Valid_Uint with Predicate => Ubool in Uint_0 | Uint_1; + subtype Opt_Ubool is Uint with + Predicate => No (Opt_Ubool) or else Opt_Ubool in Ubool; ----------------- -- Subprograms -- @@ -116,177 +117,150 @@ package Uintp is -- unit, these are among the few tables that can be expanded during -- gigi processing. - function UI_Abs (Right : Uint) return Uint; + function UI_Abs (Right : Valid_Uint) return Unat; pragma Inline (UI_Abs); -- Returns abs function of universal integer - function UI_Add (Left : Uint; Right : Uint) return Uint; - function UI_Add (Left : Int; Right : Uint) return Uint; - function UI_Add (Left : Uint; Right : Int) return Uint; + function UI_Add (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint; + function UI_Add (Left : Int; Right : Valid_Uint) return Valid_Uint; + function UI_Add (Left : Valid_Uint; Right : Int) return Valid_Uint; -- Returns sum of two integer values - function UI_Decimal_Digits_Hi (U : Uint) return Nat; + function UI_Decimal_Digits_Hi (U : Valid_Uint) return Nat; -- Returns an estimate of the number of decimal digits required to -- represent the absolute value of U. This estimate is correct or high, -- i.e. it never returns a value that is too low. The accuracy of the -- estimate affects only the effectiveness of comparison optimizations -- in Urealp. - function UI_Decimal_Digits_Lo (U : Uint) return Nat; + function UI_Decimal_Digits_Lo (U : Valid_Uint) return Nat; -- Returns an estimate of the number of decimal digits required to -- represent the absolute value of U. This estimate is correct or low, -- i.e. it never returns a value that is too high. The accuracy of the -- estimate affects only the effectiveness of comparison optimizations -- in Urealp. - function UI_Div (Left : Uint; Right : Uint) return Uint; - function UI_Div (Left : Int; Right : Uint) return Uint; - function UI_Div (Left : Uint; Right : Int) return Uint; + function UI_Div (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint; + function UI_Div (Left : Int; Right : Nonzero_Uint) return Valid_Uint; + function UI_Div (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint; -- Returns quotient of two integer values. Fatal error if Right = 0 - function UI_Eq (Left : Uint; Right : Uint) return Boolean; - function UI_Eq (Left : Int; Right : Uint) return Boolean; - function UI_Eq (Left : Uint; Right : Int) return Boolean; + function UI_Eq (Left : Valid_Uint; Right : Valid_Uint) return Boolean; + function UI_Eq (Left : Int; Right : Valid_Uint) return Boolean; + function UI_Eq (Left : Valid_Uint; Right : Int) return Boolean; pragma Inline (UI_Eq); -- Compares integer values for equality - function UI_Expon (Left : Uint; Right : Uint) return Uint; - function UI_Expon (Left : Int; Right : Uint) return Uint; - function UI_Expon (Left : Uint; Right : Int) return Uint; - function UI_Expon (Left : Int; Right : Int) return Uint; + function UI_Expon (Left : Valid_Uint; Right : Unat) return Valid_Uint; + function UI_Expon (Left : Int; Right : Unat) return Valid_Uint; + function UI_Expon (Left : Valid_Uint; Right : Nat) return Valid_Uint; + function UI_Expon (Left : Int; Right : Nat) return Valid_Uint; -- Returns result of exponentiating two integer values. -- Fatal error if Right is negative. - function UI_GCD (Uin, Vin : Uint) return Uint; + function UI_GCD (Uin, Vin : Valid_Uint) return Valid_Uint; -- Computes GCD of input values. Assumes Uin >= Vin >= 0 - function UI_Ge (Left : Uint; Right : Uint) return Boolean; - function UI_Ge (Left : Int; Right : Uint) return Boolean; - function UI_Ge (Left : Uint; Right : Int) return Boolean; + function UI_Ge (Left : Valid_Uint; Right : Valid_Uint) return Boolean; + function UI_Ge (Left : Int; Right : Valid_Uint) return Boolean; + function UI_Ge (Left : Valid_Uint; Right : Int) return Boolean; pragma Inline (UI_Ge); -- Compares integer values for greater than or equal - function UI_Gt (Left : Uint; Right : Uint) return Boolean; - function UI_Gt (Left : Int; Right : Uint) return Boolean; - function UI_Gt (Left : Uint; Right : Int) return Boolean; + function UI_Gt (Left : Valid_Uint; Right : Valid_Uint) return Boolean; + function UI_Gt (Left : Int; Right : Valid_Uint) return Boolean; + function UI_Gt (Left : Valid_Uint; Right : Int) return Boolean; pragma Inline (UI_Gt); -- Compares integer values for greater than - function UI_Is_In_Int_Range (Input : Uint) return Boolean; + function UI_Is_In_Int_Range (Input : Valid_Uint) return Boolean; pragma Inline (UI_Is_In_Int_Range); - -- Determines if universal integer is in Int range + -- Determines if universal integer is in Int range. - function UI_Le (Left : Uint; Right : Uint) return Boolean; - function UI_Le (Left : Int; Right : Uint) return Boolean; - function UI_Le (Left : Uint; Right : Int) return Boolean; + function UI_Le (Left : Valid_Uint; Right : Valid_Uint) return Boolean; + function UI_Le (Left : Int; Right : Valid_Uint) return Boolean; + function UI_Le (Left : Valid_Uint; Right : Int) return Boolean; pragma Inline (UI_Le); -- Compares integer values for less than or equal - function UI_Lt (Left : Uint; Right : Uint) return Boolean; - function UI_Lt (Left : Int; Right : Uint) return Boolean; - function UI_Lt (Left : Uint; Right : Int) return Boolean; + function UI_Lt (Left : Valid_Uint; Right : Valid_Uint) return Boolean; + function UI_Lt (Left : Int; Right : Valid_Uint) return Boolean; + function UI_Lt (Left : Valid_Uint; Right : Int) return Boolean; -- Compares integer values for less than - function UI_Max (Left : Uint; Right : Uint) return Uint; - function UI_Max (Left : Int; Right : Uint) return Uint; - function UI_Max (Left : Uint; Right : Int) return Uint; + function UI_Max (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint; + function UI_Max (Left : Int; Right : Valid_Uint) return Valid_Uint; + function UI_Max (Left : Valid_Uint; Right : Int) return Valid_Uint; -- Returns maximum of two integer values - function UI_Min (Left : Uint; Right : Uint) return Uint; - function UI_Min (Left : Int; Right : Uint) return Uint; - function UI_Min (Left : Uint; Right : Int) return Uint; + function UI_Min (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint; + function UI_Min (Left : Int; Right : Valid_Uint) return Valid_Uint; + function UI_Min (Left : Valid_Uint; Right : Int) return Valid_Uint; -- Returns minimum of two integer values - function UI_Mod (Left : Uint; Right : Uint) return Uint; - function UI_Mod (Left : Int; Right : Uint) return Uint; - function UI_Mod (Left : Uint; Right : Int) return Uint; + function UI_Mod (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint; + function UI_Mod (Left : Int; Right : Nonzero_Uint) return Valid_Uint; + function UI_Mod (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint; pragma Inline (UI_Mod); -- Returns mod function of two integer values - function UI_Mul (Left : Uint; Right : Uint) return Uint; - function UI_Mul (Left : Int; Right : Uint) return Uint; - function UI_Mul (Left : Uint; Right : Int) return Uint; + function UI_Mul (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint; + function UI_Mul (Left : Int; Right : Valid_Uint) return Valid_Uint; + function UI_Mul (Left : Valid_Uint; Right : Int) return Valid_Uint; -- Returns product of two integer values - function UI_Ne (Left : Uint; Right : Uint) return Boolean; - function UI_Ne (Left : Int; Right : Uint) return Boolean; - function UI_Ne (Left : Uint; Right : Int) return Boolean; + function UI_Ne (Left : Valid_Uint; Right : Valid_Uint) return Boolean; + function UI_Ne (Left : Int; Right : Valid_Uint) return Boolean; + function UI_Ne (Left : Valid_Uint; Right : Int) return Boolean; pragma Inline (UI_Ne); -- Compares integer values for inequality - function UI_Negate (Right : Uint) return Uint; + function UI_Negate (Right : Valid_Uint) return Valid_Uint; pragma Inline (UI_Negate); -- Returns negative of universal integer - function UI_Rem (Left : Uint; Right : Uint) return Uint; - function UI_Rem (Left : Int; Right : Uint) return Uint; - function UI_Rem (Left : Uint; Right : Int) return Uint; + function UI_Rem (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint; + function UI_Rem (Left : Int; Right : Nonzero_Uint) return Valid_Uint; + function UI_Rem (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint; -- Returns rem of two integer values - function UI_Sub (Left : Uint; Right : Uint) return Uint; - function UI_Sub (Left : Int; Right : Uint) return Uint; - function UI_Sub (Left : Uint; Right : Int) return Uint; + function UI_Sub (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint; + function UI_Sub (Left : Int; Right : Valid_Uint) return Valid_Uint; + function UI_Sub (Left : Valid_Uint; Right : Int) return Valid_Uint; pragma Inline (UI_Sub); -- Returns difference of two integer values - function UI_Modular_Exponentiation - (B : Uint; - E : Uint; - Modulo : Uint) return Uint; - -- Efficiently compute (B**E) rem Modulo - - function UI_Modular_Inverse (N : Uint; Modulo : Uint) return Uint; - -- Compute the multiplicative inverse of N in modular arithmetics with the - -- given Modulo (uses Euclid's algorithm). Note: the call is considered - -- to be erroneous (and the behavior is undefined) if n is not invertible. - - function UI_From_Int (Input : Int) return Uint; + function UI_From_Int (Input : Int) return Valid_Uint; -- Converts Int value to universal integer form generic type In_T is range <>; - function UI_From_Integral (Input : In_T) return Uint; + function UI_From_Integral (Input : In_T) return Valid_Uint; -- Likewise, but converts from any integer type. Must not be applied to -- biased types (instantiation will provide a warning if actual is a biased -- type). - function UI_From_CC (Input : Char_Code) return Uint; + function UI_From_CC (Input : Char_Code) return Valid_Uint; -- Converts Char_Code value to universal integer form - function UI_To_Int (Input : Uint) return Int; + function UI_To_Int (Input : Valid_Uint) return Int; -- Converts universal integer value to Int. Constraint_Error if value is -- not in appropriate range. type Unsigned_64 is mod 2**64; - function UI_To_Unsigned_64 (Input : Uint) return Unsigned_64; + function UI_To_Unsigned_64 (Input : Valid_Uint) return Unsigned_64; -- Converts universal integer value to Unsigned_64. Constraint_Error if -- value is not in appropriate range. - function UI_To_CC (Input : Uint) return Char_Code; + function UI_To_CC (Input : Valid_Uint) return Char_Code; -- Converts universal integer value to Char_Code. Constraint_Error if value -- is not in Char_Code range. - function Num_Bits (Input : Uint) return Nat; + function Num_Bits (Input : Valid_Uint) return Nat; -- Approximate number of binary bits in given universal integer. This -- function is used for capacity checks, and it can be one bit off -- without affecting its usage. - function Vector_To_Uint - (In_Vec : UI_Vector; - Negative : Boolean) return Uint; - -- Functions that calculate values in UI_Vectors, call this function to - -- create and return the Uint value. In_Vec contains the multiple precision - -- (Base) representation of a non-negative value. Leading zeroes are - -- permitted. Negative is set if the desired result is the negative of the - -- given value. The result will be either the appropriate directly - -- represented value, or a table entry in the proper canonical format is - -- created and returned. - -- - -- Note that Init_Operand puts a signed value in the result vector, but - -- Vector_To_Uint is always presented with a non-negative value. The - -- processing of signs is something that is done by the caller before - -- calling Vector_To_Uint. - --------------------- -- Output Routines -- --------------------- @@ -338,58 +312,97 @@ package Uintp is -- Operator Renamings -- ------------------------ - function "+" (Left : Uint; Right : Uint) return Uint renames UI_Add; - function "+" (Left : Int; Right : Uint) return Uint renames UI_Add; - function "+" (Left : Uint; Right : Int) return Uint renames UI_Add; - - function "/" (Left : Uint; Right : Uint) return Uint renames UI_Div; - function "/" (Left : Int; Right : Uint) return Uint renames UI_Div; - function "/" (Left : Uint; Right : Int) return Uint renames UI_Div; - - function "*" (Left : Uint; Right : Uint) return Uint renames UI_Mul; - function "*" (Left : Int; Right : Uint) return Uint renames UI_Mul; - function "*" (Left : Uint; Right : Int) return Uint renames UI_Mul; - - function "-" (Left : Uint; Right : Uint) return Uint renames UI_Sub; - function "-" (Left : Int; Right : Uint) return Uint renames UI_Sub; - function "-" (Left : Uint; Right : Int) return Uint renames UI_Sub; - - function "**" (Left : Uint; Right : Uint) return Uint renames UI_Expon; - function "**" (Left : Uint; Right : Int) return Uint renames UI_Expon; - function "**" (Left : Int; Right : Uint) return Uint renames UI_Expon; - function "**" (Left : Int; Right : Int) return Uint renames UI_Expon; - - function "abs" (Real : Uint) return Uint renames UI_Abs; - - function "mod" (Left : Uint; Right : Uint) return Uint renames UI_Mod; - function "mod" (Left : Int; Right : Uint) return Uint renames UI_Mod; - function "mod" (Left : Uint; Right : Int) return Uint renames UI_Mod; - - function "rem" (Left : Uint; Right : Uint) return Uint renames UI_Rem; - function "rem" (Left : Int; Right : Uint) return Uint renames UI_Rem; - function "rem" (Left : Uint; Right : Int) return Uint renames UI_Rem; - - function "-" (Real : Uint) return Uint renames UI_Negate; - - function "=" (Left : Uint; Right : Uint) return Boolean renames UI_Eq; - function "=" (Left : Int; Right : Uint) return Boolean renames UI_Eq; - function "=" (Left : Uint; Right : Int) return Boolean renames UI_Eq; - - function ">=" (Left : Uint; Right : Uint) return Boolean renames UI_Ge; - function ">=" (Left : Int; Right : Uint) return Boolean renames UI_Ge; - function ">=" (Left : Uint; Right : Int) return Boolean renames UI_Ge; - - function ">" (Left : Uint; Right : Uint) return Boolean renames UI_Gt; - function ">" (Left : Int; Right : Uint) return Boolean renames UI_Gt; - function ">" (Left : Uint; Right : Int) return Boolean renames UI_Gt; - - function "<=" (Left : Uint; Right : Uint) return Boolean renames UI_Le; - function "<=" (Left : Int; Right : Uint) return Boolean renames UI_Le; - function "<=" (Left : Uint; Right : Int) return Boolean renames UI_Le; - - function "<" (Left : Uint; Right : Uint) return Boolean renames UI_Lt; - function "<" (Left : Int; Right : Uint) return Boolean renames UI_Lt; - function "<" (Left : Uint; Right : Int) return Boolean renames UI_Lt; + function "+" (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint + renames UI_Add; + function "+" (Left : Int; Right : Valid_Uint) return Valid_Uint + renames UI_Add; + function "+" (Left : Valid_Uint; Right : Int) return Valid_Uint + renames UI_Add; + + function "/" (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint + renames UI_Div; + function "/" (Left : Int; Right : Nonzero_Uint) return Valid_Uint + renames UI_Div; + function "/" (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint + renames UI_Div; + + function "*" (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint + renames UI_Mul; + function "*" (Left : Int; Right : Valid_Uint) return Valid_Uint + renames UI_Mul; + function "*" (Left : Valid_Uint; Right : Int) return Valid_Uint + renames UI_Mul; + + function "-" (Left : Valid_Uint; Right : Valid_Uint) return Valid_Uint + renames UI_Sub; + function "-" (Left : Int; Right : Valid_Uint) return Valid_Uint + renames UI_Sub; + function "-" (Left : Valid_Uint; Right : Int) return Valid_Uint + renames UI_Sub; + + function "**" (Left : Valid_Uint; Right : Unat) return Valid_Uint + renames UI_Expon; + function "**" (Left : Valid_Uint; Right : Nat) return Valid_Uint + renames UI_Expon; + function "**" (Left : Int; Right : Unat) return Valid_Uint + renames UI_Expon; + function "**" (Left : Int; Right : Nat) return Valid_Uint + renames UI_Expon; + + function "abs" (Real : Valid_Uint) return Unat + renames UI_Abs; + + function "mod" (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint + renames UI_Mod; + function "mod" (Left : Int; Right : Nonzero_Uint) return Valid_Uint + renames UI_Mod; + function "mod" (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint + renames UI_Mod; + + function "rem" (Left : Valid_Uint; Right : Nonzero_Uint) return Valid_Uint + renames UI_Rem; + function "rem" (Left : Int; Right : Nonzero_Uint) return Valid_Uint + renames UI_Rem; + function "rem" (Left : Valid_Uint; Right : Nonzero_Int) return Valid_Uint + renames UI_Rem; + + function "-" (Real : Valid_Uint) return Valid_Uint + renames UI_Negate; + + function "=" (Left : Valid_Uint; Right : Valid_Uint) return Boolean + renames UI_Eq; + function "=" (Left : Int; Right : Valid_Uint) return Boolean + renames UI_Eq; + function "=" (Left : Valid_Uint; Right : Int) return Boolean + renames UI_Eq; + + function ">=" (Left : Valid_Uint; Right : Valid_Uint) return Boolean + renames UI_Ge; + function ">=" (Left : Int; Right : Valid_Uint) return Boolean + renames UI_Ge; + function ">=" (Left : Valid_Uint; Right : Int) return Boolean + renames UI_Ge; + + function ">" (Left : Valid_Uint; Right : Valid_Uint) return Boolean + renames UI_Gt; + function ">" (Left : Int; Right : Valid_Uint) return Boolean + renames UI_Gt; + function ">" (Left : Valid_Uint; Right : Int) return Boolean + renames UI_Gt; + + function "<=" (Left : Valid_Uint; Right : Valid_Uint) return Boolean + renames UI_Le; + function "<=" (Left : Int; Right : Valid_Uint) return Boolean + renames UI_Le; + function "<=" (Left : Valid_Uint; Right : Int) return Boolean + renames UI_Le; + + function "<" (Left : Valid_Uint; Right : Valid_Uint) return Boolean + renames UI_Lt; + function "<" (Left : Int; Right : Valid_Uint) return Boolean + renames UI_Lt; + function "<" (Left : Valid_Uint; Right : Int) return Boolean + renames UI_Lt; ----------------------------- -- Mark/Release Processing -- @@ -409,12 +422,12 @@ package Uintp is procedure Release (M : Save_Mark); -- Release storage allocated since mark was noted - procedure Release_And_Save (M : Save_Mark; UI : in out Uint); + procedure Release_And_Save (M : Save_Mark; UI : in out Valid_Uint); -- Like Release, except that the given Uint value (which is typically among -- the data being released) is recopied after the release, so that it is -- the most recent item, and UI is updated to point to its copied location. - procedure Release_And_Save (M : Save_Mark; UI1, UI2 : in out Uint); + procedure Release_And_Save (M : Save_Mark; UI1, UI2 : in out Valid_Uint); -- Like Release, except that the given Uint values (which are typically -- among the data being released) are recopied after the release, so that -- they are the most recent items, and UI1 and UI2 are updated if necessary @@ -518,7 +531,7 @@ private -- UI_Mul to efficiently compute the product in this case. type Save_Mark is record - Save_Uint : Uint; + Save_Uint : Valid_Uint; Save_Udigit : Int; end record; @@ -537,8 +550,9 @@ private -- Some subprograms defined in this package manipulate the Udigits table -- directly, while for others it is more convenient to work with locally -- defined arrays of the digits of the Universal Integers. The type - -- UI_Vector is defined for this purpose and some internal subprograms - -- used for converting from one to the other are defined. + -- UI_Vector is declared in the package body for this purpose and some + -- internal subprograms used for converting from one to the other are + -- defined. type Uint_Entry is record Length : aliased Pos; diff --git a/gcc/ada/usage.adb b/gcc/ada/usage.adb index c88ccec..bca3527 100644 --- a/gcc/ada/usage.adb +++ b/gcc/ada/usage.adb @@ -483,8 +483,10 @@ begin Write_Line (" .B turn off warnings for biased representation"); Write_Line (" c+ turn on warnings for constant conditional"); Write_Line (" C* turn off warnings for constant conditional"); - Write_Line (" .c+ turn on warnings for unrepped components"); - Write_Line (" .C* turn off warnings for unrepped components"); + Write_Line (" .c+ turn on warnings for components without " & + "representation clauses"); + Write_Line (" .C* turn off warnings for components without " & + "representation clauses"); Write_Line (" _c* turn on warnings for unknown " & "Compile_Time_Warning"); Write_Line (" _C turn off warnings for unknown " & diff --git a/gcc/attribs.c b/gcc/attribs.c index 0d22c20..83fafc9 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -1022,40 +1022,6 @@ common_function_versions (tree fn1, tree fn2) return result; } -/* Return a new name by appending SUFFIX to the DECL name. If make_unique - is true, append the full path name of the source file. */ - -char * -make_unique_name (tree decl, const char *suffix, bool make_unique) -{ - char *global_var_name; - int name_len; - const char *name; - const char *unique_name = NULL; - - name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); - - /* Get a unique name that can be used globally without any chances - of collision at link time. */ - if (make_unique) - unique_name = IDENTIFIER_POINTER (get_file_function_name ("\0")); - - name_len = strlen (name) + strlen (suffix) + 2; - - if (make_unique) - name_len += strlen (unique_name) + 1; - global_var_name = XNEWVEC (char, name_len); - - /* Use '.' to concatenate names as it is demangler friendly. */ - if (make_unique) - snprintf (global_var_name, name_len, "%s.%s.%s", name, unique_name, - suffix); - else - snprintf (global_var_name, name_len, "%s.%s", name, suffix); - - return global_var_name; -} - /* Make a dispatcher declaration for the multi-versioned function DECL. Calls to DECL function will be replaced with calls to the dispatcher by the front-end. Return the decl created. */ diff --git a/gcc/attribs.h b/gcc/attribs.h index 87231b9..138c509 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -44,7 +44,6 @@ extern struct scoped_attributes* register_scoped_attributes (const struct attrib extern char *sorted_attr_string (tree); extern bool common_function_versions (tree, tree); -extern char *make_unique_name (tree, const char *, bool); extern tree make_dispatcher_decl (const tree); extern bool is_function_default_version (const tree); diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index d4be236..9c59035 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,24 @@ +2021-09-20 Matthias Kretz <m.kretz@gsi.de> + + * c-cppbuiltin.c (c_cpp_builtins_optimize_pragma): Define or + undefine __RECIPROCAL_MATH__, __NO_SIGNED_ZEROS__, + __NO_TRAPPING_MATH__, __ASSOCIATIVE_MATH__, and + __ROUNDING_MATH__ according to the new optimization flags. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * c-omp.c (c_omp_split_clauses): Split order clause also to + distribute construct. Copy over OMP_CLAUSE_ORDER_UNCONSTRAINED. + +2021-09-17 Jakub Jelinek <jakub@redhat.com> + + * c-omp.c (c_finish_omp_atomic): Avoid creating + TARGET_EXPR if test is true, use create_tmp_var_raw instead of + create_tmp_var and add a zero initializer to TARGET_EXPRs that + had NULL initializer. When omitting operands after v = x, + use type of v rather than type of x. Fix type of vtmp + TARGET_EXPR. + 2021-09-13 Jason Merrill <jason@redhat.com> * c.opt: Add -Winterference-size. diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index ce88e70..a299273 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -628,6 +628,31 @@ c_cpp_builtins_optimize_pragma (cpp_reader *pfile, tree prev_tree, cpp_undef (pfile, "__FINITE_MATH_ONLY__"); cpp_define_unused (pfile, "__FINITE_MATH_ONLY__=0"); } + + if (!prev->x_flag_reciprocal_math && cur->x_flag_reciprocal_math) + cpp_define_unused (pfile, "__RECIPROCAL_MATH__"); + else if (prev->x_flag_reciprocal_math && !cur->x_flag_reciprocal_math) + cpp_undef (pfile, "__RECIPROCAL_MATH__"); + + if (!prev->x_flag_signed_zeros && cur->x_flag_signed_zeros) + cpp_undef (pfile, "__NO_SIGNED_ZEROS__"); + else if (prev->x_flag_signed_zeros && !cur->x_flag_signed_zeros) + cpp_define_unused (pfile, "__NO_SIGNED_ZEROS__"); + + if (!prev->x_flag_trapping_math && cur->x_flag_trapping_math) + cpp_undef (pfile, "__NO_TRAPPING_MATH__"); + else if (prev->x_flag_trapping_math && !cur->x_flag_trapping_math) + cpp_define_unused (pfile, "__NO_TRAPPING_MATH__"); + + if (!prev->x_flag_associative_math && cur->x_flag_associative_math) + cpp_define_unused (pfile, "__ASSOCIATIVE_MATH__"); + else if (prev->x_flag_associative_math && !cur->x_flag_associative_math) + cpp_undef (pfile, "__ASSOCIATIVE_MATH__"); + + if (!prev->x_flag_rounding_math && cur->x_flag_rounding_math) + cpp_define_unused (pfile, "__ROUNDING_MATH__"); + else if (prev->x_flag_rounding_math && !cur->x_flag_rounding_math) + cpp_undef (pfile, "__ROUNDING_MATH__"); } diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 476abc1..b606cf4 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -2114,14 +2114,31 @@ c_omp_split_clauses (location_t loc, enum tree_code code, } s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; - /* order clauses are allowed on for, simd and loop. */ + /* order clauses are allowed on distribute, for, simd and loop. */ case OMP_CLAUSE_ORDER: + if ((mask & (OMP_CLAUSE_MASK_1 + << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0) + { + if (code == OMP_DISTRIBUTE) + { + s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; + break; + } + c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), + OMP_CLAUSE_ORDER); + OMP_CLAUSE_ORDER_UNCONSTRAINED (c) + = OMP_CLAUSE_ORDER_UNCONSTRAINED (clauses); + OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; + cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE] = c; + } if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)) != 0) { if (code == OMP_SIMD) { c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), OMP_CLAUSE_ORDER); + OMP_CLAUSE_ORDER_UNCONSTRAINED (c) + = OMP_CLAUSE_ORDER_UNCONSTRAINED (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; cclauses[C_OMP_CLAUSE_SPLIT_FOR] = c; s = C_OMP_CLAUSE_SPLIT_SIMD; diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 28fe7bc..794cbe7 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,19 @@ +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_order): Parse unconstrained + and reproducible modifiers. + (OMP_DISTRIBUTE_CLAUSE_MASK): Add order clause. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_clause_default): Handle private and + firstprivate arguments, adjust diagnostics on unknown argument. + +2021-09-17 Jakub Jelinek <jakub@redhat.com> + + * c-parser.c (c_parser_omp_atomic): Reject atomic swap if capture + is true. + 2021-09-10 Jakub Jelinek <jakub@redhat.com> * c-parser.c (c_parser_conditional_expression): If omp_atomic_lhs and diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index eba9bbf..fb1399e 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -13420,6 +13420,9 @@ c_parser_omp_clause_copyprivate (c_parser *parser, tree list) /* OpenMP 2.5: default ( none | shared ) + OpenMP 5.1: + default ( private | firstprivate ) + OpenACC: default ( none | present ) */ @@ -13446,9 +13449,24 @@ c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) break; case 'p': - if (strcmp ("present", p) != 0 || !is_oacc) + if (is_oacc) + { + if (strcmp ("present", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_PRESENT; + } + else + { + if (strcmp ("private", p) != 0) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_PRIVATE; + } + break; + + case 'f': + if (strcmp ("firstprivate", p) != 0 || is_oacc) goto invalid_kind; - kind = OMP_CLAUSE_DEFAULT_PRESENT; + kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; break; case 's': @@ -13469,7 +13487,8 @@ c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc) if (is_oacc) c_parser_error (parser, "expected %<none%> or %<present%>"); else - c_parser_error (parser, "expected %<none%> or %<shared%>"); + c_parser_error (parser, "expected %<none%>, %<shared%>, " + "%<private%> or %<firstprivate%>"); } parens.skip_until_found_close (parser); @@ -14591,7 +14610,14 @@ c_parser_oacc_clause_wait (c_parser *parser, tree list) /* OpenMP 5.0: - order ( concurrent ) */ + order ( concurrent ) + + OpenMP 5.1: + order ( order-modifier : concurrent ) + + order-modifier: + reproducible + unconstrained */ static tree c_parser_omp_clause_order (c_parser *parser, tree list) @@ -14599,10 +14625,26 @@ c_parser_omp_clause_order (c_parser *parser, tree list) location_t loc = c_parser_peek_token (parser)->location; tree c; const char *p; + bool unconstrained = false; matching_parens parens; if (!parens.require_open (parser)) return list; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_COLON) + { + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "unconstrained") == 0) + unconstrained = true; + else if (strcmp (p, "reproducible") != 0) + { + c_parser_error (parser, "expected %<reproducible%> or " + "%<unconstrained%>"); + goto out_err; + } + c_parser_consume_token (parser); + c_parser_consume_token (parser); + } if (!c_parser_next_token_is (parser, CPP_NAME)) { c_parser_error (parser, "expected %<concurrent%>"); @@ -14616,8 +14658,9 @@ c_parser_omp_clause_order (c_parser *parser, tree list) } c_parser_consume_token (parser); parens.skip_until_found_close (parser); - /* check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order"); */ + check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order"); c = build_omp_clause (loc, OMP_CLAUSE_ORDER); + OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; OMP_CLAUSE_CHAIN (c) = list; return c; @@ -20231,7 +20274,8 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) static tree c_parser_omp_distribute (location_t loc, c_parser *parser, diff --git a/gcc/common/config/arm/arm-common.c b/gcc/common/config/arm/arm-common.c index 481aa9e..de898a7 100644 --- a/gcc/common/config/arm/arm-common.c +++ b/gcc/common/config/arm/arm-common.c @@ -115,7 +115,12 @@ const char * arm_rewrite_mcpu (int argc, const char **argv) { gcc_assert (argc); + +#ifdef HAVE_GAS_ARM_EXTENDED_ARCH + return argv[argc - 1]; +#else return arm_rewrite_selected_cpu (argv[argc - 1]); +#endif } /* Comparator for arm_rewrite_selected_arch. Compare the two arch extension @@ -223,7 +228,12 @@ const char * arm_rewrite_march (int argc, const char **argv) { gcc_assert (argc); + +#ifdef HAVE_GAS_ARM_EXTENDED_ARCH + return argv[argc - 1]; +#else return arm_rewrite_selected_arch (argv[argc - 1]); +#endif } #include "arm-cpu-cdata.h" diff --git a/gcc/config.gcc b/gcc/config.gcc index c3a8b27..498c51e 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -250,6 +250,8 @@ md_file= case ${target} in tile*-*-* \ | cr16-*-* \ + | hppa[12]*-*-hpux10* \ + | hppa[12]*-*-hpux11* \ ) if test "x$enable_obsolete" != xyes; then echo "*** Configuration ${target} is obsolete." >&2 diff --git a/gcc/config.in b/gcc/config.in index d8a810b..61cafe4 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1331,6 +1331,13 @@ #endif +/* Define if your Arm assembler permits context-specific feature extensions. + */ +#ifndef USED_FOR_TARGET +#undef HAVE_GAS_ARM_EXTENDED_ARCH +#endif + + /* Define if your assembler supports .balign and .p2align. */ #ifndef USED_FOR_TARGET #undef HAVE_GAS_BALIGN_AND_P2ALIGN diff --git a/gcc/config/avr/avr-mcus.def b/gcc/config/avr/avr-mcus.def index 37e4e9b..9b672e6 100644 --- a/gcc/config/avr/avr-mcus.def +++ b/gcc/config/avr/avr-mcus.def @@ -207,6 +207,7 @@ AVR_MCU ("atmega323", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega323__", AVR_MCU ("atmega324a", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega324A__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("atmega324p", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega324P__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("atmega324pa", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega324PA__", 0x0100, 0x0, 0x8000, 0) +AVR_MCU ("atmega324pb", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega324PB__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("atmega325", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega325__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("atmega325a", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega325A__", 0x0100, 0x0, 0x8000, 0) AVR_MCU ("atmega325p", ARCH_AVR5, AVR_ISA_NONE, "__AVR_ATmega325P__", 0x0100, 0x0, 0x8000, 0) diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index 6396586..50524a5 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -231,7 +231,7 @@ extern GTY(()) int darwin_ms_struct; %{%:sanitize(address): -lasan } \ %{%:sanitize(undefined): -lubsan } \ %(link_ssp) \ - %:version-compare(>< 10.6 10.7 mmacosx-version-min= -ld10-uwfef.o) \ + %:version-compare(>< 10.6 10.7 mmacosx-version-min= -ld10-uwfef) \ %(link_gcc_c_sequence) \ }}}\ %{!nostdlib:%{!r:%{!nostartfiles:%E}}} %{T*} %{F*} "\ diff --git a/gcc/config/gcn/gcn-protos.h b/gcc/config/gcn/gcn-protos.h index 5d62a84..2d385e0 100644 --- a/gcc/config/gcn/gcn-protos.h +++ b/gcc/config/gcn/gcn-protos.h @@ -41,7 +41,8 @@ extern bool gcn_global_address_p (rtx); extern tree gcn_goacc_adjust_private_decl (location_t, tree var, int level); extern tree gcn_goacc_create_worker_broadcast_record (tree record_type, bool sender, - const char *name); + const char *name, + unsigned HOST_WIDE_INT offset); extern void gcn_goacc_reduction (gcall *call); extern bool gcn_hard_regno_rename_ok (unsigned int from_reg, unsigned int to_reg); diff --git a/gcc/config/gcn/gcn-tree.c b/gcc/config/gcn/gcn-tree.c index f722d2d..d8b913b 100644 --- a/gcc/config/gcn/gcn-tree.c +++ b/gcc/config/gcn/gcn-tree.c @@ -309,7 +309,6 @@ static tree gcn_goacc_get_worker_red_decl (tree type, unsigned offset) { machine_function *machfun = cfun->machine; - tree existing_decl; if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); @@ -319,31 +318,12 @@ gcn_goacc_get_worker_red_decl (tree type, unsigned offset) (TYPE_QUALS (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS))); - if (machfun->reduc_decls - && offset < machfun->reduc_decls->length () - && (existing_decl = (*machfun->reduc_decls)[offset])) - { - gcc_assert (TREE_TYPE (existing_decl) == var_type); - return existing_decl; - } - else - { - char name[50]; - sprintf (name, ".oacc_reduction_%u", offset); - tree decl = create_tmp_var_raw (var_type, name); - - DECL_CONTEXT (decl) = NULL_TREE; - TREE_STATIC (decl) = 1; - - varpool_node::finalize_decl (decl); - - vec_safe_grow_cleared (machfun->reduc_decls, offset + 1, true); - (*machfun->reduc_decls)[offset] = decl; + gcc_assert (offset + < (machfun->reduction_limit - machfun->reduction_base)); + tree ptr_type = build_pointer_type (var_type); + tree addr = build_int_cst (ptr_type, machfun->reduction_base + offset); - return decl; - } - - return NULL_TREE; + return build_simple_mem_ref (addr); } /* Expand IFN_GOACC_REDUCTION_SETUP. */ @@ -500,7 +480,7 @@ gcn_goacc_reduction_teardown (gcall *call) } if (lhs) - gimplify_assign (lhs, var, &seq); + gimplify_assign (lhs, unshare_expr (var), &seq); pop_gimplify_context (NULL); @@ -581,27 +561,24 @@ gcn_goacc_adjust_private_decl (location_t, tree var, int level) tree gcn_goacc_create_worker_broadcast_record (tree record_type, bool sender, - const char *name) + const char *name, + unsigned HOST_WIDE_INT offset) { - tree type = record_type; - - TYPE_ADDR_SPACE (type) = ADDR_SPACE_LDS; + tree type = build_qualified_type (record_type, + TYPE_QUALS_NO_ADDR_SPACE (record_type) + | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_LDS)); if (!sender) - type = build_pointer_type (type); - - tree decl = create_tmp_var_raw (type, name); - - if (sender) { - DECL_CONTEXT (decl) = NULL_TREE; - TREE_STATIC (decl) = 1; + tree ptr_type = build_pointer_type (type); + return create_tmp_var_raw (ptr_type, name); } - if (sender) - varpool_node::finalize_decl (decl); + if (record_type == char_type_node) + offset = 1; - return decl; + tree ptr_type = build_pointer_type (type); + return build_int_cst (ptr_type, offset); } /* }}} */ diff --git a/gcc/config/gcn/gcn.c b/gcc/config/gcn/gcn.c index 9df2827..2a3fc96 100644 --- a/gcc/config/gcn/gcn.c +++ b/gcc/config/gcn/gcn.c @@ -51,6 +51,7 @@ #include "intl.h" #include "rtl-iter.h" #include "dwarf2.h" +#include "gimple.h" /* This file should be included last. */ #include "target-def.h" @@ -73,14 +74,21 @@ int gcn_isa = 3; /* Default to GCN3. */ We want to permit full occupancy, so size accordingly. */ +/* Use this as a default, but allow it to grow if the user requests a large + amount of gang-private shared-memory space. */ +static int acc_lds_size = 0x600; + #define OMP_LDS_SIZE 0x600 /* 0x600 is 1/40 total, rounded down. */ -#define ACC_LDS_SIZE 32768 /* Half of the total should be fine. */ +#define ACC_LDS_SIZE acc_lds_size #define OTHER_LDS_SIZE 65536 /* If in doubt, reserve all of it. */ #define LDS_SIZE (flag_openacc ? ACC_LDS_SIZE \ : flag_openmp ? OMP_LDS_SIZE \ : OTHER_LDS_SIZE) +static int gang_private_hwm = 32; +static hash_map<tree, int> lds_allocs; + /* The number of registers usable by normal non-kernel functions. The SGPR count includes any special extra registers such as VCC. */ @@ -99,13 +107,6 @@ gcn_init_machine_status (void) f = ggc_cleared_alloc<machine_function> (); - /* Set up LDS allocation for broadcasting for this function. */ - f->lds_allocated = 32; - f->lds_allocs = hash_map<tree, int>::create_ggc (64); - - /* And LDS temporary decls for worker reductions. */ - vec_alloc (f->reduc_decls, 0); - if (TARGET_GCN3) f->use_flat_addressing = true; @@ -145,6 +146,24 @@ gcn_option_override (void) stack_size_opt = 1048576; } + /* Reserve 1Kb (somewhat arbitrarily) of LDS space for reduction results and + worker broadcasts. */ + if (gang_private_size_opt == -1) + gang_private_size_opt = 512; + else if (gang_private_size_opt < gang_private_hwm) + gang_private_size_opt = gang_private_hwm; + else if (gang_private_size_opt >= acc_lds_size - 1024) + { + /* We need some space for reductions and worker broadcasting. If the + user requests a large amount of gang-private LDS space, we might not + have enough left for the former. Increase the LDS allocation in that + case, although this may reduce the maximum occupancy on the + hardware. */ + acc_lds_size = gang_private_size_opt + 1024; + if (acc_lds_size > 32768) + acc_lds_size = 32768; + } + /* The xnack option is a placeholder, for now. */ if (flag_xnack) sorry ("XNACK support"); @@ -3066,7 +3085,7 @@ gcn_expand_prologue () The low-part is the address of the topmost addressable byte, which is size-1. The high-part is an offset and should be zero. */ emit_move_insn (gen_rtx_REG (SImode, M0_REG), - gen_int_mode (LDS_SIZE-1, SImode)); + gen_int_mode (LDS_SIZE, SImode)); emit_insn (gen_prologue_use (gen_rtx_REG (SImode, M0_REG))); @@ -5115,10 +5134,14 @@ gcn_oacc_dim_pos (int dim) /* Implement TARGET_GOACC_FORK_JOIN. */ static bool -gcn_fork_join (gcall *ARG_UNUSED (call), const int *ARG_UNUSED (dims), - bool ARG_UNUSED (is_fork)) +gcn_fork_join (gcall *call, const int dims[], bool is_fork) { - /* GCN does not need to expand fork/join markers at the RTL level. */ + tree arg = gimple_call_arg (call, 2); + unsigned axis = TREE_INT_CST_LOW (arg); + + if (!is_fork && axis == GOMP_DIM_WORKER && dims[axis] != 1) + return true; + return false; } @@ -5161,6 +5184,28 @@ gcn_fixup_accel_lto_options (tree fndecl) } } +/* Implement TARGET_GOACC_SHARED_MEM_LAYOUT hook. */ + +static void +gcn_shared_mem_layout (unsigned HOST_WIDE_INT *lo, + unsigned HOST_WIDE_INT *hi, + int ARG_UNUSED (dims[GOMP_DIM_MAX]), + unsigned HOST_WIDE_INT + ARG_UNUSED (private_size[GOMP_DIM_MAX]), + unsigned HOST_WIDE_INT reduction_size[GOMP_DIM_MAX]) +{ + *lo = gang_private_size_opt + reduction_size[GOMP_DIM_WORKER]; + /* !!! We can maybe use dims[] to estimate the maximum number of work + groups/wavefronts/etc. we will launch, and therefore tune the maximum + amount of LDS we should use. For now, use a minimal amount to try to + maximise occupancy. */ + *hi = acc_lds_size; + machine_function *machfun = cfun->machine; + machfun->reduction_base = gang_private_size_opt; + machfun->reduction_limit + = gang_private_size_opt + reduction_size[GOMP_DIM_WORKER]; +} + /* }}} */ /* {{{ ASM Output. */ @@ -5488,17 +5533,18 @@ gcn_section_type_flags (tree decl, const char *name, int reloc) /* Helper function for gcn_asm_output_symbol_ref. - FIXME: If we want to have propagation blocks allocated separately and - statically like this, it would be better done via symbol refs and the - assembler/linker. This is a temporary hack. */ + FIXME: This function is used to lay out gang-private variables in LDS + on a per-CU basis. + There may be cases in which gang-private variables in different compilation + units could clobber each other. In that case we should be relying on the + linker to lay out gang-private LDS space, but that doesn't appear to be + possible at present. */ static void gcn_print_lds_decl (FILE *f, tree var) { int *offset; - machine_function *machfun = cfun->machine; - - if ((offset = machfun->lds_allocs->get (var))) + if ((offset = lds_allocs.get (var))) fprintf (f, "%u", (unsigned) *offset); else { @@ -5508,14 +5554,14 @@ gcn_print_lds_decl (FILE *f, tree var) if (size > align && size > 4 && align < 8) align = 8; - machfun->lds_allocated = ((machfun->lds_allocated + align - 1) - & ~(align - 1)); + gang_private_hwm = ((gang_private_hwm + align - 1) & ~(align - 1)); - machfun->lds_allocs->put (var, machfun->lds_allocated); - fprintf (f, "%u", machfun->lds_allocated); - machfun->lds_allocated += size; - if (machfun->lds_allocated > LDS_SIZE) - error ("local data-share memory exhausted"); + lds_allocs.put (var, gang_private_hwm); + fprintf (f, "%u", gang_private_hwm); + gang_private_hwm += size; + if (gang_private_hwm > gang_private_size_opt) + error ("gang-private data-share memory exhausted (increase with " + "%<-mgang-private-size=<number>%>)"); } } @@ -6515,6 +6561,8 @@ gcn_dwarf_register_span (rtx rtl) #define TARGET_GOACC_REDUCTION gcn_goacc_reduction #undef TARGET_GOACC_VALIDATE_DIMS #define TARGET_GOACC_VALIDATE_DIMS gcn_goacc_validate_dims +#undef TARGET_GOACC_SHARED_MEM_LAYOUT +#define TARGET_GOACC_SHARED_MEM_LAYOUT gcn_shared_mem_layout #undef TARGET_HARD_REGNO_MODE_OK #define TARGET_HARD_REGNO_MODE_OK gcn_hard_regno_mode_ok #undef TARGET_HARD_REGNO_NREGS diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index 5822ec3..b97ec48 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -576,10 +576,8 @@ struct GTY(()) machine_function HOST_WIDE_INT local_vars; HOST_WIDE_INT callee_saves; - unsigned lds_allocated; - hash_map<tree, int> *lds_allocs; - - vec<tree, va_gc> *reduc_decls; + unsigned HOST_WIDE_INT reduction_base; + unsigned HOST_WIDE_INT reduction_limit; bool use_flat_addressing; }; diff --git a/gcc/config/gcn/gcn.opt b/gcc/config/gcn/gcn.opt index 6faacca..09cf191 100644 --- a/gcc/config/gcn/gcn.opt +++ b/gcc/config/gcn/gcn.opt @@ -68,6 +68,12 @@ mstack-size= Target RejectNegative Joined UInteger Var(stack_size_opt) Init(-1) -mstack-size=<number> Set the private segment size per wave-front, in bytes. +int gang_private_size_opt = -1 + +mgang-private-size= +Target RejectNegative Joined UInteger Var(gang_private_size_opt) Init(-1) +Amount of local data-share (LDS) memory to reserve for gang-private variables. + Wopenacc-dims Target Var(warn_openacc_dims) Warning Warn about invalid OpenACC dimensions. diff --git a/gcc/config/i386/avx512fp16intrin.h b/gcc/config/i386/avx512fp16intrin.h index a5041ed..4714696 100644 --- a/gcc/config/i386/avx512fp16intrin.h +++ b/gcc/config/i386/avx512fp16intrin.h @@ -5043,6 +5043,1078 @@ _mm_maskz_cvt_roundsd_sh (__mmask8 __A, __m128h __B, __m128d __C, #endif /* __OPTIMIZE__ */ +/* Intrinsics vfmaddsub[132,213,231]ph. */ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fmaddsub_ph (__m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmaddsub_ph (__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmaddsub_ph (__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmaddsub_ph (__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __OPTIMIZE__ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fmaddsub_round_ph (__m512h __A, __m512h __B, __m512h __C, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmaddsub_round_ph (__m512h __A, __mmask32 __U, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmaddsub_round_ph (__m512h __A, __m512h __B, __m512h __C, + __mmask32 __U, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmaddsub_round_ph (__mmask32 __U, __m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmaddsubph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +#else +#define _mm512_fmaddsub_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask ((A), (B), (C), -1, (R))) + +#define _mm512_mask_fmaddsub_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask ((A), (B), (C), (U), (R))) + +#define _mm512_mask3_fmaddsub_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask3 ((A), (B), (C), (U), (R))) + +#define _mm512_maskz_fmaddsub_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfmsubadd[132,213,231]ph. */ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) + _mm512_fmsubadd_ph (__m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmsubadd_ph (__m512h __A, __mmask32 __U, + __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmsubadd_ph (__m512h __A, __m512h __B, + __m512h __C, __mmask32 __U) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmsubadd_ph (__mmask32 __U, __m512h __A, + __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __OPTIMIZE__ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fmsubadd_round_ph (__m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmsubadd_round_ph (__m512h __A, __mmask32 __U, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmsubadd_round_ph (__m512h __A, __m512h __B, __m512h __C, + __mmask32 __U, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmsubadd_round_ph (__mmask32 __U, __m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) + __builtin_ia32_vfmsubaddph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +#else +#define _mm512_fmsubadd_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmsubaddph512_mask ((A), (B), (C), -1, (R))) + +#define _mm512_mask_fmsubadd_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmsubaddph512_mask ((A), (B), (C), (U), (R))) + +#define _mm512_mask3_fmsubadd_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmsubaddph512_mask3 ((A), (B), (C), (U), (R))) + +#define _mm512_maskz_fmsubadd_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmsubaddph512_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfmadd[132,213,231]ph. */ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) + _mm512_fmadd_ph (__m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmadd_ph (__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmadd_ph (__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) +{ + return (__m512h) + __builtin_ia32_vfmaddph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmadd_ph (__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmaddph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __OPTIMIZE__ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fmadd_round_ph (__m512h __A, __m512h __B, __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmadd_round_ph (__m512h __A, __mmask32 __U, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmadd_round_ph (__m512h __A, __m512h __B, __m512h __C, + __mmask32 __U, const int __R) +{ + return (__m512h) __builtin_ia32_vfmaddph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmadd_round_ph (__mmask32 __U, __m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfmaddph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +#else +#define _mm512_fmadd_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask ((A), (B), (C), -1, (R))) + +#define _mm512_mask_fmadd_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask ((A), (B), (C), (U), (R))) + +#define _mm512_mask3_fmadd_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask3 ((A), (B), (C), (U), (R))) + +#define _mm512_maskz_fmadd_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfnmadd[132,213,231]ph. */ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fnmadd_ph (__m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfnmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fnmadd_ph (__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfnmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fnmadd_ph (__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) +{ + return (__m512h) + __builtin_ia32_vfnmaddph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fnmadd_ph (__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfnmaddph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __OPTIMIZE__ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fnmadd_round_ph (__m512h __A, __m512h __B, __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fnmadd_round_ph (__m512h __A, __mmask32 __U, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmaddph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fnmadd_round_ph (__m512h __A, __m512h __B, __m512h __C, + __mmask32 __U, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmaddph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fnmadd_round_ph (__mmask32 __U, __m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmaddph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +#else +#define _mm512_fnmadd_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfnmaddph512_mask ((A), (B), (C), -1, (R))) + +#define _mm512_mask_fnmadd_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfnmaddph512_mask ((A), (B), (C), (U), (R))) + +#define _mm512_mask3_fnmadd_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfnmaddph512_mask3 ((A), (B), (C), (U), (R))) + +#define _mm512_maskz_fnmadd_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfnmaddph512_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfmsub[132,213,231]ph. */ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fmsub_ph (__m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmsub_ph (__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmsub_ph (__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) +{ + return (__m512h) + __builtin_ia32_vfmsubph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmsub_ph (__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfmsubph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __OPTIMIZE__ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fmsub_round_ph (__m512h __A, __m512h __B, __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fmsub_round_ph (__m512h __A, __mmask32 __U, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fmsub_round_ph (__m512h __A, __m512h __B, __m512h __C, + __mmask32 __U, const int __R) +{ + return (__m512h) __builtin_ia32_vfmsubph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fmsub_round_ph (__mmask32 __U, __m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfmsubph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +#else +#define _mm512_fmsub_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmsubph512_mask ((A), (B), (C), -1, (R))) + +#define _mm512_mask_fmsub_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmsubph512_mask ((A), (B), (C), (U), (R))) + +#define _mm512_mask3_fmsub_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmsubph512_mask3 ((A), (B), (C), (U), (R))) + +#define _mm512_maskz_fmsub_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmsubph512_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfnmsub[132,213,231]ph. */ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fnmsub_ph (__m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfnmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fnmsub_ph (__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfnmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fnmsub_ph (__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) +{ + return (__m512h) + __builtin_ia32_vfnmsubph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fnmsub_ph (__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) +{ + return (__m512h) + __builtin_ia32_vfnmsubph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __OPTIMIZE__ +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_fnmsub_round_ph (__m512h __A, __m512h __B, __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) -1, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask_fnmsub_round_ph (__m512h __A, __mmask32 __U, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmsubph512_mask ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_mask3_fnmsub_round_ph (__m512h __A, __m512h __B, __m512h __C, + __mmask32 __U, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmsubph512_mask3 ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +extern __inline __m512h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm512_maskz_fnmsub_round_ph (__mmask32 __U, __m512h __A, __m512h __B, + __m512h __C, const int __R) +{ + return (__m512h) __builtin_ia32_vfnmsubph512_maskz ((__v32hf) __A, + (__v32hf) __B, + (__v32hf) __C, + (__mmask32) __U, __R); +} + +#else +#define _mm512_fnmsub_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfnmsubph512_mask ((A), (B), (C), -1, (R))) + +#define _mm512_mask_fnmsub_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfnmsubph512_mask ((A), (B), (C), (U), (R))) + +#define _mm512_mask3_fnmsub_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfnmsubph512_mask3 ((A), (B), (C), (U), (R))) + +#define _mm512_maskz_fnmsub_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfnmsubph512_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfmadd[132,213,231]sh. */ +extern __inline __m128h + __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmadd_sh (__m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmadd_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmadd_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask3 ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmadd_sh (__mmask8 __U, __m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_maskz ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + + +#ifdef __OPTIMIZE__ +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmadd_round_sh (__m128h __W, __m128h __A, __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) -1, + __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmadd_round_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B, + const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmadd_round_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U, + const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask3 ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmadd_round_sh (__mmask8 __U, __m128h __W, __m128h __A, + __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_maskz ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +#else +#define _mm_fmadd_round_sh(A, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask ((A), (B), (C), (-1), (R))) +#define _mm_mask_fmadd_round_sh(A, U, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask ((A), (B), (C), (U), (R))) +#define _mm_mask3_fmadd_round_sh(A, B, C, U, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask3 ((A), (B), (C), (U), (R))) +#define _mm_maskz_fmadd_round_sh(U, A, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfnmadd[132,213,231]sh. */ +extern __inline __m128h + __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fnmadd_sh (__m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fnmadd_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fnmadd_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_mask3 ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fnmadd_sh (__mmask8 __U, __m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_maskz ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + + +#ifdef __OPTIMIZE__ +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fnmadd_round_sh (__m128h __W, __m128h __A, __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) -1, + __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fnmadd_round_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B, + const int __R) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fnmadd_round_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U, + const int __R) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_mask3 ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fnmadd_round_sh (__mmask8 __U, __m128h __W, __m128h __A, + __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfnmaddsh3_maskz ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +#else +#define _mm_fnmadd_round_sh(A, B, C, R) \ + ((__m128h) __builtin_ia32_vfnmaddsh3_mask ((A), (B), (C), (-1), (R))) +#define _mm_mask_fnmadd_round_sh(A, U, B, C, R) \ + ((__m128h) __builtin_ia32_vfnmaddsh3_mask ((A), (B), (C), (U), (R))) +#define _mm_mask3_fnmadd_round_sh(A, B, C, U, R) \ + ((__m128h) __builtin_ia32_vfnmaddsh3_mask3 ((A), (B), (C), (U), (R))) +#define _mm_maskz_fnmadd_round_sh(U, A, B, C, R) \ + ((__m128h) __builtin_ia32_vfnmaddsh3_maskz ((A), (B), (C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfmsub[132,213,231]sh. */ +extern __inline __m128h + __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmsub_sh (__m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + -(__v8hf) __B, + (__mmask8) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmsub_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmsub_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmsubsh3_mask3 ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmsub_sh (__mmask8 __U, __m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_maskz ((__v8hf) __W, + (__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + + +#ifdef __OPTIMIZE__ +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmsub_round_sh (__m128h __W, __m128h __A, __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + -(__v8hf) __B, + (__mmask8) -1, + __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmsub_round_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B, + const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + (__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmsub_round_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U, + const int __R) +{ + return (__m128h) __builtin_ia32_vfmsubsh3_mask3 ((__v8hf) __W, + (__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmsub_round_sh (__mmask8 __U, __m128h __W, __m128h __A, + __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_maskz ((__v8hf) __W, + (__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, __R); +} + +#else +#define _mm_fmsub_round_sh(A, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask ((A), (B), -(C), (-1), (R))) +#define _mm_mask_fmsub_round_sh(A, U, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask ((A), (B), -(C), (U), (R))) +#define _mm_mask3_fmsub_round_sh(A, B, C, U, R) \ + ((__m128h) __builtin_ia32_vfmsubsh3_mask3 ((A), (B), (C), (U), (R))) +#define _mm_maskz_fmsub_round_sh(U, A, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_maskz ((A), (B), -(C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + +/* Intrinsics vfnmsub[132,213,231]sh. */ +extern __inline __m128h + __attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fnmsub_sh (__m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + -(__v8hf) __A, + -(__v8hf) __B, + (__mmask8) -1, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fnmsub_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + -(__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fnmsub_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmsubsh3_mask3 ((__v8hf) __W, + -(__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fnmsub_sh (__mmask8 __U, __m128h __W, __m128h __A, __m128h __B) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_maskz ((__v8hf) __W, + -(__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, + _MM_FROUND_CUR_DIRECTION); +} + + +#ifdef __OPTIMIZE__ +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fnmsub_round_sh (__m128h __W, __m128h __A, __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + -(__v8hf) __A, + -(__v8hf) __B, + (__mmask8) -1, + __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fnmsub_round_sh (__m128h __W, __mmask8 __U, __m128h __A, __m128h __B, + const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_mask ((__v8hf) __W, + -(__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fnmsub_round_sh (__m128h __W, __m128h __A, __m128h __B, __mmask8 __U, + const int __R) +{ + return (__m128h) __builtin_ia32_vfmsubsh3_mask3 ((__v8hf) __W, + -(__v8hf) __A, + (__v8hf) __B, + (__mmask8) __U, __R); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fnmsub_round_sh (__mmask8 __U, __m128h __W, __m128h __A, + __m128h __B, const int __R) +{ + return (__m128h) __builtin_ia32_vfmaddsh3_maskz ((__v8hf) __W, + -(__v8hf) __A, + -(__v8hf) __B, + (__mmask8) __U, __R); +} + +#else +#define _mm_fnmsub_round_sh(A, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask ((A), -(B), -(C), (-1), (R))) +#define _mm_mask_fnmsub_round_sh(A, U, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_mask ((A), -(B), -(C), (U), (R))) +#define _mm_mask3_fnmsub_round_sh(A, B, C, U, R) \ + ((__m128h) __builtin_ia32_vfmsubsh3_mask3 ((A), -(B), (C), (U), (R))) +#define _mm_maskz_fnmsub_round_sh(U, A, B, C, R) \ + ((__m128h) __builtin_ia32_vfmaddsh3_maskz ((A), -(B), -(C), (U), (R))) + +#endif /* __OPTIMIZE__ */ + #ifdef __DISABLE_AVX512FP16__ #undef __DISABLE_AVX512FP16__ #pragma GCC pop_options diff --git a/gcc/config/i386/avx512fp16vlintrin.h b/gcc/config/i386/avx512fp16vlintrin.h index 59906d2..1292c02 100644 --- a/gcc/config/i386/avx512fp16vlintrin.h +++ b/gcc/config/i386/avx512fp16vlintrin.h @@ -2269,6 +2269,552 @@ _mm256_maskz_cvtpd_ph (__mmask8 __A, __m256d __B) __A); } +/* Intrinsics vfmaddsub[132,213,231]ph. */ +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_fmaddsub_ph (__m256h __A, __m256h __B, __m256h __C) +{ + return (__m256h)__builtin_ia32_vfmaddsubph256_mask ((__v16hf)__A, + (__v16hf)__B, + (__v16hf)__C, + (__mmask16)-1); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask_fmaddsub_ph (__m256h __A, __mmask16 __U, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmaddsubph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask3_fmaddsub_ph (__m256h __A, __m256h __B, __m256h __C, + __mmask16 __U) +{ + return (__m256h) __builtin_ia32_vfmaddsubph256_mask3 ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_maskz_fmaddsub_ph (__mmask16 __U, __m256h __A, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmaddsubph256_maskz ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmaddsub_ph (__m128h __A, __m128h __B, __m128h __C) +{ + return (__m128h)__builtin_ia32_vfmaddsubph128_mask ((__v8hf)__A, + (__v8hf)__B, + (__v8hf)__C, + (__mmask8)-1); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmaddsub_ph (__m128h __A, __mmask8 __U, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmaddsubph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmaddsub_ph (__m128h __A, __m128h __B, __m128h __C, + __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmaddsubph128_mask3 ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmaddsub_ph (__mmask8 __U, __m128h __A, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmaddsubph128_maskz ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +/* Intrinsics vfmsubadd[132,213,231]ph. */ +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_fmsubadd_ph (__m256h __A, __m256h __B, __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmsubaddph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) -1); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask_fmsubadd_ph (__m256h __A, __mmask16 __U, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmsubaddph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask3_fmsubadd_ph (__m256h __A, __m256h __B, __m256h __C, + __mmask16 __U) +{ + return (__m256h) __builtin_ia32_vfmsubaddph256_mask3 ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_maskz_fmsubadd_ph (__mmask16 __U, __m256h __A, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmsubaddph256_maskz ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmsubadd_ph (__m128h __A, __m128h __B, __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmsubaddph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) -1); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmsubadd_ph (__m128h __A, __mmask8 __U, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmsubaddph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmsubadd_ph (__m128h __A, __m128h __B, __m128h __C, + __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmsubaddph128_mask3 ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmsubadd_ph (__mmask8 __U, __m128h __A, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmsubaddph128_maskz ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +/* Intrinsics vfmadd[132,213,231]ph. */ +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_fmadd_ph (__m256h __A, __m256h __B, __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmaddph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) -1); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask_fmadd_ph (__m256h __A, __mmask16 __U, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmaddph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask3_fmadd_ph (__m256h __A, __m256h __B, __m256h __C, + __mmask16 __U) +{ + return (__m256h) __builtin_ia32_vfmaddph256_mask3 ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_maskz_fmadd_ph (__mmask16 __U, __m256h __A, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmaddph256_maskz ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmadd_ph (__m128h __A, __m128h __B, __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmaddph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) -1); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmadd_ph (__m128h __A, __mmask8 __U, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmaddph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmadd_ph (__m128h __A, __m128h __B, __m128h __C, + __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmaddph128_mask3 ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmadd_ph (__mmask8 __U, __m128h __A, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmaddph128_maskz ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +/* Intrinsics vfnmadd[132,213,231]ph. */ +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_fnmadd_ph (__m256h __A, __m256h __B, __m256h __C) +{ + return (__m256h) __builtin_ia32_vfnmaddph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) -1); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask_fnmadd_ph (__m256h __A, __mmask16 __U, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfnmaddph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask3_fnmadd_ph (__m256h __A, __m256h __B, __m256h __C, + __mmask16 __U) +{ + return (__m256h) __builtin_ia32_vfnmaddph256_mask3 ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_maskz_fnmadd_ph (__mmask16 __U, __m256h __A, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfnmaddph256_maskz ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fnmadd_ph (__m128h __A, __m128h __B, __m128h __C) +{ + return (__m128h) __builtin_ia32_vfnmaddph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) -1); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fnmadd_ph (__m128h __A, __mmask8 __U, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfnmaddph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fnmadd_ph (__m128h __A, __m128h __B, __m128h __C, + __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfnmaddph128_mask3 ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fnmadd_ph (__mmask8 __U, __m128h __A, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfnmaddph128_maskz ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +/* Intrinsics vfmsub[132,213,231]ph. */ +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_fmsub_ph (__m256h __A, __m256h __B, __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmsubph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) -1); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask_fmsub_ph (__m256h __A, __mmask16 __U, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmsubph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask3_fmsub_ph (__m256h __A, __m256h __B, __m256h __C, + __mmask16 __U) +{ + return (__m256h) __builtin_ia32_vfmsubph256_mask3 ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_maskz_fmsub_ph (__mmask16 __U, __m256h __A, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfmsubph256_maskz ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fmsub_ph (__m128h __A, __m128h __B, __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmsubph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) -1); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fmsub_ph (__m128h __A, __mmask8 __U, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmsubph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fmsub_ph (__m128h __A, __m128h __B, __m128h __C, + __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfmsubph128_mask3 ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fmsub_ph (__mmask8 __U, __m128h __A, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfmsubph128_maskz ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +/* Intrinsics vfnmsub[132,213,231]ph. */ +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_fnmsub_ph (__m256h __A, __m256h __B, __m256h __C) +{ + return (__m256h) __builtin_ia32_vfnmsubph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) -1); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask_fnmsub_ph (__m256h __A, __mmask16 __U, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfnmsubph256_mask ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_mask3_fnmsub_ph (__m256h __A, __m256h __B, __m256h __C, + __mmask16 __U) +{ + return (__m256h) __builtin_ia32_vfnmsubph256_mask3 ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m256h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_maskz_fnmsub_ph (__mmask16 __U, __m256h __A, __m256h __B, + __m256h __C) +{ + return (__m256h) __builtin_ia32_vfnmsubph256_maskz ((__v16hf) __A, + (__v16hf) __B, + (__v16hf) __C, + (__mmask16) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_fnmsub_ph (__m128h __A, __m128h __B, __m128h __C) +{ + return (__m128h) __builtin_ia32_vfnmsubph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) -1); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask_fnmsub_ph (__m128h __A, __mmask8 __U, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfnmsubph128_mask ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_mask3_fnmsub_ph (__m128h __A, __m128h __B, __m128h __C, + __mmask8 __U) +{ + return (__m128h) __builtin_ia32_vfnmsubph128_mask3 ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + +extern __inline __m128h +__attribute__ ((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maskz_fnmsub_ph (__mmask8 __U, __m128h __A, __m128h __B, + __m128h __C) +{ + return (__m128h) __builtin_ia32_vfnmsubph128_maskz ((__v8hf) __A, + (__v8hf) __B, + (__v8hf) __C, + (__mmask8) + __U); +} + #ifdef __DISABLE_AVX512FP16VL__ #undef __DISABLE_AVX512FP16VL__ #pragma GCC pop_options diff --git a/gcc/config/i386/i386-builtin-types.def b/gcc/config/i386/i386-builtin-types.def index 7fd4286..5eae4d0 100644 --- a/gcc/config/i386/i386-builtin-types.def +++ b/gcc/config/i386/i386-builtin-types.def @@ -1342,6 +1342,7 @@ DEF_FUNCTION_TYPE (V8HF, V8HF, V8HF, INT) DEF_FUNCTION_TYPE (V8HF, V8HF, INT, V8HF, UQI) DEF_FUNCTION_TYPE (UQI, V8HF, V8HF, INT, UQI) DEF_FUNCTION_TYPE (V8HF, V8HF, V8HF, V8HF, UQI) +DEF_FUNCTION_TYPE (V8HF, V8HF, V8HF, V8HF, INT) DEF_FUNCTION_TYPE (UQI, V8HF, V8HF, INT, UQI, INT) DEF_FUNCTION_TYPE (V8DI, V8HF, V8DI, UQI, INT) DEF_FUNCTION_TYPE (V8DF, V8HF, V8DF, UQI, INT) diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def index dc56dc2..5950d5e 100644 --- a/gcc/config/i386/i386-builtin.def +++ b/gcc/config/i386/i386-builtin.def @@ -2875,6 +2875,42 @@ BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp1 BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtps2ph_v8sf_mask, "__builtin_ia32_vcvtps2phx256_mask", IX86_BUILTIN_VCVTPS2PHX256_MASK, UNKNOWN, (int) V8HF_FTYPE_V8SF_V8HF_UQI) BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtpd2ph_v2df_mask, "__builtin_ia32_vcvtpd2ph128_mask", IX86_BUILTIN_VCVTPD2PH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V2DF_V8HF_UQI) BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtpd2ph_v4df_mask, "__builtin_ia32_vcvtpd2ph256_mask", IX86_BUILTIN_VCVTPD2PH256_MASK, UNKNOWN, (int) V8HF_FTYPE_V4DF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmaddsub_v16hf_mask, "__builtin_ia32_vfmaddsubph256_mask", IX86_BUILTIN_VFMADDSUBPH256_MASK, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmaddsub_v16hf_mask3, "__builtin_ia32_vfmaddsubph256_mask3", IX86_BUILTIN_VFMADDSUBPH256_MASK3, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmaddsub_v16hf_maskz, "__builtin_ia32_vfmaddsubph256_maskz", IX86_BUILTIN_VFMADDSUBPH256_MASKZ, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmaddsub_v8hf_mask, "__builtin_ia32_vfmaddsubph128_mask", IX86_BUILTIN_VFMADDSUBPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmaddsub_v8hf_mask3, "__builtin_ia32_vfmaddsubph128_mask3", IX86_BUILTIN_VFMADDSUBPH128_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmaddsub_v8hf_maskz, "__builtin_ia32_vfmaddsubph128_maskz", IX86_BUILTIN_VFMADDSUBPH128_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmsubadd_v16hf_mask, "__builtin_ia32_vfmsubaddph256_mask", IX86_BUILTIN_VFMSUBADDPH256_MASK, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmsubadd_v16hf_mask3, "__builtin_ia32_vfmsubaddph256_mask3", IX86_BUILTIN_VFMSUBADDPH256_MASK3, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmsubadd_v16hf_maskz, "__builtin_ia32_vfmsubaddph256_maskz", IX86_BUILTIN_VFMSUBADDPH256_MASKZ, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmsubadd_v8hf_mask, "__builtin_ia32_vfmsubaddph128_mask", IX86_BUILTIN_VFMSUBADDPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmsubadd_v8hf_mask3, "__builtin_ia32_vfmsubaddph128_mask3", IX86_BUILTIN_VFMSUBADDPH128_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmsubadd_v8hf_maskz, "__builtin_ia32_vfmsubaddph128_maskz", IX86_BUILTIN_VFMSUBADDPH128_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmadd_v16hf_mask, "__builtin_ia32_vfmaddph256_mask", IX86_BUILTIN_VFMADDPH256_MASK, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmadd_v16hf_mask3, "__builtin_ia32_vfmaddph256_mask3", IX86_BUILTIN_VFMADDPH256_MASK3, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmadd_v16hf_maskz, "__builtin_ia32_vfmaddph256_maskz", IX86_BUILTIN_VFMADDPH256_MASKZ, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmadd_v8hf_mask, "__builtin_ia32_vfmaddph128_mask", IX86_BUILTIN_VFMADDPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmadd_v8hf_mask3, "__builtin_ia32_vfmaddph128_mask3", IX86_BUILTIN_VFMADDPH128_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmadd_v8hf_maskz, "__builtin_ia32_vfmaddph128_maskz", IX86_BUILTIN_VFMADDPH128_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fnmadd_v16hf_mask, "__builtin_ia32_vfnmaddph256_mask", IX86_BUILTIN_VFNMADDPH256_MASK, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fnmadd_v16hf_mask3, "__builtin_ia32_vfnmaddph256_mask3", IX86_BUILTIN_VFNMADDPH256_MASK3, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fnmadd_v16hf_maskz, "__builtin_ia32_vfnmaddph256_maskz", IX86_BUILTIN_VFNMADDPH256_MASKZ, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fnmadd_v8hf_mask, "__builtin_ia32_vfnmaddph128_mask", IX86_BUILTIN_VFNMADDPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fnmadd_v8hf_mask3, "__builtin_ia32_vfnmaddph128_mask3", IX86_BUILTIN_VFNMADDPH128_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fnmadd_v8hf_maskz, "__builtin_ia32_vfnmaddph128_maskz", IX86_BUILTIN_VFNMADDPH128_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmsub_v16hf_mask, "__builtin_ia32_vfmsubph256_mask", IX86_BUILTIN_VFMSUBPH256_MASK, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmsub_v16hf_mask3, "__builtin_ia32_vfmsubph256_mask3", IX86_BUILTIN_VFMSUBPH256_MASK3, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fmsub_v16hf_maskz, "__builtin_ia32_vfmsubph256_maskz", IX86_BUILTIN_VFMSUBPH256_MASKZ, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmsub_v8hf_mask, "__builtin_ia32_vfmsubph128_mask", IX86_BUILTIN_VFMSUBPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmsub_v8hf_mask3, "__builtin_ia32_vfmsubph128_mask3", IX86_BUILTIN_VFMSUBPH128_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fmsub_v8hf_maskz, "__builtin_ia32_vfmsubph128_maskz", IX86_BUILTIN_VFMSUBPH128_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fnmsub_v16hf_mask, "__builtin_ia32_vfnmsubph256_mask", IX86_BUILTIN_VFNMSUBPH256_MASK, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fnmsub_v16hf_mask3, "__builtin_ia32_vfnmsubph256_mask3", IX86_BUILTIN_VFNMSUBPH256_MASK3, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512vl_fnmsub_v16hf_maskz, "__builtin_ia32_vfnmsubph256_maskz", IX86_BUILTIN_VFNMSUBPH256_MASKZ, UNKNOWN, (int) V16HF_FTYPE_V16HF_V16HF_V16HF_UHI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fnmsub_v8hf_mask, "__builtin_ia32_vfnmsubph128_mask", IX86_BUILTIN_VFNMSUBPH128_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fnmsub_v8hf_mask3, "__builtin_ia32_vfnmsubph128_mask3", IX86_BUILTIN_VFNMSUBPH128_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) +BDESC (OPTION_MASK_ISA_AVX512VL, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_fnmsub_v8hf_maskz, "__builtin_ia32_vfnmsubph128_maskz", IX86_BUILTIN_VFNMSUBPH128_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI) /* Builtins with rounding support. */ BDESC_END (ARGS, ROUND_ARGS) @@ -3140,6 +3176,31 @@ BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtsh2ss_mask_round, BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtsh2sd_mask_round, "__builtin_ia32_vcvtsh2sd_mask_round", IX86_BUILTIN_VCVTSH2SD_MASK_ROUND, UNKNOWN, (int) V2DF_FTYPE_V8HF_V2DF_V2DF_UQI_INT) BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtss2sh_mask_round, "__builtin_ia32_vcvtss2sh_mask_round", IX86_BUILTIN_VCVTSS2SH_MASK_ROUND, UNKNOWN, (int) V8HF_FTYPE_V4SF_V8HF_V8HF_UQI_INT) BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512fp16_vcvtsd2sh_mask_round, "__builtin_ia32_vcvtsd2sh_mask_round", IX86_BUILTIN_VCVTSD2SH_MASK_ROUND, UNKNOWN, (int) V8HF_FTYPE_V2DF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmaddsub_v32hf_mask_round, "__builtin_ia32_vfmaddsubph512_mask", IX86_BUILTIN_VFMADDSUBPH512_MASK, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmaddsub_v32hf_mask3_round, "__builtin_ia32_vfmaddsubph512_mask3", IX86_BUILTIN_VFMADDSUBPH512_MASK3, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmaddsub_v32hf_maskz_round, "__builtin_ia32_vfmaddsubph512_maskz", IX86_BUILTIN_VFMADDSUBPH512_MASKZ, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmsubadd_v32hf_mask_round, "__builtin_ia32_vfmsubaddph512_mask", IX86_BUILTIN_VFMSUBADDPH512_MASK, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmsubadd_v32hf_mask3_round, "__builtin_ia32_vfmsubaddph512_mask3", IX86_BUILTIN_VFMSUBADDPH512_MASK3, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmsubadd_v32hf_maskz_round, "__builtin_ia32_vfmsubaddph512_maskz", IX86_BUILTIN_VFMSUBADDPH512_MASKZ, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmadd_v32hf_mask_round, "__builtin_ia32_vfmaddph512_mask", IX86_BUILTIN_VFMADDPH512_MASK, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmadd_v32hf_mask3_round, "__builtin_ia32_vfmaddph512_mask3", IX86_BUILTIN_VFMADDPH512_MASK3, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmadd_v32hf_maskz_round, "__builtin_ia32_vfmaddph512_maskz", IX86_BUILTIN_VFMADDPH512_MASKZ, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fnmadd_v32hf_mask_round, "__builtin_ia32_vfnmaddph512_mask", IX86_BUILTIN_VFNMADDPH512_MASK, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fnmadd_v32hf_mask3_round, "__builtin_ia32_vfnmaddph512_mask3", IX86_BUILTIN_VFNMADDPH512_MASK3, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fnmadd_v32hf_maskz_round, "__builtin_ia32_vfnmaddph512_maskz", IX86_BUILTIN_VFNMADDPH512_MASKZ, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmsub_v32hf_mask_round, "__builtin_ia32_vfmsubph512_mask", IX86_BUILTIN_VFMSUBPH512_MASK, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmsub_v32hf_mask3_round, "__builtin_ia32_vfmsubph512_mask3", IX86_BUILTIN_VFMSUBPH512_MASK3, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fmsub_v32hf_maskz_round, "__builtin_ia32_vfmsubph512_maskz", IX86_BUILTIN_VFMSUBPH512_MASKZ, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fnmsub_v32hf_mask_round, "__builtin_ia32_vfnmsubph512_mask", IX86_BUILTIN_VFNMSUBPH512_MASK, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fnmsub_v32hf_mask3_round, "__builtin_ia32_vfnmsubph512_mask3", IX86_BUILTIN_VFNMSUBPH512_MASK3, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512bw_fnmsub_v32hf_maskz_round, "__builtin_ia32_vfnmsubph512_maskz", IX86_BUILTIN_VFNMSUBPH512_MASKZ, UNKNOWN, (int) V32HF_FTYPE_V32HF_V32HF_V32HF_USI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfmadd_v8hf_mask_round, "__builtin_ia32_vfmaddsh3_mask", IX86_BUILTIN_VFMADDSH3_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfmadd_v8hf_mask3_round, "__builtin_ia32_vfmaddsh3_mask3", IX86_BUILTIN_VFMADDSH3_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfmadd_v8hf_maskz_round, "__builtin_ia32_vfmaddsh3_maskz", IX86_BUILTIN_VFMADDSH3_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfnmadd_v8hf_mask_round, "__builtin_ia32_vfnmaddsh3_mask", IX86_BUILTIN_VFNMADDSH3_MASK, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfnmadd_v8hf_mask3_round, "__builtin_ia32_vfnmaddsh3_mask3", IX86_BUILTIN_VFNMADDSH3_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfnmadd_v8hf_maskz_round, "__builtin_ia32_vfnmaddsh3_maskz", IX86_BUILTIN_VFNMADDSH3_MASKZ, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) +BDESC (0, OPTION_MASK_ISA2_AVX512FP16, CODE_FOR_avx512f_vmfmsub_v8hf_mask3_round, "__builtin_ia32_vfmsubsh3_mask3", IX86_BUILTIN_VFMSUBSH3_MASK3, UNKNOWN, (int) V8HF_FTYPE_V8HF_V8HF_V8HF_UQI_INT) BDESC_END (ROUND_ARGS, MULTI_ARG) diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index bfafd15..c88cb14 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -1981,8 +1981,12 @@ ix86_expand_fp_absneg_operator (enum rtx_code code, machine_mode mode, machine_mode vmode = mode; rtvec par; - if (vector_mode || mode == TFmode) - use_sse = true; + if (vector_mode || mode == TFmode || mode == HFmode) + { + use_sse = true; + if (mode == HFmode) + vmode = V8HFmode; + } else if (TARGET_SSE_MATH) { use_sse = SSE_FLOAT_MODE_P (mode); @@ -2123,7 +2127,9 @@ ix86_expand_copysign (rtx operands[]) mode = GET_MODE (operands[0]); - if (mode == SFmode) + if (mode == HFmode) + vmode = V8HFmode; + else if (mode == SFmode) vmode = V4SFmode; else if (mode == DFmode) vmode = V2DFmode; @@ -2182,7 +2188,9 @@ ix86_expand_xorsign (rtx operands[]) mode = GET_MODE (dest); - if (mode == SFmode) + if (mode == HFmode) + vmode = V8HFmode; + else if (mode == SFmode) vmode = V4SFmode; else if (mode == DFmode) vmode = V2DFmode; @@ -10730,6 +10738,7 @@ ix86_expand_round_builtin (const struct builtin_description *d, case V8HF_FTYPE_V8DI_V8HF_UQI_INT: case V8HF_FTYPE_V8DF_V8HF_UQI_INT: case V16HF_FTYPE_V16SF_V16HF_UHI_INT: + case V8HF_FTYPE_V8HF_V8HF_V8HF_INT: nargs = 4; break; case V4SF_FTYPE_V4SF_V4SF_INT_INT: diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index a525a83..14f816f 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -2165,7 +2165,7 @@ make_pass_insert_endbr_and_patchable_area (gcc::context *ctxt) } /* At entry of the nearest common dominator for basic blocks with - conversions, generate a single + conversions/rcp/sqrt/rsqrt/round, generate a single vxorps %xmmN, %xmmN, %xmmN for all vcvtss2sd op, %xmmN, %xmmX @@ -2211,13 +2211,27 @@ remove_partial_avx_dependency (void) continue; /* Convert PARTIAL_XMM_UPDATE_TRUE insns, DF -> SF, SF -> DF, - SI -> SF, SI -> DF, DI -> SF, DI -> DF, to vec_dup and - vec_merge with subreg. */ + SI -> SF, SI -> DF, DI -> SF, DI -> DF, sqrt, rsqrt, rcp, + round, to vec_dup and vec_merge with subreg. */ rtx src = SET_SRC (set); rtx dest = SET_DEST (set); machine_mode dest_mode = GET_MODE (dest); - machine_mode src_mode = GET_MODE (XEXP (src, 0)); + bool convert_p = false; + switch (GET_CODE (src)) + { + case FLOAT: + case FLOAT_EXTEND: + case FLOAT_TRUNCATE: + case UNSIGNED_FLOAT: + convert_p = true; + break; + default: + break; + } + /* Only hanlde conversion here. */ + machine_mode src_mode + = convert_p ? GET_MODE (XEXP (src, 0)) : VOIDmode; switch (src_mode) { case E_SFmode: @@ -2232,8 +2246,11 @@ remove_partial_avx_dependency (void) || !TARGET_SSE_PARTIAL_REG_CONVERTS_DEPENDENCY) continue; break; - default: + case E_VOIDmode: + gcc_assert (!convert_p); break; + default: + gcc_unreachable (); } if (!v4sf_const0) diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index afc2674..ba89e11 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -13610,12 +13610,17 @@ ix86_print_operand (FILE *file, rtx x, int code) case E_V8SFmode: case E_V8DFmode: case E_V8DImode: + case E_V8HFmode: fputs ("{1to8}", file); break; case E_V16SFmode: case E_V16SImode: + case E_V16HFmode: fputs ("{1to16}", file); break; + case E_V32HFmode: + fputs ("{1to32}", file); + break; default: gcc_unreachable (); } @@ -15556,6 +15561,9 @@ ix86_build_const_vector (machine_mode mode, bool vect, rtx value) case E_V2DImode: gcc_assert (vect); /* FALLTHRU */ + case E_V8HFmode: + case E_V16HFmode: + case E_V32HFmode: case E_V16SFmode: case E_V8SFmode: case E_V4SFmode: @@ -15594,6 +15602,13 @@ ix86_build_signbit_mask (machine_mode mode, bool vect, bool invert) switch (mode) { + case E_V8HFmode: + case E_V16HFmode: + case E_V32HFmode: + vec_mode = mode; + imode = HImode; + break; + case E_V16SImode: case E_V16SFmode: case E_V8SImode: diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index ec60b89..8a4251b 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1105,7 +1105,8 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define VALID_BCST_MODE_P(MODE) \ ((MODE) == SFmode || (MODE) == DFmode \ - || (MODE) == SImode || (MODE) == DImode) + || (MODE) == SImode || (MODE) == DImode \ + || (MODE) == HFmode) /* It is possible to write patterns to move flags; but until someone does it, */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index c82a9dc..188f431 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1237,8 +1237,8 @@ (define_mode_iterator X87MODEFH [HF SF DF XF]) ;; All SSE floating point modes -(define_mode_iterator SSEMODEF [SF DF TF]) -(define_mode_attr ssevecmodef [(SF "V4SF") (DF "V2DF") (TF "TF")]) +(define_mode_iterator SSEMODEF [HF SF DF TF]) +(define_mode_attr ssevecmodef [(HF "V8HF") (SF "V4SF") (DF "V2DF") (TF "TF")]) ;; SSE instruction suffix for various modes (define_mode_attr ssemodesuffix @@ -10732,6 +10732,12 @@ } [(set_attr "isa" "noavx,noavx,avx,avx")]) +(define_expand "<code>hf2" + [(set (match_operand:HF 0 "register_operand") + (absneg:HF (match_operand:HF 1 "register_operand")))] + "TARGET_AVX512FP16" + "ix86_expand_fp_absneg_operator (<CODE>, HFmode, operands); DONE;") + (define_expand "<code><mode>2" [(set (match_operand:X87MODEF 0 "register_operand") (absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand")))] @@ -10762,6 +10768,22 @@ [(const_int 0)] "ix86_split_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;") +(define_insn_and_split "*<code>hf2_1" + [(set (match_operand:HF 0 "register_operand" "=Yv") + (absneg:HF + (match_operand:HF 1 "register_operand" "Yv"))) + (use (match_operand:V8HF 2 "vector_operand" "Yvm")) + (clobber (reg:CC FLAGS_REG))] + "TARGET_AVX512FP16" + "#" + "&& reload_completed" + [(set (match_dup 0) + (<absneg_op>:V8HF (match_dup 1) (match_dup 2)))] +{ + operands[0] = lowpart_subreg (V8HFmode, operands[0], HFmode); + operands[1] = lowpart_subreg (V8HFmode, operands[1], HFmode); +}) + (define_insn "*<code><mode>2_1" [(set (match_operand:MODEF 0 "register_operand" "=x,x,Yv,f,!r") (absneg:MODEF @@ -10862,14 +10884,16 @@ (match_operand:SSEMODEF 1 "nonmemory_operand") (match_operand:SSEMODEF 2 "register_operand")] "(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH) - || (TARGET_SSE && (<MODE>mode == TFmode))" + || (TARGET_SSE && (<MODE>mode == TFmode)) + || (TARGET_AVX512FP16 && (<MODE>mode ==HFmode))" "ix86_expand_copysign (operands); DONE;") (define_expand "xorsign<mode>3" - [(match_operand:MODEF 0 "register_operand") - (match_operand:MODEF 1 "register_operand") - (match_operand:MODEF 2 "register_operand")] - "SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH" + [(match_operand:MODEFH 0 "register_operand") + (match_operand:MODEFH 1 "register_operand") + (match_operand:MODEFH 2 "register_operand")] + "(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH) + || <MODE>mode == HFmode" { if (rtx_equal_p (operands[1], operands[2])) emit_insn (gen_abs<mode>2 (operands[0], operands[1])); diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index d7a1328..0016c02 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -319,11 +319,26 @@ (V16SF "TARGET_AVX512F") (V8SF "TARGET_AVX") V4SF (V8DF "TARGET_AVX512F") (V4DF "TARGET_AVX") (V2DF "TARGET_SSE2")]) +;; 128-, 256- and 512-bit float vector modes for bitwise operations +(define_mode_iterator VFB + [(V32HF "TARGET_AVX512FP16") + (V16HF "TARGET_AVX512FP16") + (V8HF "TARGET_AVX512FP16") + (V16SF "TARGET_AVX512F") (V8SF "TARGET_AVX") V4SF + (V8DF "TARGET_AVX512F") (V4DF "TARGET_AVX") (V2DF "TARGET_SSE2")]) + ;; 128- and 256-bit float vector modes (define_mode_iterator VF_128_256 [(V8SF "TARGET_AVX") V4SF (V4DF "TARGET_AVX") (V2DF "TARGET_SSE2")]) +;; 128- and 256-bit float vector modes for bitwise operations +(define_mode_iterator VFB_128_256 + [(V16HF "TARGET_AVX512FP16") + (V8HF "TARGET_AVX512FP16") + (V8SF "TARGET_AVX") V4SF + (V4DF "TARGET_AVX") (V2DF "TARGET_SSE2")]) + ;; All SFmode vector float modes (define_mode_iterator VF1 [(V16SF "TARGET_AVX512F") (V8SF "TARGET_AVX") V4SF]) @@ -376,6 +391,10 @@ (define_mode_iterator VF_512 [V16SF V8DF]) +;; All 512bit vector float modes for bitwise operations +(define_mode_iterator VFB_512 + [(V32HF "TARGET_AVX512FP16") V16SF V8DF]) + (define_mode_iterator VI48_AVX512VL [V16SI (V8SI "TARGET_AVX512VL") (V4SI "TARGET_AVX512VL") V8DI (V4DI "TARGET_AVX512VL") (V2DI "TARGET_AVX512VL")]) @@ -841,14 +860,6 @@ (define_mode_iterator V16_256 [V16HI V16HF]) (define_mode_iterator V32_512 [V32HI V32HF]) -(define_mode_attr avx512bcst - [(V4SI "%{1to4%}") (V2DI "%{1to2%}") - (V8SI "%{1to8%}") (V4DI "%{1to4%}") - (V16SI "%{1to16%}") (V8DI "%{1to8%}") - (V4SF "%{1to4%}") (V2DF "%{1to2%}") - (V8SF "%{1to8%}") (V4DF "%{1to4%}") - (V16SF "%{1to16%}") (V8DF "%{1to8%}")]) - ;; Mapping from float mode to required SSE level (define_mode_attr sse [(SF "sse") (DF "sse2") (HF "avx512fp16") @@ -962,7 +973,8 @@ (define_mode_attr sseintvecmode2 [(V8DF "XI") (V4DF "OI") (V2DF "TI") - (V8SF "OI") (V4SF "TI")]) + (V8SF "OI") (V4SF "TI") + (V16HF "OI") (V8HF "TI")]) (define_mode_attr sseintvecmodelower [(V16SF "v16si") (V8DF "v8di") @@ -2038,22 +2050,22 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define_expand "<code><mode>2" - [(set (match_operand:VF 0 "register_operand") - (absneg:VF - (match_operand:VF 1 "register_operand")))] + [(set (match_operand:VFB 0 "register_operand") + (absneg:VFB + (match_operand:VFB 1 "register_operand")))] "TARGET_SSE" "ix86_expand_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;") (define_insn_and_split "*<code><mode>2" - [(set (match_operand:VF 0 "register_operand" "=x,x,v,v") - (absneg:VF - (match_operand:VF 1 "vector_operand" "0,xBm,v,m"))) - (use (match_operand:VF 2 "vector_operand" "xBm,0,vm,v"))] + [(set (match_operand:VFB 0 "register_operand" "=x,x,v,v") + (absneg:VFB + (match_operand:VFB 1 "vector_operand" "0,xBm,v,m"))) + (use (match_operand:VFB 2 "vector_operand" "xBm,0,vm,v"))] "TARGET_SSE" "#" "&& reload_completed" [(set (match_dup 0) - (<absneg_op>:VF (match_dup 1) (match_dup 2)))] + (<absneg_op>:VFB (match_dup 1) (match_dup 2)))] { if (TARGET_AVX) { @@ -4081,11 +4093,11 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define_insn "<sse>_andnot<mode>3<mask_name>" - [(set (match_operand:VF_128_256 0 "register_operand" "=x,x,v,v") - (and:VF_128_256 - (not:VF_128_256 - (match_operand:VF_128_256 1 "register_operand" "0,x,v,v")) - (match_operand:VF_128_256 2 "vector_operand" "xBm,xm,vm,vm")))] + [(set (match_operand:VFB_128_256 0 "register_operand" "=x,x,v,v") + (and:VFB_128_256 + (not:VFB_128_256 + (match_operand:VFB_128_256 1 "register_operand" "0,x,v,v")) + (match_operand:VFB_128_256 2 "vector_operand" "xBm,xm,vm,vm")))] "TARGET_SSE && <mask_avx512vl_condition>" { char buf[128]; @@ -4108,6 +4120,8 @@ switch (get_attr_mode (insn)) { + case MODE_V16HF: + case MODE_V8HF: case MODE_V8SF: case MODE_V4SF: suffix = "ps"; @@ -4146,11 +4160,11 @@ (const_string "<MODE>")))]) (define_insn "<sse>_andnot<mode>3<mask_name>" - [(set (match_operand:VF_512 0 "register_operand" "=v") - (and:VF_512 - (not:VF_512 - (match_operand:VF_512 1 "register_operand" "v")) - (match_operand:VF_512 2 "nonimmediate_operand" "vm")))] + [(set (match_operand:VFB_512 0 "register_operand" "=v") + (and:VFB_512 + (not:VFB_512 + (match_operand:VFB_512 1 "register_operand" "v")) + (match_operand:VFB_512 2 "nonimmediate_operand" "vm")))] "TARGET_AVX512F" { char buf[128]; @@ -4160,8 +4174,9 @@ suffix = "<ssemodesuffix>"; ops = ""; - /* There is no vandnp[sd] in avx512f. Use vpandn[qd]. */ - if (!TARGET_AVX512DQ) + /* Since there are no vandnp[sd] without AVX512DQ nor vandnph, + use vp<logic>[dq]. */ + if (!TARGET_AVX512DQ || <MODE>mode == V32HFmode) { suffix = GET_MODE_INNER (<MODE>mode) == DFmode ? "q" : "d"; ops = "p"; @@ -4181,26 +4196,26 @@ (const_string "XI")))]) (define_expand "<code><mode>3<mask_name>" - [(set (match_operand:VF_128_256 0 "register_operand") - (any_logic:VF_128_256 - (match_operand:VF_128_256 1 "vector_operand") - (match_operand:VF_128_256 2 "vector_operand")))] + [(set (match_operand:VFB_128_256 0 "register_operand") + (any_logic:VFB_128_256 + (match_operand:VFB_128_256 1 "vector_operand") + (match_operand:VFB_128_256 2 "vector_operand")))] "TARGET_SSE && <mask_avx512vl_condition>" "ix86_fixup_binary_operands_no_copy (<CODE>, <MODE>mode, operands);") (define_expand "<code><mode>3<mask_name>" - [(set (match_operand:VF_512 0 "register_operand") - (any_logic:VF_512 - (match_operand:VF_512 1 "nonimmediate_operand") - (match_operand:VF_512 2 "nonimmediate_operand")))] + [(set (match_operand:VFB_512 0 "register_operand") + (any_logic:VFB_512 + (match_operand:VFB_512 1 "nonimmediate_operand") + (match_operand:VFB_512 2 "nonimmediate_operand")))] "TARGET_AVX512F" "ix86_fixup_binary_operands_no_copy (<CODE>, <MODE>mode, operands);") (define_insn "*<code><mode>3<mask_name>" - [(set (match_operand:VF_128_256 0 "register_operand" "=x,x,v,v") - (any_logic:VF_128_256 - (match_operand:VF_128_256 1 "vector_operand" "%0,x,v,v") - (match_operand:VF_128_256 2 "vector_operand" "xBm,xm,vm,vm")))] + [(set (match_operand:VFB_128_256 0 "register_operand" "=x,x,v,v") + (any_logic:VFB_128_256 + (match_operand:VFB_128_256 1 "vector_operand" "%0,x,v,v") + (match_operand:VFB_128_256 2 "vector_operand" "xBm,xm,vm,vm")))] "TARGET_SSE && <mask_avx512vl_condition> && !(MEM_P (operands[1]) && MEM_P (operands[2]))" { @@ -4224,6 +4239,8 @@ switch (get_attr_mode (insn)) { + case MODE_V16HF: + case MODE_V8HF: case MODE_V8SF: case MODE_V4SF: suffix = "ps"; @@ -4262,10 +4279,10 @@ (const_string "<MODE>")))]) (define_insn "*<code><mode>3<mask_name>" - [(set (match_operand:VF_512 0 "register_operand" "=v") - (any_logic:VF_512 - (match_operand:VF_512 1 "nonimmediate_operand" "%v") - (match_operand:VF_512 2 "nonimmediate_operand" "vm")))] + [(set (match_operand:VFB_512 0 "register_operand" "=v") + (any_logic:VFB_512 + (match_operand:VFB_512 1 "nonimmediate_operand" "%v") + (match_operand:VFB_512 2 "nonimmediate_operand" "vm")))] "TARGET_AVX512F && !(MEM_P (operands[1]) && MEM_P (operands[2]))" { char buf[128]; @@ -4275,8 +4292,9 @@ suffix = "<ssemodesuffix>"; ops = ""; - /* There is no v<logic>p[sd] in avx512f. Use vp<logic>[dq]. */ - if (!TARGET_AVX512DQ) + /* Since there are no v<logic>p[sd] without AVX512DQ nor v<logic>ph, + use vp<logic>[dq]. */ + if (!TARGET_AVX512DQ || <MODE>mode == V32HFmode) { suffix = GET_MODE_INNER (<MODE>mode) == DFmode ? "q" : "d"; ops = "p"; @@ -4297,14 +4315,14 @@ (define_expand "copysign<mode>3" [(set (match_dup 4) - (and:VF - (not:VF (match_dup 3)) - (match_operand:VF 1 "vector_operand"))) + (and:VFB + (not:VFB (match_dup 3)) + (match_operand:VFB 1 "vector_operand"))) (set (match_dup 5) - (and:VF (match_dup 3) - (match_operand:VF 2 "vector_operand"))) - (set (match_operand:VF 0 "register_operand") - (ior:VF (match_dup 4) (match_dup 5)))] + (and:VFB (match_dup 3) + (match_operand:VFB 2 "vector_operand"))) + (set (match_operand:VFB 0 "register_operand") + (ior:VFB (match_dup 4) (match_dup 5)))] "TARGET_SSE" { operands[3] = ix86_build_signbit_mask (<MODE>mode, 1, 0); @@ -4315,11 +4333,11 @@ (define_expand "xorsign<mode>3" [(set (match_dup 4) - (and:VF (match_dup 3) - (match_operand:VF 2 "vector_operand"))) - (set (match_operand:VF 0 "register_operand") - (xor:VF (match_dup 4) - (match_operand:VF 1 "vector_operand")))] + (and:VFB (match_dup 3) + (match_operand:VFB 2 "vector_operand"))) + (set (match_operand:VFB 0 "register_operand") + (xor:VFB (match_dup 4) + (match_operand:VFB 1 "vector_operand")))] "TARGET_SSE" { operands[3] = ix86_build_signbit_mask (<MODE>mode, 1, 0); @@ -4697,10 +4715,10 @@ (match_operand:FMAMODE_AVX512 3 "nonimmediate_operand"))))]) (define_expand "<avx512>_fmadd_<mode>_maskz<round_expand_name>" - [(match_operand:VF_AVX512VL 0 "register_operand") - (match_operand:VF_AVX512VL 1 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 2 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 3 "<round_expand_nimm_predicate>") + [(match_operand:VFH_AVX512VL 0 "register_operand") + (match_operand:VFH_AVX512VL 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 3 "<round_expand_nimm_predicate>") (match_operand:<avx512fmaskmode> 4 "register_operand")] "TARGET_AVX512F && <round_mode512bit_condition>" { @@ -4732,12 +4750,19 @@ [SF V16SF (V8SF "TARGET_AVX512VL") (V4SF "TARGET_AVX512VL") DF V8DF (V4DF "TARGET_AVX512VL") (V2DF "TARGET_AVX512VL")]) +(define_mode_iterator VFH_SF_AVX512VL + [(V32HF "TARGET_AVX512FP16") + (V16HF "TARGET_AVX512FP16 && TARGET_AVX512VL") + (V8HF "TARGET_AVX512FP16 && TARGET_AVX512VL") + SF V16SF (V8SF "TARGET_AVX512VL") (V4SF "TARGET_AVX512VL") + DF V8DF (V4DF "TARGET_AVX512VL") (V2DF "TARGET_AVX512VL")]) + (define_insn "<sd_mask_codefor>fma_fmadd_<mode><sd_maskz_name><round_name>" - [(set (match_operand:VF_SF_AVX512VL 0 "register_operand" "=v,v,v") - (fma:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v") - (match_operand:VF_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") - (match_operand:VF_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0")))] + [(set (match_operand:VFH_SF_AVX512VL 0 "register_operand" "=v,v,v") + (fma:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v") + (match_operand:VFH_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") + (match_operand:VFH_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0")))] "TARGET_AVX512F && <sd_mask_mode512bit_condition> && <round_mode512bit_condition>" "@ vfmadd132<ssemodesuffix>\t{<round_sd_mask_op4>%2, %3, %0<sd_mask_op4>|%0<sd_mask_op4>, %3, %2<round_sd_mask_op4>} @@ -4770,12 +4795,12 @@ }) (define_insn "<avx512>_fmadd_<mode>_mask<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "register_operand" "0,0") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") - (match_operand:VF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>")) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "register_operand" "0,0") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") + (match_operand:VFH_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>")) (match_dup 1) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk,Yk")))] "TARGET_AVX512F && <round_mode512bit_condition>" @@ -4786,12 +4811,12 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fmadd_<mode>_mask3<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "<round_nimm_predicate>" "%v") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") - (match_operand:VF_AVX512VL 3 "register_operand" "0")) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "<round_nimm_predicate>" "%v") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") + (match_operand:VFH_AVX512VL 3 "register_operand" "0")) (match_dup 3) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))] "TARGET_AVX512F" @@ -4818,10 +4843,10 @@ (set_attr "mode" "<MODE>")]) (define_expand "<avx512>_fmsub_<mode>_maskz<round_expand_name>" - [(match_operand:VF_AVX512VL 0 "register_operand") - (match_operand:VF_AVX512VL 1 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 2 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 3 "<round_expand_nimm_predicate>") + [(match_operand:VFH_AVX512VL 0 "register_operand") + (match_operand:VFH_AVX512VL 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 3 "<round_expand_nimm_predicate>") (match_operand:<avx512fmaskmode> 4 "register_operand")] "TARGET_AVX512F && <round_mode512bit_condition>" { @@ -4832,12 +4857,12 @@ }) (define_insn "<sd_mask_codefor>fma_fmsub_<mode><sd_maskz_name><round_name>" - [(set (match_operand:VF_SF_AVX512VL 0 "register_operand" "=v,v,v") - (fma:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v") - (match_operand:VF_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") - (neg:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0"))))] + [(set (match_operand:VFH_SF_AVX512VL 0 "register_operand" "=v,v,v") + (fma:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v") + (match_operand:VFH_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") + (neg:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0"))))] "TARGET_AVX512F && <sd_mask_mode512bit_condition> && <round_mode512bit_condition>" "@ vfmsub132<ssemodesuffix>\t{<round_sd_mask_op4>%2, %3, %0<sd_mask_op4>|%0<sd_mask_op4>, %3, %2<round_sd_mask_op4>} @@ -4871,13 +4896,13 @@ }) (define_insn "<avx512>_fmsub_<mode>_mask<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "register_operand" "0,0") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>"))) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "register_operand" "0,0") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>"))) (match_dup 1) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk,Yk")))] "TARGET_AVX512F" @@ -4888,13 +4913,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fmsub_<mode>_mask3<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "<round_nimm_predicate>" "%v") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 3 "register_operand" "0"))) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "<round_nimm_predicate>" "%v") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 3 "register_operand" "0"))) (match_dup 3) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))] "TARGET_AVX512F && <round_mode512bit_condition>" @@ -4921,10 +4946,10 @@ (set_attr "mode" "<MODE>")]) (define_expand "<avx512>_fnmadd_<mode>_maskz<round_expand_name>" - [(match_operand:VF_AVX512VL 0 "register_operand") - (match_operand:VF_AVX512VL 1 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 2 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 3 "<round_expand_nimm_predicate>") + [(match_operand:VFH_AVX512VL 0 "register_operand") + (match_operand:VFH_AVX512VL 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 3 "<round_expand_nimm_predicate>") (match_operand:<avx512fmaskmode> 4 "register_operand")] "TARGET_AVX512F && <round_mode512bit_condition>" { @@ -4935,12 +4960,12 @@ }) (define_insn "<sd_mask_codefor>fma_fnmadd_<mode><sd_maskz_name><round_name>" - [(set (match_operand:VF_SF_AVX512VL 0 "register_operand" "=v,v,v") - (fma:VF_SF_AVX512VL - (neg:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v")) - (match_operand:VF_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") - (match_operand:VF_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0")))] + [(set (match_operand:VFH_SF_AVX512VL 0 "register_operand" "=v,v,v") + (fma:VFH_SF_AVX512VL + (neg:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v")) + (match_operand:VFH_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") + (match_operand:VFH_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0")))] "TARGET_AVX512F && <sd_mask_mode512bit_condition> && <round_mode512bit_condition>" "@ vfnmadd132<ssemodesuffix>\t{<round_sd_mask_op4>%2, %3, %0<sd_mask_op4>|%0<sd_mask_op4>, %3, %2<round_sd_mask_op4>} @@ -4974,13 +4999,13 @@ }) (define_insn "<avx512>_fnmadd_<mode>_mask<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "register_operand" "0,0")) - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") - (match_operand:VF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>")) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "register_operand" "0,0")) + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") + (match_operand:VFH_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>")) (match_dup 1) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk,Yk")))] "TARGET_AVX512F && <round_mode512bit_condition>" @@ -4991,13 +5016,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fnmadd_<mode>_mask3<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "<round_nimm_predicate>" "%v")) - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") - (match_operand:VF_AVX512VL 3 "register_operand" "0")) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "<round_nimm_predicate>" "%v")) + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") + (match_operand:VFH_AVX512VL 3 "register_operand" "0")) (match_dup 3) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))] "TARGET_AVX512F && <round_mode512bit_condition>" @@ -5025,10 +5050,10 @@ (set_attr "mode" "<MODE>")]) (define_expand "<avx512>_fnmsub_<mode>_maskz<round_expand_name>" - [(match_operand:VF_AVX512VL 0 "register_operand") - (match_operand:VF_AVX512VL 1 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 2 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 3 "<round_expand_nimm_predicate>") + [(match_operand:VFH_AVX512VL 0 "register_operand") + (match_operand:VFH_AVX512VL 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 3 "<round_expand_nimm_predicate>") (match_operand:<avx512fmaskmode> 4 "register_operand")] "TARGET_AVX512F && <round_mode512bit_condition>" { @@ -5039,13 +5064,13 @@ }) (define_insn "<sd_mask_codefor>fma_fnmsub_<mode><sd_maskz_name><round_name>" - [(set (match_operand:VF_SF_AVX512VL 0 "register_operand" "=v,v,v") - (fma:VF_SF_AVX512VL - (neg:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v")) - (match_operand:VF_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") - (neg:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0"))))] + [(set (match_operand:VFH_SF_AVX512VL 0 "register_operand" "=v,v,v") + (fma:VFH_SF_AVX512VL + (neg:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 1 "<bcst_round_nimm_predicate>" "%0,0,v")) + (match_operand:VFH_SF_AVX512VL 2 "<bcst_round_nimm_predicate>" "<bcst_round_constraint>,v,<bcst_round_constraint>") + (neg:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 3 "<bcst_round_nimm_predicate>" "v,<bcst_round_constraint>,0"))))] "TARGET_AVX512F && <sd_mask_mode512bit_condition> && <round_mode512bit_condition>" "@ vfnmsub132<ssemodesuffix>\t{<round_sd_mask_op4>%2, %3, %0<sd_mask_op4>|%0<sd_mask_op4>, %3, %2<round_sd_mask_op4>} @@ -5080,14 +5105,14 @@ }) (define_insn "<avx512>_fnmsub_<mode>_mask<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "register_operand" "0,0")) - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>"))) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "register_operand" "0,0")) + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>"))) (match_dup 1) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk,Yk")))] "TARGET_AVX512F && <round_mode512bit_condition>" @@ -5098,14 +5123,14 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fnmsub_<mode>_mask3<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v") - (vec_merge:VF_AVX512VL - (fma:VF_AVX512VL - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 1 "<round_nimm_predicate>" "%v")) - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 3 "register_operand" "0"))) + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v") + (vec_merge:VFH_AVX512VL + (fma:VFH_AVX512VL + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 1 "<round_nimm_predicate>" "%v")) + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 3 "register_operand" "0"))) (match_dup 3) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))] "TARGET_AVX512F" @@ -5153,10 +5178,10 @@ "TARGET_FMA || TARGET_FMA4 || TARGET_AVX512F") (define_expand "<avx512>_fmaddsub_<mode>_maskz<round_expand_name>" - [(match_operand:VF_AVX512VL 0 "register_operand") - (match_operand:VF_AVX512VL 1 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 2 "<round_expand_nimm_predicate>") - (match_operand:VF_AVX512VL 3 "<round_expand_nimm_predicate>") + [(match_operand:VFH_AVX512VL 0 "register_operand") + (match_operand:VFH_AVX512VL 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 3 "<round_expand_nimm_predicate>") (match_operand:<avx512fmaskmode> 4 "register_operand")] "TARGET_AVX512F" { @@ -5166,6 +5191,20 @@ DONE; }) +(define_expand "<avx512>_fmsubadd_<mode>_maskz<round_expand_name>" + [(match_operand:VFH_AVX512VL 0 "register_operand") + (match_operand:VFH_AVX512VL 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_AVX512VL 3 "<round_expand_nimm_predicate>") + (match_operand:<avx512fmaskmode> 4 "register_operand")] + "TARGET_AVX512F" +{ + emit_insn (gen_fma_fmsubadd_<mode>_maskz_1<round_expand_name> ( + operands[0], operands[1], operands[2], operands[3], + CONST0_RTX (<MODE>mode), operands[4]<round_expand_operand>)); + DONE; +}) + (define_insn "*fma_fmaddsub_<mode>" [(set (match_operand:VF_128_256 0 "register_operand" "=v,v,v,x,x") (unspec:VF_128_256 @@ -5185,11 +5224,11 @@ (set_attr "mode" "<MODE>")]) (define_insn "<sd_mask_codefor>fma_fmaddsub_<mode><sd_maskz_name><round_name>" - [(set (match_operand:VF_SF_AVX512VL 0 "register_operand" "=v,v,v") - (unspec:VF_SF_AVX512VL - [(match_operand:VF_SF_AVX512VL 1 "<round_nimm_predicate>" "%0,0,v") - (match_operand:VF_SF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v,<round_constraint>") - (match_operand:VF_SF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>,0")] + [(set (match_operand:VFH_SF_AVX512VL 0 "register_operand" "=v,v,v") + (unspec:VFH_SF_AVX512VL + [(match_operand:VFH_SF_AVX512VL 1 "<round_nimm_predicate>" "%0,0,v") + (match_operand:VFH_SF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v,<round_constraint>") + (match_operand:VFH_SF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>,0")] UNSPEC_FMADDSUB))] "TARGET_AVX512F && <sd_mask_mode512bit_condition> && <round_mode512bit_condition>" "@ @@ -5200,12 +5239,12 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fmaddsub_<mode>_mask<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512VL - (unspec:VF_AVX512VL - [(match_operand:VF_AVX512VL 1 "register_operand" "0,0") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") - (match_operand:VF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>")] + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VFH_AVX512VL + (unspec:VFH_AVX512VL + [(match_operand:VFH_AVX512VL 1 "register_operand" "0,0") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") + (match_operand:VFH_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>")] UNSPEC_FMADDSUB) (match_dup 1) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk,Yk")))] @@ -5217,12 +5256,12 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fmaddsub_<mode>_mask3<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v") - (vec_merge:VF_AVX512VL - (unspec:VF_AVX512VL - [(match_operand:VF_AVX512VL 1 "register_operand" "v") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") - (match_operand:VF_AVX512VL 3 "register_operand" "0")] + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v") + (vec_merge:VFH_AVX512VL + (unspec:VFH_AVX512VL + [(match_operand:VFH_AVX512VL 1 "register_operand" "v") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") + (match_operand:VFH_AVX512VL 3 "register_operand" "0")] UNSPEC_FMADDSUB) (match_dup 3) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))] @@ -5251,12 +5290,12 @@ (set_attr "mode" "<MODE>")]) (define_insn "<sd_mask_codefor>fma_fmsubadd_<mode><sd_maskz_name><round_name>" - [(set (match_operand:VF_SF_AVX512VL 0 "register_operand" "=v,v,v") - (unspec:VF_SF_AVX512VL - [(match_operand:VF_SF_AVX512VL 1 "<round_nimm_predicate>" "%0,0,v") - (match_operand:VF_SF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v,<round_constraint>") - (neg:VF_SF_AVX512VL - (match_operand:VF_SF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>,0"))] + [(set (match_operand:VFH_SF_AVX512VL 0 "register_operand" "=v,v,v") + (unspec:VFH_SF_AVX512VL + [(match_operand:VFH_SF_AVX512VL 1 "<round_nimm_predicate>" "%0,0,v") + (match_operand:VFH_SF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v,<round_constraint>") + (neg:VFH_SF_AVX512VL + (match_operand:VFH_SF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>,0"))] UNSPEC_FMADDSUB))] "TARGET_AVX512F && <sd_mask_mode512bit_condition> && <round_mode512bit_condition>" "@ @@ -5267,13 +5306,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fmsubadd_<mode>_mask<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v,v") - (vec_merge:VF_AVX512VL - (unspec:VF_AVX512VL - [(match_operand:VF_AVX512VL 1 "register_operand" "0,0") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>"))] + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v,v") + (vec_merge:VFH_AVX512VL + (unspec:VFH_AVX512VL + [(match_operand:VFH_AVX512VL 1 "register_operand" "0,0") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>,v") + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 3 "<round_nimm_predicate>" "v,<round_constraint>"))] UNSPEC_FMADDSUB) (match_dup 1) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk,Yk")))] @@ -5285,13 +5324,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "<avx512>_fmsubadd_<mode>_mask3<round_name>" - [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v") - (vec_merge:VF_AVX512VL - (unspec:VF_AVX512VL - [(match_operand:VF_AVX512VL 1 "register_operand" "v") - (match_operand:VF_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") - (neg:VF_AVX512VL - (match_operand:VF_AVX512VL 3 "register_operand" "0"))] + [(set (match_operand:VFH_AVX512VL 0 "register_operand" "=v") + (vec_merge:VFH_AVX512VL + (unspec:VFH_AVX512VL + [(match_operand:VFH_AVX512VL 1 "register_operand" "v") + (match_operand:VFH_AVX512VL 2 "<round_nimm_predicate>" "<round_constraint>") + (neg:VFH_AVX512VL + (match_operand:VFH_AVX512VL 3 "register_operand" "0"))] UNSPEC_FMADDSUB) (match_dup 3) (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))] @@ -5304,60 +5343,60 @@ ;; high-order elements from the destination register. (define_expand "fmai_vmfmadd_<mode><round_name>" - [(set (match_operand:VF_128 0 "register_operand") - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>")) + [(set (match_operand:VFH_128 0 "register_operand") + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>")) (match_dup 1) (const_int 1)))] "TARGET_FMA") (define_expand "fmai_vmfmsub_<mode><round_name>" - [(set (match_operand:VF_128 0 "register_operand") - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>"))) + [(set (match_operand:VFH_128 0 "register_operand") + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>"))) (match_dup 1) (const_int 1)))] "TARGET_FMA") (define_expand "fmai_vmfnmadd_<mode><round_name>" - [(set (match_operand:VF_128 0 "register_operand") - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>")) - (match_operand:VF_128 1 "register_operand") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>")) + [(set (match_operand:VFH_128 0 "register_operand") + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>")) + (match_operand:VFH_128 1 "register_operand") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>")) (match_dup 1) (const_int 1)))] "TARGET_FMA") (define_expand "fmai_vmfnmsub_<mode><round_name>" - [(set (match_operand:VF_128 0 "register_operand") - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>")) - (match_operand:VF_128 1 "register_operand") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>"))) + [(set (match_operand:VFH_128 0 "register_operand") + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>")) + (match_operand:VFH_128 1 "register_operand") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>"))) (match_dup 1) (const_int 1)))] "TARGET_FMA") (define_insn "*fmai_fmadd_<mode>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>, v") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>, v") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) (match_dup 1) (const_int 1)))] "TARGET_FMA || TARGET_AVX512F" @@ -5368,13 +5407,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "*fmai_fmsub_<mode>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) (match_dup 1) (const_int 1)))] "TARGET_FMA || TARGET_AVX512F" @@ -5385,13 +5424,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "*fmai_fnmadd_<mode><round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) (match_dup 1) (const_int 1)))] "TARGET_FMA || TARGET_AVX512F" @@ -5402,14 +5441,14 @@ (set_attr "mode" "<MODE>")]) (define_insn "*fmai_fnmsub_<mode><round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) - (match_operand:VF_128 1 "register_operand" "0,0") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) + (match_operand:VFH_128 1 "register_operand" "0,0") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) (match_dup 1) (const_int 1)))] "TARGET_FMA || TARGET_AVX512F" @@ -5420,13 +5459,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "avx512f_vmfmadd_<mode>_mask<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) (match_dup 1) (match_operand:QI 4 "register_operand" "Yk,Yk")) (match_dup 1) @@ -5439,13 +5478,13 @@ (set_attr "mode" "<MODE>")]) (define_insn "avx512f_vmfmadd_<mode>_mask3<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "<round_nimm_scalar_predicate>" "%v") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>") - (match_operand:VF_128 3 "register_operand" "0")) + [(set (match_operand:VFH_128 0 "register_operand" "=v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "<round_nimm_scalar_predicate>" "%v") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>") + (match_operand:VFH_128 3 "register_operand" "0")) (match_dup 3) (match_operand:QI 4 "register_operand" "Yk")) (match_dup 3) @@ -5456,10 +5495,10 @@ (set_attr "mode" "<MODE>")]) (define_expand "avx512f_vmfmadd_<mode>_maskz<round_expand_name>" - [(match_operand:VF_128 0 "register_operand") - (match_operand:VF_128 1 "<round_expand_nimm_predicate>") - (match_operand:VF_128 2 "<round_expand_nimm_predicate>") - (match_operand:VF_128 3 "<round_expand_nimm_predicate>") + [(match_operand:VFH_128 0 "register_operand") + (match_operand:VFH_128 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_128 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_128 3 "<round_expand_nimm_predicate>") (match_operand:QI 4 "register_operand")] "TARGET_AVX512F" { @@ -5470,14 +5509,14 @@ }) (define_insn "avx512f_vmfmadd_<mode>_maskz_1<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) - (match_operand:VF_128 4 "const0_operand" "C,C") + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) + (match_operand:VFH_128 4 "const0_operand" "C,C") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -5489,14 +5528,14 @@ (set_attr "mode" "<MODE>")]) (define_insn "*avx512f_vmfmsub_<mode>_mask<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) (match_dup 1) (match_operand:QI 4 "register_operand" "Yk,Yk")) (match_dup 1) @@ -5509,14 +5548,14 @@ (set_attr "mode" "<MODE>")]) (define_insn "avx512f_vmfmsub_<mode>_mask3<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "<round_nimm_scalar_predicate>" "%v") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>") - (neg:VF_128 - (match_operand:VF_128 3 "register_operand" "0"))) + [(set (match_operand:VFH_128 0 "register_operand" "=v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "<round_nimm_scalar_predicate>" "%v") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>") + (neg:VFH_128 + (match_operand:VFH_128 3 "register_operand" "0"))) (match_dup 3) (match_operand:QI 4 "register_operand" "Yk")) (match_dup 3) @@ -5527,15 +5566,15 @@ (set_attr "mode" "<MODE>")]) (define_insn "*avx512f_vmfmsub_<mode>_maskz_1<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) - (match_operand:VF_128 4 "const0_operand" "C,C") + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) + (match_operand:VFH_128 4 "const0_operand" "C,C") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -5546,15 +5585,15 @@ [(set_attr "type" "ssemuladd") (set_attr "mode" "<MODE>")]) -(define_insn "*avx512f_vmfnmadd_<mode>_mask<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) +(define_insn "avx512f_vmfnmadd_<mode>_mask<round_name>" + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) (match_dup 1) (match_operand:QI 4 "register_operand" "Yk,Yk")) (match_dup 1) @@ -5566,15 +5605,15 @@ [(set_attr "type" "ssemuladd") (set_attr "mode" "<MODE>")]) -(define_insn "*avx512f_vmfnmadd_<mode>_mask3<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>")) - (match_operand:VF_128 1 "<round_nimm_scalar_predicate>" "%v") - (match_operand:VF_128 3 "register_operand" "0")) +(define_insn "avx512f_vmfnmadd_<mode>_mask3<round_name>" + [(set (match_operand:VFH_128 0 "register_operand" "=v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>")) + (match_operand:VFH_128 1 "<round_nimm_scalar_predicate>" "%v") + (match_operand:VFH_128 3 "register_operand" "0")) (match_dup 3) (match_operand:QI 4 "register_operand" "Yk")) (match_dup 3) @@ -5584,16 +5623,30 @@ [(set_attr "type" "ssemuladd") (set_attr "mode" "<MODE>")]) -(define_insn "*avx512f_vmfnmadd_<mode>_maskz_1<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) - (match_operand:VF_128 1 "register_operand" "0,0") - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) - (match_operand:VF_128 4 "const0_operand" "C,C") +(define_expand "avx512f_vmfnmadd_<mode>_maskz<round_expand_name>" + [(match_operand:VFH_128 0 "register_operand") + (match_operand:VFH_128 1 "<round_expand_nimm_predicate>") + (match_operand:VFH_128 2 "<round_expand_nimm_predicate>") + (match_operand:VFH_128 3 "<round_expand_nimm_predicate>") + (match_operand:QI 4 "register_operand")] + "TARGET_AVX512F" +{ + emit_insn (gen_avx512f_vmfnmadd_<mode>_maskz_1<round_expand_name> ( + operands[0], operands[1], operands[2], operands[3], + CONST0_RTX (<MODE>mode), operands[4]<round_expand_operand>)); + DONE; +}) + +(define_insn "avx512f_vmfnmadd_<mode>_maskz_1<round_name>" + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) + (match_operand:VFH_128 1 "register_operand" "0,0") + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>")) + (match_operand:VFH_128 4 "const0_operand" "C,C") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -5605,15 +5658,15 @@ (set_attr "mode" "<MODE>")]) (define_insn "*avx512f_vmfnmsub_<mode>_mask<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) - (match_operand:VF_128 1 "register_operand" "0,0") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) + (match_operand:VFH_128 1 "register_operand" "0,0") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) (match_dup 1) (match_operand:QI 4 "register_operand" "Yk,Yk")) (match_dup 1) @@ -5626,15 +5679,15 @@ (set_attr "mode" "<MODE>")]) (define_insn "*avx512f_vmfnmsub_<mode>_mask3<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>")) - (match_operand:VF_128 1 "<round_nimm_scalar_predicate>" "%v") - (neg:VF_128 - (match_operand:VF_128 3 "register_operand" "0"))) + [(set (match_operand:VFH_128 0 "register_operand" "=v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>")) + (match_operand:VFH_128 1 "<round_nimm_scalar_predicate>" "%v") + (neg:VFH_128 + (match_operand:VFH_128 3 "register_operand" "0"))) (match_dup 3) (match_operand:QI 4 "register_operand" "Yk")) (match_dup 3) @@ -5645,16 +5698,16 @@ (set_attr "mode" "<MODE>")]) (define_insn "*avx512f_vmfnmsub_<mode>_maskz_1<round_name>" - [(set (match_operand:VF_128 0 "register_operand" "=v,v") - (vec_merge:VF_128 - (vec_merge:VF_128 - (fma:VF_128 - (neg:VF_128 - (match_operand:VF_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) - (match_operand:VF_128 1 "register_operand" "0,0") - (neg:VF_128 - (match_operand:VF_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) - (match_operand:VF_128 4 "const0_operand" "C,C") + [(set (match_operand:VFH_128 0 "register_operand" "=v,v") + (vec_merge:VFH_128 + (vec_merge:VFH_128 + (fma:VFH_128 + (neg:VFH_128 + (match_operand:VFH_128 2 "<round_nimm_scalar_predicate>" "<round_constraint>,v")) + (match_operand:VFH_128 1 "register_operand" "0,0") + (neg:VFH_128 + (match_operand:VFH_128 3 "<round_nimm_scalar_predicate>" "v,<round_constraint>"))) + (match_operand:VFH_128 4 "const0_operand" "C,C") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -24371,9 +24424,9 @@ "TARGET_AVX") (define_expand "maskload<mode><avx512fmaskmodelower>" - [(set (match_operand:V48_AVX512VL 0 "register_operand") - (vec_merge:V48_AVX512VL - (match_operand:V48_AVX512VL 1 "memory_operand") + [(set (match_operand:V48H_AVX512VL 0 "register_operand") + (vec_merge:V48H_AVX512VL + (match_operand:V48H_AVX512VL 1 "memory_operand") (match_dup 0) (match_operand:<avx512fmaskmode> 2 "register_operand")))] "TARGET_AVX512F") @@ -24396,9 +24449,9 @@ "TARGET_AVX") (define_expand "maskstore<mode><avx512fmaskmodelower>" - [(set (match_operand:V48_AVX512VL 0 "memory_operand") - (vec_merge:V48_AVX512VL - (match_operand:V48_AVX512VL 1 "register_operand") + [(set (match_operand:V48H_AVX512VL 0 "memory_operand") + (vec_merge:V48H_AVX512VL + (match_operand:V48H_AVX512VL 1 "register_operand") (match_dup 0) (match_operand:<avx512fmaskmode> 2 "register_operand")))] "TARGET_AVX512F") diff --git a/gcc/config/rs6000/rs6000-builtin-new.def b/gcc/config/rs6000/rs6000-builtin-new.def index a8c6b9e..1966516 100644 --- a/gcc/config/rs6000/rs6000-builtin-new.def +++ b/gcc/config/rs6000/rs6000-builtin-new.def @@ -129,6 +129,7 @@ ; mma Needs special handling for MMA ; quad MMA instruction using a register quad as an input operand ; pair MMA instruction using a register pair as an input operand +; mmaint MMA instruction expanding to internal call at GIMPLE time ; no32bit Not valid for TARGET_32BIT ; 32bit Requires different handling for TARGET_32BIT ; cpu This is a "cpu_is" or "cpu_supports" builtin @@ -3584,415 +3585,421 @@ [mma] void __builtin_mma_assemble_acc (v512 *, vuc, vuc, vuc, vuc); - ASSEMBLE_ACC nothing {mma} + ASSEMBLE_ACC nothing {mma,mmaint} v512 __builtin_mma_assemble_acc_internal (vuc, vuc, vuc, vuc); ASSEMBLE_ACC_INTERNAL mma_assemble_acc {mma} void __builtin_mma_assemble_pair (v256 *, vuc, vuc); - ASSEMBLE_PAIR nothing {mma} + ASSEMBLE_PAIR nothing {mma,mmaint} v256 __builtin_mma_assemble_pair_internal (vuc, vuc); ASSEMBLE_PAIR_INTERNAL vsx_assemble_pair {mma} void __builtin_mma_build_acc (v512 *, vuc, vuc, vuc, vuc); - BUILD_ACC nothing {mma} + BUILD_ACC nothing {mma,mmaint} v512 __builtin_mma_build_acc_internal (vuc, vuc, vuc, vuc); BUILD_ACC_INTERNAL mma_assemble_acc {mma} void __builtin_mma_disassemble_acc (void *, v512 *); - DISASSEMBLE_ACC nothing {mma,quad} + DISASSEMBLE_ACC nothing {mma,quad,mmaint} vuc __builtin_mma_disassemble_acc_internal (v512, const int<2>); DISASSEMBLE_ACC_INTERNAL mma_disassemble_acc {mma} void __builtin_mma_disassemble_pair (void *, v256 *); - DISASSEMBLE_PAIR nothing {mma,pair} + DISASSEMBLE_PAIR nothing {mma,pair,mmaint} vuc __builtin_mma_disassemble_pair_internal (v256, const int<2>); DISASSEMBLE_PAIR_INTERNAL vsx_disassemble_pair {mma} void __builtin_mma_pmxvbf16ger2 (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVBF16GER2 nothing {mma} + PMXVBF16GER2 nothing {mma,mmaint} v512 __builtin_mma_pmxvbf16ger2_internal (vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVBF16GER2_INTERNAL mma_pmxvbf16ger2 {mma} void __builtin_mma_pmxvbf16ger2nn (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVBF16GER2NN nothing {mma,quad} + PMXVBF16GER2NN nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvbf16ger2nn_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVBF16GER2NN_INTERNAL mma_pmxvbf16ger2nn {mma,quad} void __builtin_mma_pmxvbf16ger2np (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVBF16GER2NP nothing {mma,quad} + PMXVBF16GER2NP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvbf16ger2np_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVBF16GER2NP_INTERNAL mma_pmxvbf16ger2np {mma,quad} void __builtin_mma_pmxvbf16ger2pn (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVBF16GER2PN nothing {mma,quad} + PMXVBF16GER2PN nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvbf16ger2pn_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVBF16GER2PN_INTERNAL mma_pmxvbf16ger2pn {mma,quad} void __builtin_mma_pmxvbf16ger2pp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVBF16GER2PP nothing {mma,quad} + PMXVBF16GER2PP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvbf16ger2pp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVBF16GER2PP_INTERNAL mma_pmxvbf16ger2pp {mma,quad} void __builtin_mma_pmxvf16ger2 (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVF16GER2 nothing {mma} + PMXVF16GER2 nothing {mma,mmaint} v512 __builtin_mma_pmxvf16ger2_internal (vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVF16GER2_INTERNAL mma_pmxvf16ger2 {mma} void __builtin_mma_pmxvf16ger2nn (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVF16GER2NN nothing {mma,quad} + PMXVF16GER2NN nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf16ger2nn_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVF16GER2NN_INTERNAL mma_pmxvf16ger2nn {mma,quad} void __builtin_mma_pmxvf16ger2np (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVF16GER2NP nothing {mma,quad} + PMXVF16GER2NP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf16ger2np_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVF16GER2NP_INTERNAL mma_pmxvf16ger2np {mma,quad} void __builtin_mma_pmxvf16ger2pn (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVF16GER2PN nothing {mma,quad} + PMXVF16GER2PN nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf16ger2pn_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVF16GER2PN_INTERNAL mma_pmxvf16ger2pn {mma,quad} void __builtin_mma_pmxvf16ger2pp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVF16GER2PP nothing {mma,quad} + PMXVF16GER2PP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf16ger2pp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVF16GER2PP_INTERNAL mma_pmxvf16ger2pp {mma,quad} void __builtin_mma_pmxvf32ger (v512 *, vuc, vuc, const int<4>, const int<4>); - PMXVF32GER nothing {mma} + PMXVF32GER nothing {mma,mmaint} v512 __builtin_mma_pmxvf32ger_internal (vuc, vuc, const int<4>, const int<4>); PMXVF32GER_INTERNAL mma_pmxvf32ger {mma} void __builtin_mma_pmxvf32gernn (v512 *, vuc, vuc, const int<4>, const int<4>); - PMXVF32GERNN nothing {mma,quad} + PMXVF32GERNN nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf32gernn_internal (v512, vuc, vuc, const int<4>, const int<4>); PMXVF32GERNN_INTERNAL mma_pmxvf32gernn {mma,quad} void __builtin_mma_pmxvf32gernp (v512 *, vuc, vuc, const int<4>, const int<4>); - PMXVF32GERNP nothing {mma,quad} + PMXVF32GERNP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf32gernp_internal (v512, vuc, vuc, const int<4>, const int<4>); PMXVF32GERNP_INTERNAL mma_pmxvf32gernp {mma,quad} void __builtin_mma_pmxvf32gerpn (v512 *, vuc, vuc, const int<4>, const int<4>); - PMXVF32GERPN nothing {mma,quad} + PMXVF32GERPN nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf32gerpn_internal (v512, vuc, vuc, const int<4>, const int<4>); PMXVF32GERPN_INTERNAL mma_pmxvf32gerpn {mma,quad} void __builtin_mma_pmxvf32gerpp (v512 *, vuc, vuc, const int<4>, const int<4>); - PMXVF32GERPP nothing {mma,quad} + PMXVF32GERPP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvf32gerpp_internal (v512, vuc, vuc, const int<4>, const int<4>); PMXVF32GERPP_INTERNAL mma_pmxvf32gerpp {mma,quad} void __builtin_mma_pmxvf64ger (v512 *, v256, vuc, const int<4>, const int<2>); - PMXVF64GER nothing {mma,pair} + PMXVF64GER nothing {mma,pair,mmaint} v512 __builtin_mma_pmxvf64ger_internal (v256, vuc, const int<4>, const int<2>); PMXVF64GER_INTERNAL mma_pmxvf64ger {mma,pair} void __builtin_mma_pmxvf64gernn (v512 *, v256, vuc, const int<4>, const int<2>); - PMXVF64GERNN nothing {mma,pair,quad} + PMXVF64GERNN nothing {mma,pair,quad,mmaint} v512 __builtin_mma_pmxvf64gernn_internal (v512, v256, vuc, const int<4>, const int<2>); PMXVF64GERNN_INTERNAL mma_pmxvf64gernn {mma,pair,quad} void __builtin_mma_pmxvf64gernp (v512 *, v256, vuc, const int<4>, const int<2>); - PMXVF64GERNP nothing {mma,pair,quad} + PMXVF64GERNP nothing {mma,pair,quad,mmaint} v512 __builtin_mma_pmxvf64gernp_internal (v512, v256, vuc, const int<4>, const int<2>); PMXVF64GERNP_INTERNAL mma_pmxvf64gernp {mma,pair,quad} void __builtin_mma_pmxvf64gerpn (v512 *, v256, vuc, const int<4>, const int<2>); - PMXVF64GERPN nothing {mma,pair,quad} + PMXVF64GERPN nothing {mma,pair,quad,mmaint} v512 __builtin_mma_pmxvf64gerpn_internal (v512, v256, vuc, const int<4>, const int<2>); PMXVF64GERPN_INTERNAL mma_pmxvf64gerpn {mma,pair,quad} void __builtin_mma_pmxvf64gerpp (v512 *, v256, vuc, const int<4>, const int<2>); - PMXVF64GERPP nothing {mma,pair,quad} + PMXVF64GERPP nothing {mma,pair,quad,mmaint} v512 __builtin_mma_pmxvf64gerpp_internal (v512, v256, vuc, const int<4>, const int<2>); PMXVF64GERPP_INTERNAL mma_pmxvf64gerpp {mma,pair,quad} void __builtin_mma_pmxvi16ger2 (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVI16GER2 nothing {mma} + PMXVI16GER2 nothing {mma,mmaint} v512 __builtin_mma_pmxvi16ger2_internal (vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVI16GER2_INTERNAL mma_pmxvi16ger2 {mma} void __builtin_mma_pmxvi16ger2pp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVI16GER2PP nothing {mma,quad} + PMXVI16GER2PP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvi16ger2pp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVI16GER2PP_INTERNAL mma_pmxvi16ger2pp {mma,quad} void __builtin_mma_pmxvi16ger2s (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVI16GER2S nothing {mma} + PMXVI16GER2S nothing {mma,mmaint} v512 __builtin_mma_pmxvi16ger2s_internal (vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVI16GER2S_INTERNAL mma_pmxvi16ger2s {mma} void __builtin_mma_pmxvi16ger2spp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<2>); - PMXVI16GER2SPP nothing {mma,quad} + PMXVI16GER2SPP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvi16ger2spp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<2>); PMXVI16GER2SPP_INTERNAL mma_pmxvi16ger2spp {mma,quad} void __builtin_mma_pmxvi4ger8 (v512 *, vuc, vuc, const int<4>, const int<4>, const int<8>); - PMXVI4GER8 nothing {mma} + PMXVI4GER8 nothing {mma,mmaint} v512 __builtin_mma_pmxvi4ger8_internal (vuc, vuc, const int<4>, const int<4>, const int<8>); PMXVI4GER8_INTERNAL mma_pmxvi4ger8 {mma} void __builtin_mma_pmxvi4ger8pp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<4>); - PMXVI4GER8PP nothing {mma,quad} + PMXVI4GER8PP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvi4ger8pp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<4>); PMXVI4GER8PP_INTERNAL mma_pmxvi4ger8pp {mma,quad} void __builtin_mma_pmxvi8ger4 (v512 *, vuc, vuc, const int<4>, const int<4>, const int<4>); - PMXVI8GER4 nothing {mma} + PMXVI8GER4 nothing {mma,mmaint} v512 __builtin_mma_pmxvi8ger4_internal (vuc, vuc, const int<4>, const int<4>, const int<4>); PMXVI8GER4_INTERNAL mma_pmxvi8ger4 {mma} void __builtin_mma_pmxvi8ger4pp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<4>); - PMXVI8GER4PP nothing {mma,quad} + PMXVI8GER4PP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvi8ger4pp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<4>); PMXVI8GER4PP_INTERNAL mma_pmxvi8ger4pp {mma,quad} void __builtin_mma_pmxvi8ger4spp (v512 *, vuc, vuc, const int<4>, const int<4>, const int<4>); - PMXVI8GER4SPP nothing {mma,quad} + PMXVI8GER4SPP nothing {mma,quad,mmaint} v512 __builtin_mma_pmxvi8ger4spp_internal (v512, vuc, vuc, const int<4>, const int<4>, const int<4>); PMXVI8GER4SPP_INTERNAL mma_pmxvi8ger4spp {mma,quad} void __builtin_mma_xvbf16ger2 (v512 *, vuc, vuc); - XVBF16GER2 nothing {mma} + XVBF16GER2 nothing {mma,mmaint} v512 __builtin_mma_xvbf16ger2_internal (vuc, vuc); XVBF16GER2_INTERNAL mma_xvbf16ger2 {mma} void __builtin_mma_xvbf16ger2nn (v512 *, vuc, vuc); - XVBF16GER2NN nothing {mma,quad} + XVBF16GER2NN nothing {mma,quad,mmaint} v512 __builtin_mma_xvbf16ger2nn_internal (v512, vuc, vuc); XVBF16GER2NN_INTERNAL mma_xvbf16ger2nn {mma,quad} void __builtin_mma_xvbf16ger2np (v512 *, vuc, vuc); - XVBF16GER2NP nothing {mma,quad} + XVBF16GER2NP nothing {mma,quad,mmaint} v512 __builtin_mma_xvbf16ger2np_internal (v512, vuc, vuc); XVBF16GER2NP_INTERNAL mma_xvbf16ger2np {mma,quad} void __builtin_mma_xvbf16ger2pn (v512 *, vuc, vuc); - XVBF16GER2PN nothing {mma,quad} + XVBF16GER2PN nothing {mma,quad,mmaint} v512 __builtin_mma_xvbf16ger2pn_internal (v512, vuc, vuc); XVBF16GER2PN_INTERNAL mma_xvbf16ger2pn {mma,quad} void __builtin_mma_xvbf16ger2pp (v512 *, vuc, vuc); - XVBF16GER2PP nothing {mma,quad} + XVBF16GER2PP nothing {mma,quad,mmaint} v512 __builtin_mma_xvbf16ger2pp_internal (v512, vuc, vuc); XVBF16GER2PP_INTERNAL mma_xvbf16ger2pp {mma,quad} void __builtin_mma_xvf16ger2 (v512 *, vuc, vuc); - XVF16GER2 nothing {mma} + XVF16GER2 nothing {mma,mmaint} v512 __builtin_mma_xvf16ger2_internal (vuc, vuc); XVF16GER2_INTERNAL mma_xvf16ger2 {mma} void __builtin_mma_xvf16ger2nn (v512 *, vuc, vuc); - XVF16GER2NN nothing {mma,quad} + XVF16GER2NN nothing {mma,quad,mmaint} v512 __builtin_mma_xvf16ger2nn_internal (v512, vuc, vuc); XVF16GER2NN_INTERNAL mma_xvf16ger2nn {mma,quad} void __builtin_mma_xvf16ger2np (v512 *, vuc, vuc); - XVF16GER2NP nothing {mma,quad} + XVF16GER2NP nothing {mma,quad,mmaint} v512 __builtin_mma_xvf16ger2np_internal (v512, vuc, vuc); XVF16GER2NP_INTERNAL mma_xvf16ger2np {mma,quad} void __builtin_mma_xvf16ger2pn (v512 *, vuc, vuc); - XVF16GER2PN nothing {mma,quad} + XVF16GER2PN nothing {mma,quad,mmaint} v512 __builtin_mma_xvf16ger2pn_internal (v512, vuc, vuc); XVF16GER2PN_INTERNAL mma_xvf16ger2pn {mma,quad} void __builtin_mma_xvf16ger2pp (v512 *, vuc, vuc); - XVF16GER2PP nothing {mma,quad} + XVF16GER2PP nothing {mma,quad,mmaint} v512 __builtin_mma_xvf16ger2pp_internal (v512, vuc, vuc); XVF16GER2PP_INTERNAL mma_xvf16ger2pp {mma,quad} void __builtin_mma_xvf32ger (v512 *, vuc, vuc); - XVF32GER nothing {mma} + XVF32GER nothing {mma,mmaint} v512 __builtin_mma_xvf32ger_internal (vuc, vuc); XVF32GER_INTERNAL mma_xvf32ger {mma} void __builtin_mma_xvf32gernn (v512 *, vuc, vuc); - XVF32GERNN nothing {mma,quad} + XVF32GERNN nothing {mma,quad,mmaint} v512 __builtin_mma_xvf32gernn_internal (v512, vuc, vuc); XVF32GERNN_INTERNAL mma_xvf32gernn {mma,quad} void __builtin_mma_xvf32gernp (v512 *, vuc, vuc); - XVF32GERNP nothing {mma,quad} + XVF32GERNP nothing {mma,quad,mmaint} v512 __builtin_mma_xvf32gernp_internal (v512, vuc, vuc); XVF32GERNP_INTERNAL mma_xvf32gernp {mma,quad} void __builtin_mma_xvf32gerpn (v512 *, vuc, vuc); - XVF32GERPN nothing {mma,quad} + XVF32GERPN nothing {mma,quad,mmaint} v512 __builtin_mma_xvf32gerpn_internal (v512, vuc, vuc); XVF32GERPN_INTERNAL mma_xvf32gerpn {mma,quad} void __builtin_mma_xvf32gerpp (v512 *, vuc, vuc); - XVF32GERPP nothing {mma,quad} + XVF32GERPP nothing {mma,quad,mmaint} v512 __builtin_mma_xvf32gerpp_internal (v512, vuc, vuc); XVF32GERPP_INTERNAL mma_xvf32gerpp {mma,quad} void __builtin_mma_xvf64ger (v512 *, v256, vuc); - XVF64GER nothing {mma,pair} + XVF64GER nothing {mma,pair,mmaint} v512 __builtin_mma_xvf64ger_internal (v256, vuc); XVF64GER_INTERNAL mma_xvf64ger {mma,pair} void __builtin_mma_xvf64gernn (v512 *, v256, vuc); - XVF64GERNN nothing {mma,pair,quad} + XVF64GERNN nothing {mma,pair,quad,mmaint} v512 __builtin_mma_xvf64gernn_internal (v512, v256, vuc); XVF64GERNN_INTERNAL mma_xvf64gernn {mma,pair,quad} void __builtin_mma_xvf64gernp (v512 *, v256, vuc); - XVF64GERNP nothing {mma,pair,quad} + XVF64GERNP nothing {mma,pair,quad,mmaint} v512 __builtin_mma_xvf64gernp_internal (v512, v256, vuc); XVF64GERNP_INTERNAL mma_xvf64gernp {mma,pair,quad} void __builtin_mma_xvf64gerpn (v512 *, v256, vuc); - XVF64GERPN nothing {mma,pair,quad} + XVF64GERPN nothing {mma,pair,quad,mmaint} v512 __builtin_mma_xvf64gerpn_internal (v512, v256, vuc); XVF64GERPN_INTERNAL mma_xvf64gerpn {mma,pair,quad} void __builtin_mma_xvf64gerpp (v512 *, v256, vuc); - XVF64GERPP nothing {mma,pair,quad} + XVF64GERPP nothing {mma,pair,quad,mmaint} v512 __builtin_mma_xvf64gerpp_internal (v512, v256, vuc); XVF64GERPP_INTERNAL mma_xvf64gerpp {mma,pair,quad} void __builtin_mma_xvi16ger2 (v512 *, vuc, vuc); - XVI16GER2 nothing {mma} + XVI16GER2 nothing {mma,mmaint} v512 __builtin_mma_xvi16ger2_internal (vuc, vuc); XVI16GER2_INTERNAL mma_xvi16ger2 {mma} void __builtin_mma_xvi16ger2pp (v512 *, vuc, vuc); - XVI16GER2PP nothing {mma,quad} + XVI16GER2PP nothing {mma,quad,mmaint} v512 __builtin_mma_xvi16ger2pp_internal (v512, vuc, vuc); XVI16GER2PP_INTERNAL mma_xvi16ger2pp {mma,quad} void __builtin_mma_xvi16ger2s (v512 *, vuc, vuc); - XVI16GER2S nothing {mma} + XVI16GER2S nothing {mma,mmaint} v512 __builtin_mma_xvi16ger2s_internal (vuc, vuc); XVI16GER2S_INTERNAL mma_xvi16ger2s {mma} void __builtin_mma_xvi16ger2spp (v512 *, vuc, vuc); - XVI16GER2SPP nothing {mma,quad} + XVI16GER2SPP nothing {mma,quad,mmaint} v512 __builtin_mma_xvi16ger2spp_internal (v512, vuc, vuc); XVI16GER2SPP_INTERNAL mma_xvi16ger2spp {mma,quad} void __builtin_mma_xvi4ger8 (v512 *, vuc, vuc); - XVI4GER8 nothing {mma} + XVI4GER8 nothing {mma,mmaint} v512 __builtin_mma_xvi4ger8_internal (vuc, vuc); XVI4GER8_INTERNAL mma_xvi4ger8 {mma} void __builtin_mma_xvi4ger8pp (v512 *, vuc, vuc); - XVI4GER8PP nothing {mma,quad} + XVI4GER8PP nothing {mma,quad,mmaint} v512 __builtin_mma_xvi4ger8pp_internal (v512, vuc, vuc); XVI4GER8PP_INTERNAL mma_xvi4ger8pp {mma,quad} void __builtin_mma_xvi8ger4 (v512 *, vuc, vuc); - XVI8GER4 nothing {mma} + XVI8GER4 nothing {mma,mmaint} v512 __builtin_mma_xvi8ger4_internal (vuc, vuc); XVI8GER4_INTERNAL mma_xvi8ger4 {mma} void __builtin_mma_xvi8ger4pp (v512 *, vuc, vuc); - XVI8GER4PP nothing {mma,quad} + XVI8GER4PP nothing {mma,quad,mmaint} v512 __builtin_mma_xvi8ger4pp_internal (v512, vuc, vuc); XVI8GER4PP_INTERNAL mma_xvi8ger4pp {mma,quad} void __builtin_mma_xvi8ger4spp (v512 *, vuc, vuc); - XVI8GER4SPP nothing {mma,quad} + XVI8GER4SPP nothing {mma,quad,mmaint} v512 __builtin_mma_xvi8ger4spp_internal (v512, vuc, vuc); XVI8GER4SPP_INTERNAL mma_xvi8ger4spp {mma,quad} void __builtin_mma_xxmfacc (v512 *); - XXMFACC nothing {mma,quad} + XXMFACC nothing {mma,quad,mmaint} v512 __builtin_mma_xxmfacc_internal (v512); XXMFACC_INTERNAL mma_xxmfacc {mma,quad} void __builtin_mma_xxmtacc (v512 *); - XXMTACC nothing {mma,quad} + XXMTACC nothing {mma,quad,mmaint} v512 __builtin_mma_xxmtacc_internal (v512); XXMTACC_INTERNAL mma_xxmtacc {mma,quad} void __builtin_mma_xxsetaccz (v512 *); - XXSETACCZ nothing {mma} + XXSETACCZ nothing {mma,mmaint} v512 __builtin_mma_xxsetaccz_internal (); XXSETACCZ_INTERNAL mma_xxsetaccz {mma} void __builtin_vsx_assemble_pair (v256 *, vuc, vuc); - ASSEMBLE_PAIR_V nothing {mma} + ASSEMBLE_PAIR_V nothing {mma,mmaint} v256 __builtin_vsx_assemble_pair_internal (vuc, vuc); ASSEMBLE_PAIR_V_INTERNAL vsx_assemble_pair {mma} void __builtin_vsx_build_pair (v256 *, vuc, vuc); - BUILD_PAIR nothing {mma} + BUILD_PAIR nothing {mma,mmaint} v256 __builtin_vsx_build_pair_internal (vuc, vuc); BUILD_PAIR_INTERNAL vsx_assemble_pair {mma} void __builtin_vsx_disassemble_pair (void *, v256 *); - DISASSEMBLE_PAIR_V nothing {mma,pair} + DISASSEMBLE_PAIR_V nothing {mma,pair,mmaint} vuc __builtin_vsx_disassemble_pair_internal (v256, const int<2>); DISASSEMBLE_PAIR_V_INTERNAL vsx_disassemble_pair {mma} + + v256 __builtin_vsx_lxvp (unsigned long, const v256 *); + LXVP nothing {mma} + + void __builtin_vsx_stxvp (v256, unsigned long, const v256 *); + STXVP nothing {mma,pair} diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index a55cb7c..7d48548 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -190,6 +190,7 @@ static tree builtin_function_type (machine_mode, machine_mode, static void rs6000_common_init_builtins (void); static void htm_init_builtins (void); static void mma_init_builtins (void); +static bool rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi); /* Hash table to keep track of the argument types for builtin functions. */ @@ -12024,6 +12025,9 @@ rs6000_gimple_fold_mma_builtin (gimple_stmt_iterator *gsi) bool rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi) { + if (new_builtins_are_live) + return rs6000_gimple_fold_new_builtin (gsi); + gimple *stmt = gsi_stmt (*gsi); tree fndecl = gimple_call_fndecl (stmt); gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD); @@ -12971,6 +12975,35 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi) return false; } +/* Helper function to sort out which built-ins may be valid without having + a LHS. */ +static bool +rs6000_new_builtin_valid_without_lhs (enum rs6000_gen_builtins fn_code, + tree fndecl) +{ + if (TREE_TYPE (TREE_TYPE (fndecl)) == void_type_node) + return true; + + switch (fn_code) + { + case RS6000_BIF_STVX_V16QI: + case RS6000_BIF_STVX_V8HI: + case RS6000_BIF_STVX_V4SI: + case RS6000_BIF_STVX_V4SF: + case RS6000_BIF_STVX_V2DI: + case RS6000_BIF_STVX_V2DF: + case RS6000_BIF_STXVW4X_V16QI: + case RS6000_BIF_STXVW4X_V8HI: + case RS6000_BIF_STXVW4X_V4SF: + case RS6000_BIF_STXVW4X_V4SI: + case RS6000_BIF_STXVD2X_V2DF: + case RS6000_BIF_STXVD2X_V2DI: + return true; + default: + return false; + } +} + /* Check whether a builtin function is supported in this target configuration. */ bool @@ -13024,6 +13057,1175 @@ rs6000_new_builtin_is_supported (enum rs6000_gen_builtins fncode) gcc_unreachable (); } +/* Expand the MMA built-ins early, so that we can convert the pass-by-reference + __vector_quad arguments into pass-by-value arguments, leading to more + efficient code generation. */ +static bool +rs6000_gimple_fold_new_mma_builtin (gimple_stmt_iterator *gsi, + rs6000_gen_builtins fn_code) +{ + gimple *stmt = gsi_stmt (*gsi); + size_t fncode = (size_t) fn_code; + + if (!bif_is_mma (rs6000_builtin_info_x[fncode])) + return false; + + /* Each call that can be gimple-expanded has an associated built-in + function that it will expand into. If this one doesn't, we have + already expanded it! Exceptions: lxvp and stxvp. */ + if (rs6000_builtin_info_x[fncode].assoc_bif == RS6000_BIF_NONE + && fncode != RS6000_BIF_LXVP + && fncode != RS6000_BIF_STXVP) + return false; + + bifdata *bd = &rs6000_builtin_info_x[fncode]; + unsigned nopnds = bd->nargs; + gimple_seq new_seq = NULL; + gimple *new_call; + tree new_decl; + + /* Compatibility built-ins; we used to call these + __builtin_mma_{dis,}assemble_pair, but now we call them + __builtin_vsx_{dis,}assemble_pair. Handle the old versions. */ + if (fncode == RS6000_BIF_ASSEMBLE_PAIR) + fncode = RS6000_BIF_ASSEMBLE_PAIR_V; + else if (fncode == RS6000_BIF_DISASSEMBLE_PAIR) + fncode = RS6000_BIF_DISASSEMBLE_PAIR_V; + + if (fncode == RS6000_BIF_DISASSEMBLE_ACC + || fncode == RS6000_BIF_DISASSEMBLE_PAIR_V) + { + /* This is an MMA disassemble built-in function. */ + push_gimplify_context (true); + unsigned nvec = (fncode == RS6000_BIF_DISASSEMBLE_ACC) ? 4 : 2; + tree dst_ptr = gimple_call_arg (stmt, 0); + tree src_ptr = gimple_call_arg (stmt, 1); + tree src_type = TREE_TYPE (src_ptr); + tree src = create_tmp_reg_or_ssa_name (TREE_TYPE (src_type)); + gimplify_assign (src, build_simple_mem_ref (src_ptr), &new_seq); + + /* If we are not disassembling an accumulator/pair or our destination is + another accumulator/pair, then just copy the entire thing as is. */ + if ((fncode == RS6000_BIF_DISASSEMBLE_ACC + && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_quad_type_node) + || (fncode == RS6000_BIF_DISASSEMBLE_PAIR_V + && TREE_TYPE (TREE_TYPE (dst_ptr)) == vector_pair_type_node)) + { + tree dst = build_simple_mem_ref (build1 (VIEW_CONVERT_EXPR, + src_type, dst_ptr)); + gimplify_assign (dst, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + + /* If we're disassembling an accumulator into a different type, we need + to emit a xxmfacc instruction now, since we cannot do it later. */ + if (fncode == RS6000_BIF_DISASSEMBLE_ACC) + { + new_decl = rs6000_builtin_decls_x[RS6000_BIF_XXMFACC_INTERNAL]; + new_call = gimple_build_call (new_decl, 1, src); + src = create_tmp_reg_or_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, src); + gimple_seq_add_stmt (&new_seq, new_call); + } + + /* Copy the accumulator/pair vector by vector. */ + new_decl + = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif]; + tree dst_type = build_pointer_type_for_mode (unsigned_V16QI_type_node, + ptr_mode, true); + tree dst_base = build1 (VIEW_CONVERT_EXPR, dst_type, dst_ptr); + for (unsigned i = 0; i < nvec; i++) + { + unsigned index = WORDS_BIG_ENDIAN ? i : nvec - 1 - i; + tree dst = build2 (MEM_REF, unsigned_V16QI_type_node, dst_base, + build_int_cst (dst_type, index * 16)); + tree dstssa = create_tmp_reg_or_ssa_name (unsigned_V16QI_type_node); + new_call = gimple_build_call (new_decl, 2, src, + build_int_cstu (uint16_type_node, i)); + gimple_call_set_lhs (new_call, dstssa); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (dst, dstssa, &new_seq); + } + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + + /* TODO: Do some factoring on these two chunks. */ + if (fncode == RS6000_BIF_LXVP) + { + push_gimplify_context (true); + tree offset = gimple_call_arg (stmt, 0); + tree ptr = gimple_call_arg (stmt, 1); + tree lhs = gimple_call_lhs (stmt); + if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) + ptr = build1 (VIEW_CONVERT_EXPR, + build_pointer_type (vector_pair_type_node), ptr); + tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, + TREE_TYPE (ptr), ptr, offset)); + gimplify_assign (lhs, mem, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + + if (fncode == RS6000_BIF_STXVP) + { + push_gimplify_context (true); + tree src = gimple_call_arg (stmt, 0); + tree offset = gimple_call_arg (stmt, 1); + tree ptr = gimple_call_arg (stmt, 2); + if (TREE_TYPE (TREE_TYPE (ptr)) != vector_pair_type_node) + ptr = build1 (VIEW_CONVERT_EXPR, + build_pointer_type (vector_pair_type_node), ptr); + tree mem = build_simple_mem_ref (build2 (POINTER_PLUS_EXPR, + TREE_TYPE (ptr), ptr, offset)); + gimplify_assign (mem, src, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + return true; + } + + /* Convert this built-in into an internal version that uses pass-by-value + arguments. The internal built-in is found in the assoc_bif field. */ + new_decl = rs6000_builtin_decls_x[rs6000_builtin_info_x[fncode].assoc_bif]; + tree lhs, op[MAX_MMA_OPERANDS]; + tree acc = gimple_call_arg (stmt, 0); + push_gimplify_context (true); + + if (bif_is_quad (*bd)) + { + /* This built-in has a pass-by-reference accumulator input, so load it + into a temporary accumulator for use as a pass-by-value input. */ + op[0] = create_tmp_reg_or_ssa_name (vector_quad_type_node); + for (unsigned i = 1; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i); + gimplify_assign (op[0], build_simple_mem_ref (acc), &new_seq); + } + else + { + /* This built-in does not use its pass-by-reference accumulator argument + as an input argument, so remove it from the input list. */ + nopnds--; + for (unsigned i = 0; i < nopnds; i++) + op[i] = gimple_call_arg (stmt, i + 1); + } + + switch (nopnds) + { + case 0: + new_call = gimple_build_call (new_decl, 0); + break; + case 1: + new_call = gimple_build_call (new_decl, 1, op[0]); + break; + case 2: + new_call = gimple_build_call (new_decl, 2, op[0], op[1]); + break; + case 3: + new_call = gimple_build_call (new_decl, 3, op[0], op[1], op[2]); + break; + case 4: + new_call = gimple_build_call (new_decl, 4, op[0], op[1], op[2], op[3]); + break; + case 5: + new_call = gimple_build_call (new_decl, 5, op[0], op[1], op[2], op[3], + op[4]); + break; + case 6: + new_call = gimple_build_call (new_decl, 6, op[0], op[1], op[2], op[3], + op[4], op[5]); + break; + case 7: + new_call = gimple_build_call (new_decl, 7, op[0], op[1], op[2], op[3], + op[4], op[5], op[6]); + break; + default: + gcc_unreachable (); + } + + if (fncode == RS6000_BIF_BUILD_PAIR || fncode == RS6000_BIF_ASSEMBLE_PAIR_V) + lhs = create_tmp_reg_or_ssa_name (vector_pair_type_node); + else + lhs = create_tmp_reg_or_ssa_name (vector_quad_type_node); + gimple_call_set_lhs (new_call, lhs); + gimple_seq_add_stmt (&new_seq, new_call); + gimplify_assign (build_simple_mem_ref (acc), lhs, &new_seq); + pop_gimplify_context (NULL); + gsi_replace_with_seq (gsi, new_seq, true); + + return true; +} + +/* Fold a machine-dependent built-in in GIMPLE. (For folding into + a constant, use rs6000_fold_builtin.) */ +static bool +rs6000_gimple_fold_new_builtin (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree fndecl = gimple_call_fndecl (stmt); + gcc_checking_assert (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD); + enum rs6000_gen_builtins fn_code + = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); + tree arg0, arg1, lhs, temp; + enum tree_code bcode; + gimple *g; + + size_t uns_fncode = (size_t) fn_code; + enum insn_code icode = rs6000_builtin_info_x[uns_fncode].icode; + const char *fn_name1 = rs6000_builtin_info_x[uns_fncode].bifname; + const char *fn_name2 = (icode != CODE_FOR_nothing) + ? get_insn_name ((int) icode) + : "nothing"; + + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "rs6000_gimple_fold_new_builtin %d %s %s\n", + fn_code, fn_name1, fn_name2); + + if (!rs6000_fold_gimple) + return false; + + /* Prevent gimple folding for code that does not have a LHS, unless it is + allowed per the rs6000_new_builtin_valid_without_lhs helper function. */ + if (!gimple_call_lhs (stmt) + && !rs6000_new_builtin_valid_without_lhs (fn_code, fndecl)) + return false; + + /* Don't fold invalid builtins, let rs6000_expand_builtin diagnose it. */ + if (!rs6000_new_builtin_is_supported (fn_code)) + return false; + + if (rs6000_gimple_fold_new_mma_builtin (gsi, fn_code)) + return true; + + switch (fn_code) + { + /* Flavors of vec_add. We deliberately don't expand + RS6000_BIF_VADDUQM as it gets lowered from V1TImode to + TImode, resulting in much poorer code generation. */ + case RS6000_BIF_VADDUBM: + case RS6000_BIF_VADDUHM: + case RS6000_BIF_VADDUWM: + case RS6000_BIF_VADDUDM: + case RS6000_BIF_VADDFP: + case RS6000_BIF_XVADDDP: + case RS6000_BIF_XVADDSP: + bcode = PLUS_EXPR; + do_binary: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (lhs))) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (lhs)))) + { + /* Ensure the binary operation is performed in a type + that wraps if it is integral type. */ + gimple_seq stmts = NULL; + tree type = unsigned_type_for (TREE_TYPE (lhs)); + tree uarg0 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + type, arg0); + tree uarg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + type, arg1); + tree res = gimple_build (&stmts, gimple_location (stmt), bcode, + type, uarg0, uarg1); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + g = gimple_build_assign (lhs, VIEW_CONVERT_EXPR, + build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (lhs), res)); + gsi_replace (gsi, g, true); + return true; + } + g = gimple_build_assign (lhs, bcode, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_sub. We deliberately don't expand + RS6000_BIF_VSUBUQM. */ + case RS6000_BIF_VSUBUBM: + case RS6000_BIF_VSUBUHM: + case RS6000_BIF_VSUBUWM: + case RS6000_BIF_VSUBUDM: + case RS6000_BIF_VSUBFP: + case RS6000_BIF_XVSUBDP: + case RS6000_BIF_XVSUBSP: + bcode = MINUS_EXPR; + goto do_binary; + case RS6000_BIF_XVMULSP: + case RS6000_BIF_XVMULDP: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, MULT_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Even element flavors of vec_mul (signed). */ + case RS6000_BIF_VMULESB: + case RS6000_BIF_VMULESH: + case RS6000_BIF_VMULESW: + /* Even element flavors of vec_mul (unsigned). */ + case RS6000_BIF_VMULEUB: + case RS6000_BIF_VMULEUH: + case RS6000_BIF_VMULEUW: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, VEC_WIDEN_MULT_EVEN_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Odd element flavors of vec_mul (signed). */ + case RS6000_BIF_VMULOSB: + case RS6000_BIF_VMULOSH: + case RS6000_BIF_VMULOSW: + /* Odd element flavors of vec_mul (unsigned). */ + case RS6000_BIF_VMULOUB: + case RS6000_BIF_VMULOUH: + case RS6000_BIF_VMULOUW: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, VEC_WIDEN_MULT_ODD_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_div (Integer). */ + case RS6000_BIF_DIV_V2DI: + case RS6000_BIF_UDIV_V2DI: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, TRUNC_DIV_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_div (Float). */ + case RS6000_BIF_XVDIVSP: + case RS6000_BIF_XVDIVDP: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, RDIV_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_and. */ + case RS6000_BIF_VAND_V16QI_UNS: + case RS6000_BIF_VAND_V16QI: + case RS6000_BIF_VAND_V8HI_UNS: + case RS6000_BIF_VAND_V8HI: + case RS6000_BIF_VAND_V4SI_UNS: + case RS6000_BIF_VAND_V4SI: + case RS6000_BIF_VAND_V2DI_UNS: + case RS6000_BIF_VAND_V2DI: + case RS6000_BIF_VAND_V4SF: + case RS6000_BIF_VAND_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_andc. */ + case RS6000_BIF_VANDC_V16QI_UNS: + case RS6000_BIF_VANDC_V16QI: + case RS6000_BIF_VANDC_V8HI_UNS: + case RS6000_BIF_VANDC_V8HI: + case RS6000_BIF_VANDC_V4SI_UNS: + case RS6000_BIF_VANDC_V4SI: + case RS6000_BIF_VANDC_V2DI_UNS: + case RS6000_BIF_VANDC_V2DI: + case RS6000_BIF_VANDC_V4SF: + case RS6000_BIF_VANDC_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_AND_EXPR, arg0, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_nand. */ + case RS6000_BIF_NAND_V16QI_UNS: + case RS6000_BIF_NAND_V16QI: + case RS6000_BIF_NAND_V8HI_UNS: + case RS6000_BIF_NAND_V8HI: + case RS6000_BIF_NAND_V4SI_UNS: + case RS6000_BIF_NAND_V4SI: + case RS6000_BIF_NAND_V2DI_UNS: + case RS6000_BIF_NAND_V2DI: + case RS6000_BIF_NAND_V4SF: + case RS6000_BIF_NAND_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_AND_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_or. */ + case RS6000_BIF_VOR_V16QI_UNS: + case RS6000_BIF_VOR_V16QI: + case RS6000_BIF_VOR_V8HI_UNS: + case RS6000_BIF_VOR_V8HI: + case RS6000_BIF_VOR_V4SI_UNS: + case RS6000_BIF_VOR_V4SI: + case RS6000_BIF_VOR_V2DI_UNS: + case RS6000_BIF_VOR_V2DI: + case RS6000_BIF_VOR_V4SF: + case RS6000_BIF_VOR_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_orc. */ + case RS6000_BIF_ORC_V16QI_UNS: + case RS6000_BIF_ORC_V16QI: + case RS6000_BIF_ORC_V8HI_UNS: + case RS6000_BIF_ORC_V8HI: + case RS6000_BIF_ORC_V4SI_UNS: + case RS6000_BIF_ORC_V4SI: + case RS6000_BIF_ORC_V2DI_UNS: + case RS6000_BIF_ORC_V2DI: + case RS6000_BIF_ORC_V4SF: + case RS6000_BIF_ORC_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_NOT_EXPR, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_IOR_EXPR, arg0, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_xor. */ + case RS6000_BIF_VXOR_V16QI_UNS: + case RS6000_BIF_VXOR_V16QI: + case RS6000_BIF_VXOR_V8HI_UNS: + case RS6000_BIF_VXOR_V8HI: + case RS6000_BIF_VXOR_V4SI_UNS: + case RS6000_BIF_VXOR_V4SI: + case RS6000_BIF_VXOR_V2DI_UNS: + case RS6000_BIF_VXOR_V2DI: + case RS6000_BIF_VXOR_V4SF: + case RS6000_BIF_VXOR_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, BIT_XOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_nor. */ + case RS6000_BIF_VNOR_V16QI_UNS: + case RS6000_BIF_VNOR_V16QI: + case RS6000_BIF_VNOR_V8HI_UNS: + case RS6000_BIF_VNOR_V8HI: + case RS6000_BIF_VNOR_V4SI_UNS: + case RS6000_BIF_VNOR_V4SI: + case RS6000_BIF_VNOR_V2DI_UNS: + case RS6000_BIF_VNOR_V2DI: + case RS6000_BIF_VNOR_V4SF: + case RS6000_BIF_VNOR_V2DF: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_IOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_abs. */ + case RS6000_BIF_ABS_V16QI: + case RS6000_BIF_ABS_V8HI: + case RS6000_BIF_ABS_V4SI: + case RS6000_BIF_ABS_V4SF: + case RS6000_BIF_ABS_V2DI: + case RS6000_BIF_XVABSDP: + case RS6000_BIF_XVABSSP: + arg0 = gimple_call_arg (stmt, 0); + if (INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (arg0))) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (TREE_TYPE (arg0)))) + return false; + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, ABS_EXPR, arg0); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_min. */ + case RS6000_BIF_XVMINDP: + case RS6000_BIF_XVMINSP: + case RS6000_BIF_VMINSD: + case RS6000_BIF_VMINUD: + case RS6000_BIF_VMINSB: + case RS6000_BIF_VMINSH: + case RS6000_BIF_VMINSW: + case RS6000_BIF_VMINUB: + case RS6000_BIF_VMINUH: + case RS6000_BIF_VMINUW: + case RS6000_BIF_VMINFP: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, MIN_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* flavors of vec_max. */ + case RS6000_BIF_XVMAXDP: + case RS6000_BIF_XVMAXSP: + case RS6000_BIF_VMAXSD: + case RS6000_BIF_VMAXUD: + case RS6000_BIF_VMAXSB: + case RS6000_BIF_VMAXSH: + case RS6000_BIF_VMAXSW: + case RS6000_BIF_VMAXUB: + case RS6000_BIF_VMAXUH: + case RS6000_BIF_VMAXUW: + case RS6000_BIF_VMAXFP: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, MAX_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_eqv. */ + case RS6000_BIF_EQV_V16QI: + case RS6000_BIF_EQV_V8HI: + case RS6000_BIF_EQV_V4SI: + case RS6000_BIF_EQV_V4SF: + case RS6000_BIF_EQV_V2DF: + case RS6000_BIF_EQV_V2DI: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + temp = create_tmp_reg_or_ssa_name (TREE_TYPE (arg1)); + g = gimple_build_assign (temp, BIT_XOR_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + g = gimple_build_assign (lhs, BIT_NOT_EXPR, temp); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vec_rotate_left. */ + case RS6000_BIF_VRLB: + case RS6000_BIF_VRLH: + case RS6000_BIF_VRLW: + case RS6000_BIF_VRLD: + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + g = gimple_build_assign (lhs, LROTATE_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + /* Flavors of vector shift right algebraic. + vec_sra{b,h,w} -> vsra{b,h,w}. */ + case RS6000_BIF_VSRAB: + case RS6000_BIF_VSRAH: + case RS6000_BIF_VSRAW: + case RS6000_BIF_VSRAD: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + tree arg1_type = TREE_TYPE (arg1); + tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); + tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); + location_t loc = gimple_location (stmt); + /* Force arg1 into the range valid matching the arg0 type. */ + /* Build a vector consisting of the max valid bit-size values. */ + int n_elts = VECTOR_CST_NELTS (arg1); + tree element_size = build_int_cst (unsigned_element_type, + 128 / n_elts); + tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); + for (int i = 0; i < n_elts; i++) + elts.safe_push (element_size); + tree modulo_tree = elts.build (); + /* Modulo the provided shift value against that vector. */ + gimple_seq stmts = NULL; + tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_arg1_type, arg1); + tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, + unsigned_arg1_type, unsigned_arg1, + modulo_tree); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + /* And finally, do the shift. */ + g = gimple_build_assign (lhs, RSHIFT_EXPR, arg0, new_arg1); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + /* Flavors of vector shift left. + builtin_altivec_vsl{b,h,w} -> vsl{b,h,w}. */ + case RS6000_BIF_VSLB: + case RS6000_BIF_VSLH: + case RS6000_BIF_VSLW: + case RS6000_BIF_VSLD: + { + location_t loc; + gimple_seq stmts = NULL; + arg0 = gimple_call_arg (stmt, 0); + tree arg0_type = TREE_TYPE (arg0); + if (INTEGRAL_TYPE_P (TREE_TYPE (arg0_type)) + && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0_type))) + return false; + arg1 = gimple_call_arg (stmt, 1); + tree arg1_type = TREE_TYPE (arg1); + tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); + tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); + loc = gimple_location (stmt); + lhs = gimple_call_lhs (stmt); + /* Force arg1 into the range valid matching the arg0 type. */ + /* Build a vector consisting of the max valid bit-size values. */ + int n_elts = VECTOR_CST_NELTS (arg1); + int tree_size_in_bits = TREE_INT_CST_LOW (size_in_bytes (arg1_type)) + * BITS_PER_UNIT; + tree element_size = build_int_cst (unsigned_element_type, + tree_size_in_bits / n_elts); + tree_vector_builder elts (unsigned_type_for (arg1_type), n_elts, 1); + for (int i = 0; i < n_elts; i++) + elts.safe_push (element_size); + tree modulo_tree = elts.build (); + /* Modulo the provided shift value against that vector. */ + tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_arg1_type, arg1); + tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, + unsigned_arg1_type, unsigned_arg1, + modulo_tree); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + /* And finally, do the shift. */ + g = gimple_build_assign (lhs, LSHIFT_EXPR, arg0, new_arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + /* Flavors of vector shift right. */ + case RS6000_BIF_VSRB: + case RS6000_BIF_VSRH: + case RS6000_BIF_VSRW: + case RS6000_BIF_VSRD: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + tree arg1_type = TREE_TYPE (arg1); + tree unsigned_arg1_type = unsigned_type_for (TREE_TYPE (arg1)); + tree unsigned_element_type = unsigned_type_for (TREE_TYPE (arg1_type)); + location_t loc = gimple_location (stmt); + gimple_seq stmts = NULL; + /* Convert arg0 to unsigned. */ + tree arg0_unsigned + = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_type_for (TREE_TYPE (arg0)), arg0); + /* Force arg1 into the range valid matching the arg0 type. */ + /* Build a vector consisting of the max valid bit-size values. */ + int n_elts = VECTOR_CST_NELTS (arg1); + tree element_size = build_int_cst (unsigned_element_type, + 128 / n_elts); + tree_vector_builder elts (unsigned_arg1_type, n_elts, 1); + for (int i = 0; i < n_elts; i++) + elts.safe_push (element_size); + tree modulo_tree = elts.build (); + /* Modulo the provided shift value against that vector. */ + tree unsigned_arg1 = gimple_build (&stmts, VIEW_CONVERT_EXPR, + unsigned_arg1_type, arg1); + tree new_arg1 = gimple_build (&stmts, loc, TRUNC_MOD_EXPR, + unsigned_arg1_type, unsigned_arg1, + modulo_tree); + /* Do the shift. */ + tree res + = gimple_build (&stmts, RSHIFT_EXPR, + TREE_TYPE (arg0_unsigned), arg0_unsigned, new_arg1); + /* Convert result back to the lhs type. */ + res = gimple_build (&stmts, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), res); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + replace_call_with_value (gsi, res); + return true; + } + /* Vector loads. */ + case RS6000_BIF_LVX_V16QI: + case RS6000_BIF_LVX_V8HI: + case RS6000_BIF_LVX_V4SI: + case RS6000_BIF_LVX_V4SF: + case RS6000_BIF_LVX_V2DI: + case RS6000_BIF_LVX_V2DF: + case RS6000_BIF_LVX_V1TI: + { + arg0 = gimple_call_arg (stmt, 0); // offset + arg1 = gimple_call_arg (stmt, 1); // address + lhs = gimple_call_lhs (stmt); + location_t loc = gimple_location (stmt); + /* Since arg1 may be cast to a different type, just use ptr_type_node + here instead of trying to enforce TBAA on pointer types. */ + tree arg1_type = ptr_type_node; + tree lhs_type = TREE_TYPE (lhs); + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg0. The resulting type will match + the type of arg1. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg1_type, arg1, temp_offset); + /* Mask off any lower bits from the address. */ + tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, + arg1_type, temp_addr, + build_int_cst (arg1_type, -16)); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (aligned_addr)) + { + tree t = make_ssa_name (TREE_TYPE (aligned_addr)); + gimple *g = gimple_build_assign (t, aligned_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + aligned_addr = t; + } + /* Use the build2 helper to set up the mem_ref. The MEM_REF could also + take an offset, but since we've already incorporated the offset + above, here we just pass in a zero. */ + gimple *g + = gimple_build_assign (lhs, build2 (MEM_REF, lhs_type, aligned_addr, + build_int_cst (arg1_type, 0))); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + /* Vector stores. */ + case RS6000_BIF_STVX_V16QI: + case RS6000_BIF_STVX_V8HI: + case RS6000_BIF_STVX_V4SI: + case RS6000_BIF_STVX_V4SF: + case RS6000_BIF_STVX_V2DI: + case RS6000_BIF_STVX_V2DF: + { + arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ + arg1 = gimple_call_arg (stmt, 1); /* Offset. */ + tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ + location_t loc = gimple_location (stmt); + tree arg0_type = TREE_TYPE (arg0); + /* Use ptr_type_node (no TBAA) for the arg2_type. + FIXME: (Richard) "A proper fix would be to transition this type as + seen from the frontend to GIMPLE, for example in a similar way we + do for MEM_REFs by piggy-backing that on an extra argument, a + constant zero pointer of the alias pointer type to use (which would + also serve as a type indicator of the store itself). I'd use a + target specific internal function for this (not sure if we can have + those target specific, but I guess if it's folded away then that's + fine) and get away with the overload set." */ + tree arg2_type = ptr_type_node; + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg0. The resulting type will match + the type of arg2. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg2_type, arg2, temp_offset); + /* Mask off any lower bits from the address. */ + tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR, + arg2_type, temp_addr, + build_int_cst (arg2_type, -16)); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (aligned_addr)) + { + tree t = make_ssa_name (TREE_TYPE (aligned_addr)); + gimple *g = gimple_build_assign (t, aligned_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + aligned_addr = t; + } + /* The desired gimple result should be similar to: + MEM[(__vector floatD.1407 *)_1] = vf1D.2697; */ + gimple *g + = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr, + build_int_cst (arg2_type, 0)), arg0); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + + /* unaligned Vector loads. */ + case RS6000_BIF_LXVW4X_V16QI: + case RS6000_BIF_LXVW4X_V8HI: + case RS6000_BIF_LXVW4X_V4SF: + case RS6000_BIF_LXVW4X_V4SI: + case RS6000_BIF_LXVD2X_V2DF: + case RS6000_BIF_LXVD2X_V2DI: + { + arg0 = gimple_call_arg (stmt, 0); // offset + arg1 = gimple_call_arg (stmt, 1); // address + lhs = gimple_call_lhs (stmt); + location_t loc = gimple_location (stmt); + /* Since arg1 may be cast to a different type, just use ptr_type_node + here instead of trying to enforce TBAA on pointer types. */ + tree arg1_type = ptr_type_node; + tree lhs_type = TREE_TYPE (lhs); + /* In GIMPLE the type of the MEM_REF specifies the alignment. The + required alignment (power) is 4 bytes regardless of data type. */ + tree align_ltype = build_aligned_type (lhs_type, 4); + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg0. The resulting type will match + the type of arg1. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg0); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg1_type, arg1, temp_offset); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (temp_addr)) + { + tree t = make_ssa_name (TREE_TYPE (temp_addr)); + gimple *g = gimple_build_assign (t, temp_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + temp_addr = t; + } + /* Use the build2 helper to set up the mem_ref. The MEM_REF could also + take an offset, but since we've already incorporated the offset + above, here we just pass in a zero. */ + gimple *g; + g = gimple_build_assign (lhs, build2 (MEM_REF, align_ltype, temp_addr, + build_int_cst (arg1_type, 0))); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + + /* unaligned Vector stores. */ + case RS6000_BIF_STXVW4X_V16QI: + case RS6000_BIF_STXVW4X_V8HI: + case RS6000_BIF_STXVW4X_V4SF: + case RS6000_BIF_STXVW4X_V4SI: + case RS6000_BIF_STXVD2X_V2DF: + case RS6000_BIF_STXVD2X_V2DI: + { + arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */ + arg1 = gimple_call_arg (stmt, 1); /* Offset. */ + tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */ + location_t loc = gimple_location (stmt); + tree arg0_type = TREE_TYPE (arg0); + /* Use ptr_type_node (no TBAA) for the arg2_type. */ + tree arg2_type = ptr_type_node; + /* In GIMPLE the type of the MEM_REF specifies the alignment. The + required alignment (power) is 4 bytes regardless of data type. */ + tree align_stype = build_aligned_type (arg0_type, 4); + /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create + the tree using the value from arg1. */ + gimple_seq stmts = NULL; + tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1); + tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR, + arg2_type, arg2, temp_offset); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + if (!is_gimple_mem_ref_addr (temp_addr)) + { + tree t = make_ssa_name (TREE_TYPE (temp_addr)); + gimple *g = gimple_build_assign (t, temp_addr); + gsi_insert_before (gsi, g, GSI_SAME_STMT); + temp_addr = t; + } + gimple *g; + g = gimple_build_assign (build2 (MEM_REF, align_stype, temp_addr, + build_int_cst (arg2_type, 0)), arg0); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + + /* Vector Fused multiply-add (fma). */ + case RS6000_BIF_VMADDFP: + case RS6000_BIF_XVMADDDP: + case RS6000_BIF_XVMADDSP: + case RS6000_BIF_VMLADDUHM: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + tree arg2 = gimple_call_arg (stmt, 2); + lhs = gimple_call_lhs (stmt); + gcall *g = gimple_build_call_internal (IFN_FMA, 3, arg0, arg1, arg2); + gimple_call_set_lhs (g, lhs); + gimple_call_set_nothrow (g, true); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + + /* Vector compares; EQ, NE, GE, GT, LE. */ + case RS6000_BIF_VCMPEQUB: + case RS6000_BIF_VCMPEQUH: + case RS6000_BIF_VCMPEQUW: + case RS6000_BIF_VCMPEQUD: + /* We deliberately omit RS6000_BIF_VCMPEQUT for now, because gimple + folding produces worse code for 128-bit compares. */ + fold_compare_helper (gsi, EQ_EXPR, stmt); + return true; + + case RS6000_BIF_VCMPNEB: + case RS6000_BIF_VCMPNEH: + case RS6000_BIF_VCMPNEW: + /* We deliberately omit RS6000_BIF_VCMPNET for now, because gimple + folding produces worse code for 128-bit compares. */ + fold_compare_helper (gsi, NE_EXPR, stmt); + return true; + + case RS6000_BIF_CMPGE_16QI: + case RS6000_BIF_CMPGE_U16QI: + case RS6000_BIF_CMPGE_8HI: + case RS6000_BIF_CMPGE_U8HI: + case RS6000_BIF_CMPGE_4SI: + case RS6000_BIF_CMPGE_U4SI: + case RS6000_BIF_CMPGE_2DI: + case RS6000_BIF_CMPGE_U2DI: + /* We deliberately omit RS6000_BIF_CMPGE_1TI and RS6000_BIF_CMPGE_U1TI + for now, because gimple folding produces worse code for 128-bit + compares. */ + fold_compare_helper (gsi, GE_EXPR, stmt); + return true; + + case RS6000_BIF_VCMPGTSB: + case RS6000_BIF_VCMPGTUB: + case RS6000_BIF_VCMPGTSH: + case RS6000_BIF_VCMPGTUH: + case RS6000_BIF_VCMPGTSW: + case RS6000_BIF_VCMPGTUW: + case RS6000_BIF_VCMPGTUD: + case RS6000_BIF_VCMPGTSD: + /* We deliberately omit RS6000_BIF_VCMPGTUT and RS6000_BIF_VCMPGTST + for now, because gimple folding produces worse code for 128-bit + compares. */ + fold_compare_helper (gsi, GT_EXPR, stmt); + return true; + + case RS6000_BIF_CMPLE_16QI: + case RS6000_BIF_CMPLE_U16QI: + case RS6000_BIF_CMPLE_8HI: + case RS6000_BIF_CMPLE_U8HI: + case RS6000_BIF_CMPLE_4SI: + case RS6000_BIF_CMPLE_U4SI: + case RS6000_BIF_CMPLE_2DI: + case RS6000_BIF_CMPLE_U2DI: + /* We deliberately omit RS6000_BIF_CMPLE_1TI and RS6000_BIF_CMPLE_U1TI + for now, because gimple folding produces worse code for 128-bit + compares. */ + fold_compare_helper (gsi, LE_EXPR, stmt); + return true; + + /* flavors of vec_splat_[us]{8,16,32}. */ + case RS6000_BIF_VSPLTISB: + case RS6000_BIF_VSPLTISH: + case RS6000_BIF_VSPLTISW: + { + arg0 = gimple_call_arg (stmt, 0); + lhs = gimple_call_lhs (stmt); + + /* Only fold the vec_splat_*() if the lower bits of arg 0 is a + 5-bit signed constant in range -16 to +15. */ + if (TREE_CODE (arg0) != INTEGER_CST + || !IN_RANGE (TREE_INT_CST_LOW (arg0), -16, 15)) + return false; + gimple_seq stmts = NULL; + location_t loc = gimple_location (stmt); + tree splat_value = gimple_convert (&stmts, loc, + TREE_TYPE (TREE_TYPE (lhs)), arg0); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + tree splat_tree = build_vector_from_val (TREE_TYPE (lhs), splat_value); + g = gimple_build_assign (lhs, splat_tree); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + + /* Flavors of vec_splat. */ + /* a = vec_splat (b, 0x3) becomes a = { b[3],b[3],b[3],...}; */ + case RS6000_BIF_VSPLTB: + case RS6000_BIF_VSPLTH: + case RS6000_BIF_VSPLTW: + case RS6000_BIF_XXSPLTD_V2DI: + case RS6000_BIF_XXSPLTD_V2DF: + { + arg0 = gimple_call_arg (stmt, 0); /* input vector. */ + arg1 = gimple_call_arg (stmt, 1); /* index into arg0. */ + /* Only fold the vec_splat_*() if arg1 is both a constant value and + is a valid index into the arg0 vector. */ + unsigned int n_elts = VECTOR_CST_NELTS (arg0); + if (TREE_CODE (arg1) != INTEGER_CST + || TREE_INT_CST_LOW (arg1) > (n_elts -1)) + return false; + lhs = gimple_call_lhs (stmt); + tree lhs_type = TREE_TYPE (lhs); + tree arg0_type = TREE_TYPE (arg0); + tree splat; + if (TREE_CODE (arg0) == VECTOR_CST) + splat = VECTOR_CST_ELT (arg0, TREE_INT_CST_LOW (arg1)); + else + { + /* Determine (in bits) the length and start location of the + splat value for a call to the tree_vec_extract helper. */ + int splat_elem_size = TREE_INT_CST_LOW (size_in_bytes (arg0_type)) + * BITS_PER_UNIT / n_elts; + int splat_start_bit = TREE_INT_CST_LOW (arg1) * splat_elem_size; + tree len = build_int_cst (bitsizetype, splat_elem_size); + tree start = build_int_cst (bitsizetype, splat_start_bit); + splat = tree_vec_extract (gsi, TREE_TYPE (lhs_type), arg0, + len, start); + } + /* And finally, build the new vector. */ + tree splat_tree = build_vector_from_val (lhs_type, splat); + g = gimple_build_assign (lhs, splat_tree); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + + /* vec_mergel (integrals). */ + case RS6000_BIF_VMRGLH: + case RS6000_BIF_VMRGLW: + case RS6000_BIF_XXMRGLW_4SI: + case RS6000_BIF_VMRGLB: + case RS6000_BIF_VEC_MERGEL_V2DI: + case RS6000_BIF_XXMRGLW_4SF: + case RS6000_BIF_VEC_MERGEL_V2DF: + fold_mergehl_helper (gsi, stmt, 1); + return true; + /* vec_mergeh (integrals). */ + case RS6000_BIF_VMRGHH: + case RS6000_BIF_VMRGHW: + case RS6000_BIF_XXMRGHW_4SI: + case RS6000_BIF_VMRGHB: + case RS6000_BIF_VEC_MERGEH_V2DI: + case RS6000_BIF_XXMRGHW_4SF: + case RS6000_BIF_VEC_MERGEH_V2DF: + fold_mergehl_helper (gsi, stmt, 0); + return true; + + /* Flavors of vec_mergee. */ + case RS6000_BIF_VMRGEW_V4SI: + case RS6000_BIF_VMRGEW_V2DI: + case RS6000_BIF_VMRGEW_V4SF: + case RS6000_BIF_VMRGEW_V2DF: + fold_mergeeo_helper (gsi, stmt, 0); + return true; + /* Flavors of vec_mergeo. */ + case RS6000_BIF_VMRGOW_V4SI: + case RS6000_BIF_VMRGOW_V2DI: + case RS6000_BIF_VMRGOW_V4SF: + case RS6000_BIF_VMRGOW_V2DF: + fold_mergeeo_helper (gsi, stmt, 1); + return true; + + /* d = vec_pack (a, b) */ + case RS6000_BIF_VPKUDUM: + case RS6000_BIF_VPKUHUM: + case RS6000_BIF_VPKUWUM: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + lhs = gimple_call_lhs (stmt); + gimple *g = gimple_build_assign (lhs, VEC_PACK_TRUNC_EXPR, arg0, arg1); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + + /* d = vec_unpackh (a) */ + /* Note that the UNPACK_{HI,LO}_EXPR used in the gimple_build_assign call + in this code is sensitive to endian-ness, and needs to be inverted to + handle both LE and BE targets. */ + case RS6000_BIF_VUPKHSB: + case RS6000_BIF_VUPKHSH: + case RS6000_BIF_VUPKHSW: + { + arg0 = gimple_call_arg (stmt, 0); + lhs = gimple_call_lhs (stmt); + if (BYTES_BIG_ENDIAN) + g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); + else + g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + /* d = vec_unpackl (a) */ + case RS6000_BIF_VUPKLSB: + case RS6000_BIF_VUPKLSH: + case RS6000_BIF_VUPKLSW: + { + arg0 = gimple_call_arg (stmt, 0); + lhs = gimple_call_lhs (stmt); + if (BYTES_BIG_ENDIAN) + g = gimple_build_assign (lhs, VEC_UNPACK_LO_EXPR, arg0); + else + g = gimple_build_assign (lhs, VEC_UNPACK_HI_EXPR, arg0); + gimple_set_location (g, gimple_location (stmt)); + gsi_replace (gsi, g, true); + return true; + } + /* There is no gimple type corresponding with pixel, so just return. */ + case RS6000_BIF_VUPKHPX: + case RS6000_BIF_VUPKLPX: + return false; + + /* vec_perm. */ + case RS6000_BIF_VPERM_16QI: + case RS6000_BIF_VPERM_8HI: + case RS6000_BIF_VPERM_4SI: + case RS6000_BIF_VPERM_2DI: + case RS6000_BIF_VPERM_4SF: + case RS6000_BIF_VPERM_2DF: + case RS6000_BIF_VPERM_16QI_UNS: + case RS6000_BIF_VPERM_8HI_UNS: + case RS6000_BIF_VPERM_4SI_UNS: + case RS6000_BIF_VPERM_2DI_UNS: + { + arg0 = gimple_call_arg (stmt, 0); + arg1 = gimple_call_arg (stmt, 1); + tree permute = gimple_call_arg (stmt, 2); + lhs = gimple_call_lhs (stmt); + location_t loc = gimple_location (stmt); + gimple_seq stmts = NULL; + // convert arg0 and arg1 to match the type of the permute + // for the VEC_PERM_EXPR operation. + tree permute_type = (TREE_TYPE (permute)); + tree arg0_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + permute_type, arg0); + tree arg1_ptype = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + permute_type, arg1); + tree lhs_ptype = gimple_build (&stmts, loc, VEC_PERM_EXPR, + permute_type, arg0_ptype, arg1_ptype, + permute); + // Convert the result back to the desired lhs type upon completion. + tree temp = gimple_build (&stmts, loc, VIEW_CONVERT_EXPR, + TREE_TYPE (lhs), lhs_ptype); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + g = gimple_build_assign (lhs, temp); + gimple_set_location (g, loc); + gsi_replace (gsi, g, true); + return true; + } + + default: + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n", + fn_code, fn_name1, fn_name2); + break; + } + + return false; +} + /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient (and in mode MODE if that's convenient). diff --git a/gcc/config/rs6000/rs6000-gen-builtins.c b/gcc/config/rs6000/rs6000-gen-builtins.c index f65932e..7f71121 100644 --- a/gcc/config/rs6000/rs6000-gen-builtins.c +++ b/gcc/config/rs6000/rs6000-gen-builtins.c @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see mma Needs special handling for MMA instructions quad MMA instruction using a register quad as an input operand pair MMA instruction using a register pair as an input operand + mmaint MMA instruction expanding to internal call at GIMPLE time no32bit Not valid for TARGET_32BIT 32bit Requires different handling for TARGET_32BIT cpu This is a "cpu_is" or "cpu_supports" builtin @@ -369,6 +370,7 @@ struct attrinfo bool ismma; bool isquad; bool ispair; + bool ismmaint; bool isno32bit; bool is32bit; bool iscpu; @@ -1363,6 +1365,8 @@ parse_bif_attrs (attrinfo *attrptr) attrptr->isquad = 1; else if (!strcmp (attrname, "pair")) attrptr->ispair = 1; + else if (!strcmp (attrname, "mmaint")) + attrptr->ismmaint = 1; else if (!strcmp (attrname, "no32bit")) attrptr->isno32bit = 1; else if (!strcmp (attrname, "32bit")) @@ -1409,15 +1413,15 @@ parse_bif_attrs (attrinfo *attrptr) (*diag) ("attribute set: init = %d, set = %d, extract = %d, nosoft = %d, " "ldvec = %d, stvec = %d, reve = %d, pred = %d, htm = %d, " "htmspr = %d, htmcr = %d, mma = %d, quad = %d, pair = %d, " - "no32bit = %d, 32bit = %d, cpu = %d, ldstmask = %d, lxvrse = %d, " - "lxvrze = %d, endian = %d.\n", + "mmaint = %d, no32bit = %d, 32bit = %d, cpu = %d, ldstmask = %d, " + "lxvrse = %d, lxvrze = %d, endian = %d.\n", attrptr->isinit, attrptr->isset, attrptr->isextract, attrptr->isnosoft, attrptr->isldvec, attrptr->isstvec, attrptr->isreve, attrptr->ispred, attrptr->ishtm, attrptr->ishtmspr, attrptr->ishtmcr, attrptr->ismma, attrptr->isquad, attrptr->ispair, - attrptr->isno32bit, attrptr->is32bit, attrptr->iscpu, - attrptr->isldstmask, attrptr->islxvrse, attrptr->islxvrze, - attrptr->isendian); + attrptr->ismmaint, attrptr->isno32bit, attrptr->is32bit, + attrptr->iscpu, attrptr->isldstmask, attrptr->islxvrse, + attrptr->islxvrze, attrptr->isendian); #endif return PC_OK; @@ -2223,13 +2227,14 @@ write_decls (void) fprintf (header_file, "#define bif_mma_bit\t\t(0x00000800)\n"); fprintf (header_file, "#define bif_quad_bit\t\t(0x00001000)\n"); fprintf (header_file, "#define bif_pair_bit\t\t(0x00002000)\n"); - fprintf (header_file, "#define bif_no32bit_bit\t\t(0x00004000)\n"); - fprintf (header_file, "#define bif_32bit_bit\t\t(0x00008000)\n"); - fprintf (header_file, "#define bif_cpu_bit\t\t(0x00010000)\n"); - fprintf (header_file, "#define bif_ldstmask_bit\t(0x00020000)\n"); - fprintf (header_file, "#define bif_lxvrse_bit\t\t(0x00040000)\n"); - fprintf (header_file, "#define bif_lxvrze_bit\t\t(0x00080000)\n"); - fprintf (header_file, "#define bif_endian_bit\t\t(0x00100000)\n"); + fprintf (header_file, "#define bif_mmaint_bit\t\t(0x00004000)\n"); + fprintf (header_file, "#define bif_no32bit_bit\t\t(0x00008000)\n"); + fprintf (header_file, "#define bif_32bit_bit\t\t(0x00010000)\n"); + fprintf (header_file, "#define bif_cpu_bit\t\t(0x00020000)\n"); + fprintf (header_file, "#define bif_ldstmask_bit\t(0x00040000)\n"); + fprintf (header_file, "#define bif_lxvrse_bit\t\t(0x00080000)\n"); + fprintf (header_file, "#define bif_lxvrze_bit\t\t(0x00100000)\n"); + fprintf (header_file, "#define bif_endian_bit\t\t(0x00200000)\n"); fprintf (header_file, "\n"); fprintf (header_file, "#define bif_is_init(x)\t\t((x).bifattrs & bif_init_bit)\n"); @@ -2260,6 +2265,8 @@ write_decls (void) fprintf (header_file, "#define bif_is_pair(x)\t\t((x).bifattrs & bif_pair_bit)\n"); fprintf (header_file, + "#define bif_is_mmaint(x)\t\t((x).bifattrs & bif_mmaint_bit)\n"); + fprintf (header_file, "#define bif_is_no32bit(x)\t((x).bifattrs & bif_no32bit_bit)\n"); fprintf (header_file, "#define bif_is_32bit(x)\t((x).bifattrs & bif_32bit_bit)\n"); @@ -2491,6 +2498,8 @@ write_bif_static_init (void) fprintf (init_file, " | bif_quad_bit"); if (bifp->attrs.ispair) fprintf (init_file, " | bif_pair_bit"); + if (bifp->attrs.ismmaint) + fprintf (init_file, " | bif_mmaint_bit"); if (bifp->attrs.isno32bit) fprintf (init_file, " | bif_no32bit_bit"); if (bifp->attrs.is32bit) @@ -2537,10 +2546,9 @@ write_bif_static_init (void) : (bifp->kind == FNK_PURE ? "= pure" : (bifp->kind == FNK_FPMATH ? "= fp, const" : "")))); - bool no_icode = !strcmp (bifp->patname, "nothing"); fprintf (init_file, " /* assoc_bif */\tRS6000_BIF_%s%s\n", - bifp->attrs.ismma && no_icode ? bifp->idname : "NONE", - bifp->attrs.ismma && no_icode ? "_INTERNAL" : ""); + bifp->attrs.ismmaint ? bifp->idname : "NONE", + bifp->attrs.ismmaint ? "_INTERNAL" : ""); fprintf (init_file, " },\n"); } fprintf (init_file, " };\n\n"); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index ad81dfb..060f51a 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -78,6 +78,7 @@ #include "case-cfn-macros.h" #include "ppc-auxv.h" #include "rs6000-internal.h" +#include "rs6000-builtins.h" #include "opts.h" /* This file should be included last. */ @@ -5608,6 +5609,255 @@ rs6000_loop_unroll_adjust (unsigned nunroll, struct loop *loop) return nunroll; } +/* Returns a function decl for a vectorized version of the builtin function + with builtin function code FN and the result vector type TYPE, or NULL_TREE + if it is not available. + + Implement targetm.vectorize.builtin_vectorized_function. */ + +static tree +rs6000_new_builtin_vectorized_function (unsigned int fn, tree type_out, + tree type_in) +{ + machine_mode in_mode, out_mode; + int in_n, out_n; + + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, "rs6000_new_builtin_vectorized_function (%s, %s, %s)\n", + combined_fn_name (combined_fn (fn)), + GET_MODE_NAME (TYPE_MODE (type_out)), + GET_MODE_NAME (TYPE_MODE (type_in))); + + /* TODO: Should this be gcc_assert? */ + if (TREE_CODE (type_out) != VECTOR_TYPE + || TREE_CODE (type_in) != VECTOR_TYPE) + return NULL_TREE; + + out_mode = TYPE_MODE (TREE_TYPE (type_out)); + out_n = TYPE_VECTOR_SUBPARTS (type_out); + in_mode = TYPE_MODE (TREE_TYPE (type_in)); + in_n = TYPE_VECTOR_SUBPARTS (type_in); + + switch (fn) + { + CASE_CFN_COPYSIGN: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_CPSGNDP]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_CPSGNSP]; + if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_COPYSIGN_V4SF]; + break; + CASE_CFN_CEIL: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_XVRDPIP]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_XVRSPIP]; + if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_VRFIP]; + break; + CASE_CFN_FLOOR: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_XVRDPIM]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_XVRSPIM]; + if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_VRFIM]; + break; + CASE_CFN_FMA: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_XVMADDDP]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_XVMADDSP]; + if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_VMADDFP]; + break; + CASE_CFN_TRUNC: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_XVRDPIZ]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_XVRSPIZ]; + if (VECTOR_UNIT_ALTIVEC_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_VRFIZ]; + break; + CASE_CFN_NEARBYINT: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && flag_unsafe_math_optimizations + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_XVRDPI]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && flag_unsafe_math_optimizations + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_XVRSPI]; + break; + CASE_CFN_RINT: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && !flag_trapping_math + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_XVRDPIC]; + if (VECTOR_UNIT_VSX_P (V4SFmode) + && !flag_trapping_math + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_XVRSPIC]; + break; + default: + break; + } + + /* Generate calls to libmass if appropriate. */ + if (rs6000_veclib_handler) + return rs6000_veclib_handler (combined_fn (fn), type_out, type_in); + + return NULL_TREE; +} + +/* Implement targetm.vectorize.builtin_md_vectorized_function. */ + +static tree +rs6000_new_builtin_md_vectorized_function (tree fndecl, tree type_out, + tree type_in) +{ + machine_mode in_mode, out_mode; + int in_n, out_n; + + if (TARGET_DEBUG_BUILTIN) + fprintf (stderr, + "rs6000_new_builtin_md_vectorized_function (%s, %s, %s)\n", + IDENTIFIER_POINTER (DECL_NAME (fndecl)), + GET_MODE_NAME (TYPE_MODE (type_out)), + GET_MODE_NAME (TYPE_MODE (type_in))); + + /* TODO: Should this be gcc_assert? */ + if (TREE_CODE (type_out) != VECTOR_TYPE + || TREE_CODE (type_in) != VECTOR_TYPE) + return NULL_TREE; + + out_mode = TYPE_MODE (TREE_TYPE (type_out)); + out_n = TYPE_VECTOR_SUBPARTS (type_out); + in_mode = TYPE_MODE (TREE_TYPE (type_in)); + in_n = TYPE_VECTOR_SUBPARTS (type_in); + + enum rs6000_gen_builtins fn + = (enum rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); + switch (fn) + { + case RS6000_BIF_RSQRTF: + if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_VRSQRTFP]; + break; + case RS6000_BIF_RSQRT: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_RSQRT_2DF]; + break; + case RS6000_BIF_RECIPF: + if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode) + && out_mode == SFmode && out_n == 4 + && in_mode == SFmode && in_n == 4) + return rs6000_builtin_decls_x[RS6000_BIF_VRECIPFP]; + break; + case RS6000_BIF_RECIP: + if (VECTOR_UNIT_VSX_P (V2DFmode) + && out_mode == DFmode && out_n == 2 + && in_mode == DFmode && in_n == 2) + return rs6000_builtin_decls_x[RS6000_BIF_RECIP_V2DF]; + break; + default: + break; + } + + machine_mode in_vmode = TYPE_MODE (type_in); + machine_mode out_vmode = TYPE_MODE (type_out); + + /* Power10 supported vectorized built-in functions. */ + if (TARGET_POWER10 + && in_vmode == out_vmode + && VECTOR_UNIT_ALTIVEC_OR_VSX_P (in_vmode)) + { + machine_mode exp_mode = DImode; + machine_mode exp_vmode = V2DImode; + enum rs6000_gen_builtins bif; + switch (fn) + { + case RS6000_BIF_DIVWE: + case RS6000_BIF_DIVWEU: + exp_mode = SImode; + exp_vmode = V4SImode; + if (fn == RS6000_BIF_DIVWE) + bif = RS6000_BIF_VDIVESW; + else + bif = RS6000_BIF_VDIVEUW; + break; + case RS6000_BIF_DIVDE: + case RS6000_BIF_DIVDEU: + if (fn == RS6000_BIF_DIVDE) + bif = RS6000_BIF_VDIVESD; + else + bif = RS6000_BIF_VDIVEUD; + break; + case RS6000_BIF_CFUGED: + bif = RS6000_BIF_VCFUGED; + break; + case RS6000_BIF_CNTLZDM: + bif = RS6000_BIF_VCLZDM; + break; + case RS6000_BIF_CNTTZDM: + bif = RS6000_BIF_VCTZDM; + break; + case RS6000_BIF_PDEPD: + bif = RS6000_BIF_VPDEPD; + break; + case RS6000_BIF_PEXTD: + bif = RS6000_BIF_VPEXTD; + break; + default: + return NULL_TREE; + } + + if (in_mode == exp_mode && in_vmode == exp_vmode) + return rs6000_builtin_decls_x[bif]; + } + + return NULL_TREE; +} + /* Handler for the Mathematical Acceleration Subsystem (mass) interface to a library with vectorized intrinsics. */ @@ -5727,6 +5977,9 @@ rs6000_builtin_vectorized_function (unsigned int fn, tree type_out, machine_mode in_mode, out_mode; int in_n, out_n; + if (new_builtins_are_live) + return rs6000_new_builtin_vectorized_function (fn, type_out, type_in); + if (TARGET_DEBUG_BUILTIN) fprintf (stderr, "rs6000_builtin_vectorized_function (%s, %s, %s)\n", combined_fn_name (combined_fn (fn)), @@ -5858,6 +6111,10 @@ rs6000_builtin_md_vectorized_function (tree fndecl, tree type_out, machine_mode in_mode, out_mode; int in_n, out_n; + if (new_builtins_are_live) + return rs6000_new_builtin_md_vectorized_function (fndecl, type_out, + type_in); + if (TARGET_DEBUG_BUILTIN) fprintf (stderr, "rs6000_builtin_md_vectorized_function (%s, %s, %s)\n", IDENTIFIER_POINTER (DECL_NAME (fndecl)), diff --git a/gcc/configure b/gcc/configure index 36dba4e..b3de170 100755 --- a/gcc/configure +++ b/gcc/configure @@ -28881,6 +28881,41 @@ $as_echo "#define HAVE_GCN_SRAM_ECC_GFX908 1" >>confdefs.h fi ;; + arm*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for assembler for arm accepts context-specific architecture extensions" >&5 +$as_echo_n "checking assembler for assembler for arm accepts context-specific architecture extensions... " >&6; } +if ${gcc_cv_as_arm_option_extensions+:} false; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_arm_option_extensions=no + if test x$gcc_cv_as != x; then + $as_echo '.text + .thumb + .syntax unified + vmov.f32 s0, s1' > conftest.s + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -march=armv8.1-m.main+mve -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_arm_option_extensions=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_arm_option_extensions" >&5 +$as_echo "$gcc_cv_as_arm_option_extensions" >&6; } +if test $gcc_cv_as_arm_option_extensions = yes; then + +$as_echo "#define HAVE_GAS_ARM_EXTENDED_ARCH 1" >>confdefs.h + +fi + esac # ??? Not all targets support dwarf2 debug_line, even within a version diff --git a/gcc/configure.ac b/gcc/configure.ac index fadd34d..7d3aab4 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -5357,6 +5357,16 @@ case "$target" in [AC_DEFINE(HAVE_GCN_SRAM_ECC_GFX908, 1, [Define if your assembler allows -mattr=+sram-ecc for gfx908.])]) ;; + arm*) + gcc_GAS_CHECK_FEATURE([assembler for arm accepts context-specific architecture extensions], + gcc_cv_as_arm_option_extensions, + [-march=armv8.1-m.main+mve], + [.text + .thumb + .syntax unified + vmov.f32 s0, s1],, + [AC_DEFINE(HAVE_GAS_ARM_EXTENDED_ARCH, 1, + [Define if your Arm assembler permits context-specific feature extensions.])]) esac # ??? Not all targets support dwarf2 debug_line, even within a version diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4061a85..d04d84f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,40 @@ +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_order): Parse unconstrained + and reproducible modifiers. + (OMP_DISTRIBUTE_CLAUSE_MASK): Add order clause. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * parser.c (cp_parser_omp_clause_default): Handle private and + firstprivate arguments, adjust diagnostics on unknown argument. + * cp-gimplify.c (cxx_omp_finish_clause): Handle OMP_CLAUSE_PRIVATE. + +2021-09-18 Jason Merrill <jason@redhat.com> + + * cp-tree.h (dependentish_scope_p): Declare. + * pt.c (dependentish_scope_p): New. + * parser.c (cp_parser_lookup_name): Return a TYPENAME_TYPE + for lookup of a type in a dependent object. + (cp_parser_template_id): Handle TYPENAME_TYPE. + (cp_parser_template_name): If we're looking for a type, + a name followed by < names a template. + +2021-09-18 Jason Merrill <jason@redhat.com> + + * cp-tree.h: Fix typo in LANG_FLAG list. + +2021-09-17 Jakub Jelinek <jakub@redhat.com> + + * cp-tree.h (finish_omp_atomic): Add r and weak arguments. + * parser.c (cp_parser_omp_atomic): Update function comment for + OpenMP 5.1 atomics, parse OpenMP 5.1 atomics and fail, compare and + weak clauses. + * semantics.c (finish_omp_atomic): Add r and weak arguments, handle + them, handle COND_EXPRs. + * pt.c (tsubst_expr): Adjust for COND_EXPR forms that + finish_omp_atomic can now produce. + 2021-09-16 Patrick Palka <ppalka@redhat.com> PR c++/98486 diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index bf928a8..c86a5fe 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2060,6 +2060,7 @@ cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */) bool make_shared = false; if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_PRIVATE && (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LASTPRIVATE || !OMP_CLAUSE_LASTPRIVATE_LOOP_IV (c))) return; @@ -2080,9 +2081,10 @@ cxx_omp_finish_clause (tree c, gimple_seq *, bool /* openacc */) Save the results, because later we won't be in the right context for making these queries. */ bool first = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE; + bool last = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE; if (!make_shared && CLASS_TYPE_P (inner_type) - && cxx_omp_create_clause_info (c, inner_type, !first, first, !first, + && cxx_omp_create_clause_info (c, inner_type, !first, first, last, true)) make_shared = true; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fb0d5ec..1fcd50c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -469,7 +469,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ICS_THIS_FLAG (in _CONV) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL) STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST) - TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) + TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE) TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) FNDECL_USED_AUTO (in FUNCTION_DECL) DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) @@ -7263,6 +7263,7 @@ extern tree maybe_get_template_decl_from_type_decl (tree); extern int processing_template_parmlist; extern bool dependent_type_p (tree); extern bool dependent_scope_p (tree); +extern bool dependentish_scope_p (tree); extern bool any_dependent_template_arguments_p (const_tree); extern bool any_erroneous_template_args_p (const_tree); extern bool dependent_template_p (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 58ddc6a..722e540 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5772,14 +5772,6 @@ start_decl_1 (tree decl, bool initialized) cp_apply_type_quals_to_decl (cp_type_quals (type), decl); } - if (is_global_var (decl)) - { - type_context_kind context = (DECL_THREAD_LOCAL_P (decl) - ? TCTX_THREAD_STORAGE - : TCTX_STATIC_STORAGE); - verify_type_context (input_location, context, TREE_TYPE (decl)); - } - if (initialized) /* Is it valid for this decl to have an initializer at all? */ { @@ -7977,6 +7969,14 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, && DECL_INITIALIZED_IN_CLASS_P (decl)) check_static_variable_definition (decl, type); + if (!processing_template_decl && VAR_P (decl) && is_global_var (decl)) + { + type_context_kind context = (DECL_THREAD_LOCAL_P (decl) + ? TCTX_THREAD_STORAGE + : TCTX_STATIC_STORAGE); + verify_type_context (input_location, context, TREE_TYPE (decl)); + } + if (init && TREE_CODE (decl) == FUNCTION_DECL) { tree clone; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 20f949e..62908da 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -18187,6 +18187,16 @@ cp_parser_template_id (cp_parser *parser, if (TREE_CODE (template_id) == TEMPLATE_ID_EXPR) SET_EXPR_LOCATION (template_id, combined_loc); } + else if (TREE_CODE (templ) == TYPE_DECL + && TREE_CODE (TREE_TYPE (templ)) == TYPENAME_TYPE) + { + /* Some type template in dependent scope. */ + tree &name = TYPENAME_TYPE_FULLNAME (TREE_TYPE (templ)); + name = build_min_nt_loc (combined_loc, + TEMPLATE_ID_EXPR, + name, arguments); + template_id = templ; + } else { /* If it's not a class-template or a template-template, it should be @@ -18413,8 +18423,8 @@ cp_parser_template_name (cp_parser* parser, } /* cp_parser_lookup_name clears OBJECT_TYPE. */ - const bool scoped_p = ((parser->scope ? parser->scope - : parser->context->object_type) != NULL_TREE); + tree scope = (parser->scope ? parser->scope + : parser->context->object_type); /* Look up the name. */ decl = cp_parser_lookup_name (parser, identifier, @@ -18427,6 +18437,19 @@ cp_parser_template_name (cp_parser* parser, decl = strip_using_decl (decl); + /* 13.3 [temp.names] A < is interpreted as the delimiter of a + template-argument-list if it follows a name that is not a + conversion-function-id and + - that follows the keyword template or a ~ after a nested-name-specifier or + in a class member access expression, or + - for which name lookup finds the injected-class-name of a class template + or finds any declaration of a template, or + - that is an unqualified name for which name lookup either finds one or + more functions or finds nothing, or + - that is a terminal name in a using-declarator (9.9), in a declarator-id + (9.3.4), or in a type-only context other than a nested-name-specifier + (13.8). */ + /* If DECL is a template, then the name was a template-name. */ if (TREE_CODE (decl) == TEMPLATE_DECL) { @@ -18454,11 +18477,7 @@ cp_parser_template_name (cp_parser* parser, } else { - /* The standard does not explicitly indicate whether a name that - names a set of overloaded declarations, some of which are - templates, is a template-name. However, such a name should - be a template-name; otherwise, there is no way to form a - template-id for the overloaded templates. */ + /* Look through an overload set for any templates. */ bool found = false; for (lkp_iterator iter (MAYBE_BASELINK_FUNCTIONS (decl)); @@ -18466,34 +18485,41 @@ cp_parser_template_name (cp_parser* parser, if (TREE_CODE (*iter) == TEMPLATE_DECL) found = true; + /* "an unqualified name for which name lookup either finds one or more + functions or finds nothing". */ if (!found && (cxx_dialect > cxx17) - && !scoped_p + && !scope && cp_lexer_next_token_is (parser->lexer, CPP_LESS) && tag_type == none_type) { - /* [temp.names] says "A name is also considered to refer to a template - if it is an unqualified-id followed by a < and name lookup finds - either one or more functions or finds nothing." */ - /* The "more functions" case. Just use the OVERLOAD as normally. We don't use is_overloaded_fn here to avoid considering BASELINKs. */ if (TREE_CODE (decl) == OVERLOAD /* Name lookup found one function. */ - || TREE_CODE (decl) == FUNCTION_DECL) + || TREE_CODE (decl) == FUNCTION_DECL + /* Name lookup found nothing. */ + || decl == error_mark_node) found = true; - /* Name lookup found nothing. */ - else if (decl == error_mark_node) - return identifier; } + /* "in a type-only context" */ + if (!found && scope + && tag_type != none_type + && dependentish_scope_p (scope) + && cp_parser_nth_token_starts_template_argument_list_p (parser, 1)) + found = true; + if (!found) { /* The name does not name a template. */ cp_parser_error (parser, "expected template-name"); return error_mark_node; } + else if (decl == error_mark_node) + /* Repeat the lookup at instantiation time. */ + decl = identifier; } return decl; @@ -30373,6 +30399,17 @@ cp_parser_lookup_name (cp_parser *parser, tree name, consider class templates. */ : is_template ? LOOK_want::TYPE : prefer_type_arg (tag_type)); + + /* If we know we're looking for a type (e.g. A in p->A::x), + mock up a typename. */ + if (!decl && object_type && tag_type != none_type + && dependentish_scope_p (object_type)) + { + tree type = build_typename_type (object_type, name, name, + typename_type); + decl = TYPE_NAME (type); + } + parser->object_scope = object_type; parser->qualifying_scope = NULL_TREE; } @@ -36951,6 +36988,9 @@ cp_parser_omp_clause_collapse (cp_parser *parser, tree list, location_t location /* OpenMP 2.5: default ( none | shared ) + OpenMP 5.1: + default ( private | firstprivate ) + OpenACC: default ( none | present ) */ @@ -36964,7 +37004,12 @@ cp_parser_omp_clause_default (cp_parser *parser, tree list, matching_parens parens; if (!parens.require_open (parser)) return list; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + if (!is_oacc && cp_lexer_next_token_is_keyword (parser->lexer, RID_PRIVATE)) + { + kind = OMP_CLAUSE_DEFAULT_PRIVATE; + cp_lexer_consume_token (parser->lexer); + } + else 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); @@ -36983,6 +37028,12 @@ cp_parser_omp_clause_default (cp_parser *parser, tree list, kind = OMP_CLAUSE_DEFAULT_PRESENT; break; + case 'f': + if (strcmp ("firstprivate", p) != 0 || is_oacc) + goto invalid_kind; + kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE; + break; + case 's': if (strcmp ("shared", p) != 0 || is_oacc) goto invalid_kind; @@ -37001,7 +37052,8 @@ cp_parser_omp_clause_default (cp_parser *parser, tree list, if (is_oacc) cp_parser_error (parser, "expected %<none%> or %<present%>"); else - cp_parser_error (parser, "expected %<none%> or %<shared%>"); + cp_parser_error (parser, "expected %<none%>, %<shared%>, " + "%<private%> or %<firstprivate%>"); } if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED @@ -37651,18 +37703,42 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, } /* OpenMP 5.0: - order ( concurrent ) */ + order ( concurrent ) + + OpenMP 5.1: + order ( order-modifier : concurrent ) + + order-modifier: + reproducible + unconstrained */ static tree cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) { tree c, id; const char *p; + bool unconstrained = false; matching_parens parens; if (!parens.require_open (parser)) return list; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + if (strcmp (p, "unconstrained") == 0) + unconstrained = true; + else if (strcmp (p, "reproducible") != 0) + { + cp_parser_error (parser, "expected %<reproducible%> or " + "%<unconstrained%>"); + goto out_err; + } + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + } if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { cp_parser_error (parser, "expected %<concurrent%>"); @@ -37682,8 +37758,9 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) if (!parens.require_close (parser)) goto out_err; - /* check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order", location); */ + check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order", location); c = build_omp_clause (location, OMP_CLAUSE_ORDER); + OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; OMP_CLAUSE_CHAIN (c) = list; return c; @@ -43294,7 +43371,8 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ - | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)) + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER)) static tree cp_parser_omp_distribute (cp_parser *parser, cp_token *pragma_tok, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 12c8812..4d42899 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -26970,6 +26970,15 @@ dependent_scope_p (tree scope) && !currently_open_class (scope)); } +/* True if we might find more declarations in SCOPE during instantiation than + we can when parsing the template. */ + +bool +dependentish_scope_p (tree scope) +{ + return dependent_scope_p (scope) || any_dependent_bases_p (scope); +} + /* T is a SCOPE_REF. Return whether it represents a non-static member of an unknown base of 'this' (and is therefore instantiation-dependent). */ diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c index 2c6bcfa..e112ee8 100644 --- a/gcc/cppbuiltin.c +++ b/gcc/cppbuiltin.c @@ -110,6 +110,16 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile) cpp_define (pfile, "__SUPPORT_SNAN__"); if (!flag_errno_math) cpp_define (pfile, "__NO_MATH_ERRNO__"); + if (flag_reciprocal_math) + cpp_define (pfile, "__RECIPROCAL_MATH__"); + if (!flag_signed_zeros) + cpp_define (pfile, "__NO_SIGNED_ZEROS__"); + if (!flag_trapping_math) + cpp_define (pfile, "__NO_TRAPPING_MATH__"); + if (flag_associative_math) + cpp_define (pfile, "__ASSOCIATIVE_MATH__"); + if (flag_rounding_math) + cpp_define (pfile, "__ROUNDING_MATH__"); cpp_define_formatted (pfile, "__FINITE_MATH_ONLY__=%d", flag_finite_math_only); diff --git a/gcc/doc/avr-mmcu.texi b/gcc/doc/avr-mmcu.texi index b024998..da4a5b3 100644 --- a/gcc/doc/avr-mmcu.texi +++ b/gcc/doc/avr-mmcu.texi @@ -38,7 +38,7 @@ @item avr5 ``Enhanced'' devices with 16@tie{}KiB up to 64@tie{}KiB of program memory. -@*@var{mcu}@tie{}= @code{atmega16}, @code{atmega16a}, @code{atmega16hva}, @code{atmega16hva2}, @code{atmega16hvb}, @code{atmega16hvbrevb}, @code{atmega16m1}, @code{atmega16u4}, @code{atmega161}, @code{atmega162}, @code{atmega163}, @code{atmega164a}, @code{atmega164p}, @code{atmega164pa}, @code{atmega165}, @code{atmega165a}, @code{atmega165p}, @code{atmega165pa}, @code{atmega168}, @code{atmega168a}, @code{atmega168p}, @code{atmega168pa}, @code{atmega168pb}, @code{atmega169}, @code{atmega169a}, @code{atmega169p}, @code{atmega169pa}, @code{atmega32}, @code{atmega32a}, @code{atmega32c1}, @code{atmega32hvb}, @code{atmega32hvbrevb}, @code{atmega32m1}, @code{atmega32u4}, @code{atmega32u6}, @code{atmega323}, @code{atmega324a}, @code{atmega324p}, @code{atmega324pa}, @code{atmega325}, @code{atmega325a}, @code{atmega325p}, @code{atmega325pa}, @code{atmega328}, @code{atmega328p}, @code{atmega328pb}, @code{atmega329}, @code{atmega329a}, @code{atmega329p}, @code{atmega329pa}, @code{atmega3250}, @code{atmega3250a}, @code{atmega3250p}, @code{atmega3250pa}, @code{atmega3290}, @code{atmega3290a}, @code{atmega3290p}, @code{atmega3290pa}, @code{atmega406}, @code{atmega64}, @code{atmega64a}, @code{atmega64c1}, @code{atmega64hve}, @code{atmega64hve2}, @code{atmega64m1}, @code{atmega64rfr2}, @code{atmega640}, @code{atmega644}, @code{atmega644a}, @code{atmega644p}, @code{atmega644pa}, @code{atmega644rfr2}, @code{atmega645}, @code{atmega645a}, @code{atmega645p}, @code{atmega649}, @code{atmega649a}, @code{atmega649p}, @code{atmega6450}, @code{atmega6450a}, @code{atmega6450p}, @code{atmega6490}, @code{atmega6490a}, @code{atmega6490p}, @code{ata5795}, @code{ata5790}, @code{ata5790n}, @code{ata5791}, @code{ata6613c}, @code{ata6614q}, @code{ata5782}, @code{ata5831}, @code{ata8210}, @code{ata8510}, @code{ata5702m322}, @code{at90pwm161}, @code{at90pwm216}, @code{at90pwm316}, @code{at90can32}, @code{at90can64}, @code{at90scr100}, @code{at90usb646}, @code{at90usb647}, @code{at94k}, @code{m3000}. +@*@var{mcu}@tie{}= @code{atmega16}, @code{atmega16a}, @code{atmega16hva}, @code{atmega16hva2}, @code{atmega16hvb}, @code{atmega16hvbrevb}, @code{atmega16m1}, @code{atmega16u4}, @code{atmega161}, @code{atmega162}, @code{atmega163}, @code{atmega164a}, @code{atmega164p}, @code{atmega164pa}, @code{atmega165}, @code{atmega165a}, @code{atmega165p}, @code{atmega165pa}, @code{atmega168}, @code{atmega168a}, @code{atmega168p}, @code{atmega168pa}, @code{atmega168pb}, @code{atmega169}, @code{atmega169a}, @code{atmega169p}, @code{atmega169pa}, @code{atmega32}, @code{atmega32a}, @code{atmega32c1}, @code{atmega32hvb}, @code{atmega32hvbrevb}, @code{atmega32m1}, @code{atmega32u4}, @code{atmega32u6}, @code{atmega323}, @code{atmega324a}, @code{atmega324p}, @code{atmega324pa}, @code{atmega324pb}, @code{atmega325}, @code{atmega325a}, @code{atmega325p}, @code{atmega325pa}, @code{atmega328}, @code{atmega328p}, @code{atmega328pb}, @code{atmega329}, @code{atmega329a}, @code{atmega329p}, @code{atmega329pa}, @code{atmega3250}, @code{atmega3250a}, @code{atmega3250p}, @code{atmega3250pa}, @code{atmega3290}, @code{atmega3290a}, @code{atmega3290p}, @code{atmega3290pa}, @code{atmega406}, @code{atmega64}, @code{atmega64a}, @code{atmega64c1}, @code{atmega64hve}, @code{atmega64hve2}, @code{atmega64m1}, @code{atmega64rfr2}, @code{atmega640}, @code{atmega644}, @code{atmega644a}, @code{atmega644p}, @code{atmega644pa}, @code{atmega644rfr2}, @code{atmega645}, @code{atmega645a}, @code{atmega645p}, @code{atmega649}, @code{atmega649a}, @code{atmega649p}, @code{atmega6450}, @code{atmega6450a}, @code{atmega6450p}, @code{atmega6490}, @code{atmega6490a}, @code{atmega6490p}, @code{ata5795}, @code{ata5790}, @code{ata5790n}, @code{ata5791}, @code{ata6613c}, @code{ata6614q}, @code{ata5782}, @code{ata5831}, @code{ata8210}, @code{ata8510}, @code{ata5702m322}, @code{at90pwm161}, @code{at90pwm216}, @code{at90pwm316}, @code{at90can32}, @code{at90can64}, @code{at90scr100}, @code{at90usb646}, @code{at90usb647}, @code{at94k}, @code{m3000}. @item avr51 ``Enhanced'' devices with 128@tie{}KiB of program memory. diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index d4b3ff0..53f7204 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -2462,6 +2462,24 @@ features are supported by GCC. This macro is defined if @option{-fno-math-errno} is used, or enabled by another option such as @option{-ffast-math} or by default. +@item __RECIPROCAL_MATH__ +This macro is defined if @option{-freciprocal-math} is used, or enabled +by another option such as @option{-ffast-math} or by default. + +@item __NO_SIGNED_ZEROS__ +This macro is defined if @option{-fno-signed-zeros} is used, or enabled +by another option such as @option{-ffast-math} or by default. + +@item __NO_TRAPPING_MATH__ +This macro is defined if @option{-fno-trapping-math} is used. + +@item __ASSOCIATIVE_MATH__ +This macro is defined if @option{-fassociative-math} is used, or enabled +by another option such as @option{-ffast-math} or by default. + +@item __ROUNDING_MATH__ +This macro is defined if @option{-frounding-math} is used. + @item __GNUC_EXECUTION_CHARSET_NAME @itemx __GNUC_WIDE_EXECUTION_CHARSET_NAME These macros are defined to expand to a narrow string literal of diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 88e453c..a141507 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -325,6 +325,9 @@ Necessary in some circumstances, optional in others. See the host/target specific instructions for your platform for the exact requirements. +Note binutils 2.35 or newer is required for LTO to work correctly +with GNU libtool that includes doing a bootstrap with LTO enabled. + @item gzip version 1.2.4 (or later) or @itemx bzip2 version 1.0.2 (or later) diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index be81485..902402d 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -6415,7 +6415,7 @@ private variables at OpenACC device-lowering time using the @code{TARGET_GOACC_ADJUST_PRIVATE_DECL} target hook. @end deftypefn -@deftypefn {Target Hook} tree TARGET_GOACC_CREATE_WORKER_BROADCAST_RECORD (tree @var{rec}, bool @var{sender}, const char *@var{name}) +@deftypefn {Target Hook} tree TARGET_GOACC_CREATE_WORKER_BROADCAST_RECORD (tree @var{rec}, bool @var{sender}, const char *@var{name}, unsigned HOST_WIDE_INT @var{offset}) Create a record used to propagate local-variable state from an active worker to other workers. A possible implementation might adjust the type of REC to place the new variable in shared GPU memory. @@ -6424,6 +6424,13 @@ Presence of this target hook indicates that middle end neutering/broadcasting be used. @end deftypefn +@deftypefn {Target Hook} void TARGET_GOACC_SHARED_MEM_LAYOUT (unsigned HOST_WIDE_INT *@var{}, unsigned HOST_WIDE_INT *@var{}, @var{int[]}, unsigned @var{HOST_WIDE_INT[]}, unsigned @var{HOST_WIDE_INT[]}) +Lay out a fixed shared-memory region on the target. The LO and HI +arguments should be set to a range of addresses that can be used for worker +broadcasting. The dimensions, reduction size and gang-private size +arguments are for the current offload region. +@end deftypefn + @node Anchored Addresses @section Anchored Addresses @cindex anchored addresses diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index d088eee..86352dc 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -4228,6 +4228,8 @@ address; but often a machine-dependent strategy can generate better code. @hook TARGET_GOACC_CREATE_WORKER_BROADCAST_RECORD +@hook TARGET_GOACC_SHARED_MEM_LAYOUT + @node Anchored Addresses @section Anchored Addresses @cindex anchored addresses diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8e22dd2..08e7d4c 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,31 @@ +2021-09-20 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.h (gfc_omp_clauses): Add order_unconstrained. + * dump-parse-tree.c (show_omp_clauses): Dump it. + * openmp.c (gfc_match_omp_clauses): Match unconstrained/reproducible + modifiers to ordered(concurrent). + (OMP_DISTRIBUTE_CLAUSES): Accept ordered clause. + (resolve_omp_clauses): Reject ordered + order on same directive. + * trans-openmp.c (gfc_trans_omp_clauses, gfc_split_omp_clauses): Pass + on unconstrained modifier of ordered(concurrent). + +2021-09-17 Harald Anlauf <anlauf@gmx.de> + + PR fortran/102366 + * trans-decl.c (gfc_finish_var_decl): Disable the warning message + for variables moved from stack to static storange if they are + declared in the main, but allow the move to happen. + +2021-09-17 Sandra Loosemore <sandra@codesourcery.com> + + * intrinsic.texi (ISO_C_BINDING): Change C_FLOAT128 to correspond + to _Float128 rather than __float128. + * iso-c-binding.def (c_float128): Update comments. + * trans-intrinsic.c (gfc_builtin_decl_for_float_kind): Likewise. + (build_round_expr): Likewise. + (gfc_build_intrinsic_lib_fndcecls): Likewise. + * trans-types.h (gfc_real16_is_float128): Likewise. + 2021-09-16 Harald Anlauf <anlauf@gmx.de> PR fortran/102287 diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c index 83c4517..3ff8954 100644 --- a/gcc/fortran/cpp.c +++ b/gcc/fortran/cpp.c @@ -19,11 +19,15 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" #include "coretypes.h" + +#define GCC_C_COMMON_C +#include "options.h" /* For cpp_reason_option_codes. */ +#undef GCC_C_COMMON_C + #include "target.h" #include "gfortran.h" #include "diagnostic.h" - #include "toplev.h" #include "../../libcpp/internal.h" @@ -240,6 +244,18 @@ gfc_cpp_temporary_file (void) return gfc_cpp_option.temporary_filename; } +static void +gfc_cpp_register_include_paths (void) +{ + int cxx_stdinc = 0; + cpp_get_options (cpp_in)->warn_missing_include_dirs + = global_options.x_cpp_warn_missing_include_dirs; + register_include_chains (cpp_in, gfc_cpp_option.sysroot, + gfc_cpp_option.prefix, gfc_cpp_option.multilib, + gfc_cpp_option.standard_include_paths, cxx_stdinc, + gfc_cpp_option.verbose); +} + void gfc_cpp_init_options (unsigned int decoded_options_count, struct cl_decoded_option *decoded_options ATTRIBUTE_UNUSED) @@ -435,6 +451,37 @@ gfc_cpp_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED return result; } +/* This function needs to be called before gfc_cpp_register_include_paths + as the latter may diagnose missing include directories. */ +static void +gfc_cpp_init_cb (void) +{ + struct cpp_callbacks *cb; + + cb = cpp_get_callbacks (cpp_in); + cb->file_change = cb_file_change; + cb->line_change = cb_line_change; + cb->ident = cb_ident; + cb->def_pragma = cb_def_pragma; + cb->diagnostic = cb_cpp_diagnostic; + + if (gfc_cpp_option.dump_includes) + cb->include = cb_include; + + if ((gfc_cpp_option.dump_macros == 'D') + || (gfc_cpp_option.dump_macros == 'N')) + { + cb->define = cb_define; + cb->undef = cb_undef; + } + + if (gfc_cpp_option.dump_macros == 'U') + { + cb->before_define = dump_queued_macros; + cb->used_define = cb_used_define; + cb->used_undef = cb_used_undef; + } +} void gfc_cpp_post_options (void) @@ -498,6 +545,7 @@ gfc_cpp_post_options (void) way libcpp will do it, namely, with no charset conversion but with skipping of a UTF-8 BOM if present. */ diagnostic_initialize_input_context (global_dc, nullptr, true); + gfc_cpp_init_cb (); gfc_cpp_register_include_paths (); } @@ -506,32 +554,6 @@ gfc_cpp_post_options (void) void gfc_cpp_init_0 (void) { - struct cpp_callbacks *cb; - - cb = cpp_get_callbacks (cpp_in); - cb->file_change = cb_file_change; - cb->line_change = cb_line_change; - cb->ident = cb_ident; - cb->def_pragma = cb_def_pragma; - cb->diagnostic = cb_cpp_diagnostic; - - if (gfc_cpp_option.dump_includes) - cb->include = cb_include; - - if ((gfc_cpp_option.dump_macros == 'D') - || (gfc_cpp_option.dump_macros == 'N')) - { - cb->define = cb_define; - cb->undef = cb_undef; - } - - if (gfc_cpp_option.dump_macros == 'U') - { - cb->before_define = dump_queued_macros; - cb->used_define = cb_used_define; - cb->used_undef = cb_used_undef; - } - /* Initialize the print structure. Setting print.src_line to -1 here is a trick to guarantee that the first token of the file will cause a linemarker to be output by maybe_print_line. */ @@ -723,17 +745,6 @@ gfc_cpp_add_include_path_after (char *path, bool user_supplied) add_path (path, INC_AFTER, cxx_aware, user_supplied); } -void -gfc_cpp_register_include_paths (void) -{ - int cxx_stdinc = 0; - register_include_chains (cpp_in, gfc_cpp_option.sysroot, - gfc_cpp_option.prefix, gfc_cpp_option.multilib, - gfc_cpp_option.standard_include_paths, cxx_stdinc, - gfc_cpp_option.verbose); -} - - static void scan_translation_unit_trad (cpp_reader *); static void account_for_newlines (const unsigned char *, size_t); @@ -1043,6 +1054,21 @@ cb_used_define (cpp_reader *pfile, location_t line ATTRIBUTE_UNUSED, cpp_define_queue = q; } +/* Return the gcc option code associated with the reason for a cpp + message, or 0 if none. */ + +static int +cb_cpp_diagnostic_cpp_option (enum cpp_warning_reason reason) +{ + const struct cpp_reason_option_codes_t *entry; + + for (entry = cpp_reason_option_codes; entry->reason != CPP_W_NONE; entry++) + if (entry->reason == reason) + return entry->option_code; + return 0; +} + + /* Callback from cpp_error for PFILE to print diagnostics from the preprocessor. The diagnostic is of type LEVEL, with REASON set to the reason code if LEVEL is represents a warning, at location @@ -1089,8 +1115,8 @@ cb_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED, } diagnostic_set_info_translated (&diagnostic, msg, ap, richloc, dlevel); - if (reason == CPP_W_WARNING_DIRECTIVE) - diagnostic_override_option_index (&diagnostic, OPT_Wcpp); + diagnostic_override_option_index (&diagnostic, + cb_cpp_diagnostic_cpp_option (reason)); ret = diagnostic_report_diagnostic (global_dc, &diagnostic); if (level == CPP_DL_WARNING_SYSHDR) global_dc->dc_warn_system_headers = save_warn_system_headers; diff --git a/gcc/fortran/cpp.h b/gcc/fortran/cpp.h index f642c77..5cb7e5a 100644 --- a/gcc/fortran/cpp.h +++ b/gcc/fortran/cpp.h @@ -50,6 +50,4 @@ void gfc_cpp_done (void); void gfc_cpp_add_include_path (char *path, bool user_supplied); void gfc_cpp_add_include_path_after (char *path, bool user_supplied); -void gfc_cpp_register_include_paths (void); - #endif /* GFC_CPP_H */ diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index a1df47c..28eb09e 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1630,7 +1630,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) if (omp_clauses->independent) fputs (" INDEPENDENT", dumpfile); if (omp_clauses->order_concurrent) - fputs (" ORDER(CONCURRENT)", dumpfile); + { + fputs (" ORDER(", dumpfile); + if (omp_clauses->order_unconstrained) + fputs ("UNCONSTRAINED:", dumpfile); + fputs ("CONCURRENT)", dumpfile); + } if (omp_clauses->ordered) { if (omp_clauses->orderedc) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index fdf556e..3c7a843 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1491,7 +1491,8 @@ typedef struct gfc_omp_clauses unsigned inbranch:1, notinbranch:1, nogroup:1; unsigned sched_simd:1, sched_monotonic:1, sched_nonmonotonic:1; unsigned simd:1, threads:1, depend_source:1, destroy:1, order_concurrent:1; - unsigned capture:1, grainsize_strict:1, num_tasks_strict:1; + unsigned order_unconstrained:1, capture:1, grainsize_strict:1; + unsigned num_tasks_strict:1; ENUM_BITFIELD (gfc_omp_sched_kind) sched_kind:3; ENUM_BITFIELD (gfc_omp_device_type) device_type:2; ENUM_BITFIELD (gfc_omp_memorder) memorder:3; @@ -3028,9 +3029,10 @@ match gfc_get_pdt_instance (gfc_actual_arglist *, gfc_symbol **, void gfc_scanner_done_1 (void); void gfc_scanner_init_1 (void); -void gfc_add_include_path (const char *, bool, bool, bool); +void gfc_add_include_path (const char *, bool, bool, bool, bool); void gfc_add_intrinsic_modules_path (const char *); void gfc_release_include_path (void); +void gfc_check_include_dirs (void); FILE *gfc_open_included_file (const char *, bool, bool); int gfc_at_end (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index a64b7f5..9ee52d6 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -2369,9 +2369,23 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, break; case 'o': if ((mask & OMP_CLAUSE_ORDER) - && !c->order_concurrent - && gfc_match ("order ( concurrent )") == MATCH_YES) + && (m = gfc_match_dupl_check (!c->order_concurrent, "order (")) + != MATCH_NO) { + if (m == MATCH_ERROR) + goto error; + if (gfc_match (" reproducible : concurrent )") == MATCH_YES + || gfc_match (" concurrent )") == MATCH_YES) + ; + else if (gfc_match (" unconstrained : concurrent )") == MATCH_YES) + c->order_unconstrained = true; + else + { + gfc_error ("Expected ORDER(CONCURRENT) at %C " + "with optional %<reproducible%> or " + "%<unconstrained%> modifier"); + goto error; + } c->order_concurrent = true; continue; } @@ -3475,7 +3489,8 @@ cleanup: | OMP_CLAUSE_SHARED | OMP_CLAUSE_REDUCTION) #define OMP_DISTRIBUTE_CLAUSES \ (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE \ - | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_DIST_SCHEDULE) + | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_DIST_SCHEDULE \ + | OMP_CLAUSE_ORDER) #define OMP_SINGLE_CLAUSES \ (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE) #define OMP_ORDERED_CLAUSES \ @@ -5643,7 +5658,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, if (omp_clauses->orderedc && omp_clauses->orderedc < omp_clauses->collapse) gfc_error ("ORDERED clause parameter is less than COLLAPSE at %L", &code->loc); - + if (omp_clauses->order_concurrent && omp_clauses->ordered) + gfc_error ("ORDER clause must not be used together ORDERED at %L", + &code->loc); if (omp_clauses->if_expr) { gfc_expr *expr = omp_clauses->if_expr; diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c index 847e20e..d789397 100644 --- a/gcc/fortran/options.c +++ b/gcc/fortran/options.c @@ -159,14 +159,7 @@ gfc_init_options (unsigned int decoded_options_count, | GFC_FPE_UNDERFLOW; gfc_option.rtcheck = 0; - /* ??? Wmissing-include-dirs is disabled by default in C/C++ but - enabled by default in Fortran. Ideally, we should express this - in .opt, but that is not supported yet. */ - SET_OPTION_IF_UNSET (&global_options, &global_options_set, - cpp_warn_missing_include_dirs, 1); - set_dec_flags (0); - set_default_std_flags (); /* Initialize cpp-related options. */ @@ -260,6 +253,13 @@ gfc_post_options (const char **pfilename) char *source_path; int i; + /* This needs to be after the commandline has been processed. + In Fortran, the options is by default enabled, in C/C++ + by default disabled. */ + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + cpp_warn_missing_include_dirs, 1); + gfc_check_include_dirs (); + /* Finalize DEC flags. */ post_dec_flags (flag_dec); @@ -339,10 +339,10 @@ gfc_post_options (const char **pfilename) source_path = (char *) alloca (i + 1); memcpy (source_path, canon_source_file, i); source_path[i] = 0; - gfc_add_include_path (source_path, true, true, true); + gfc_add_include_path (source_path, true, true, true, false); } else - gfc_add_include_path (".", true, true, true); + gfc_add_include_path (".", true, true, true, false); if (canon_source_file != gfc_source_file) free (CONST_CAST (char *, canon_source_file)); @@ -511,7 +511,7 @@ gfc_handle_module_path_options (const char *arg) gfc_option.module_dir = XCNEWVEC (char, strlen (arg) + 2); strcpy (gfc_option.module_dir, arg); - gfc_add_include_path (gfc_option.module_dir, true, false, true); + gfc_add_include_path (gfc_option.module_dir, true, false, true, true); strcat (gfc_option.module_dir, "/"); } @@ -690,7 +690,7 @@ gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, with intrinsic modules. Do no warn because during testing without an installed compiler, we would get lots of bogus warnings for a missing include directory. */ - gfc_add_include_path (arg, false, false, false); + gfc_add_include_path (arg, false, false, false, true); gfc_add_intrinsic_modules_path (arg); break; @@ -737,7 +737,7 @@ gfc_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_I: - gfc_add_include_path (arg, true, false, true); + gfc_add_include_path (arg, true, false, true, true); break; case OPT_J: diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c index 39db099..6fe74bd 100644 --- a/gcc/fortran/scanner.c +++ b/gcc/fortran/scanner.c @@ -298,17 +298,69 @@ gfc_scanner_done_1 (void) } } +static bool +gfc_do_check_include_dir (const char *path, bool warn) +{ + struct stat st; + if (stat (path, &st)) + { + if (errno != ENOENT) + gfc_warning_now (0, "Include directory %qs: %s", + path, xstrerror(errno)); + else if (warn && !gfc_cpp_enabled ()) + gfc_warning_now (OPT_Wmissing_include_dirs, + "Nonexistent include directory %qs", path); + return false; + } + else if (!S_ISDIR (st.st_mode)) + { + gfc_fatal_error ("%qs is not a directory", path); + return false; + } + return true; +} + +/* In order that -W(no-)missing-include-dirs works, the diagnostic can only be + run after processing the commandline. */ +static void +gfc_do_check_include_dirs (gfc_directorylist **list) +{ + gfc_directorylist *prev, *q, *n; + prev = NULL; + n = *list; + while (n) + { + q = n; n = n->next; + if (gfc_do_check_include_dir (q->path, q->warn)) + { + prev = q; + continue; + } + if (prev == NULL) + *list = n; + else + prev->next = n; + free (q->path); + free (q); + } +} + +void +gfc_check_include_dirs () +{ + gfc_do_check_include_dirs (&include_dirs); + gfc_do_check_include_dirs (&intrinsic_modules_dirs); +} /* Adds path to the list pointed to by list. */ static void add_path_to_list (gfc_directorylist **list, const char *path, - bool use_for_modules, bool head, bool warn) + bool use_for_modules, bool head, bool warn, bool defer_warn) { gfc_directorylist *dir; const char *p; char *q; - struct stat st; size_t len; int i; @@ -326,21 +378,8 @@ add_path_to_list (gfc_directorylist **list, const char *path, while (i >=0 && IS_DIR_SEPARATOR (q[i])) q[i--] = '\0'; - if (stat (q, &st)) - { - if (errno != ENOENT) - gfc_warning_now (0, "Include directory %qs: %s", path, - xstrerror(errno)); - else if (warn) - gfc_warning_now (OPT_Wmissing_include_dirs, - "Nonexistent include directory %qs", path); - return; - } - else if (!S_ISDIR (st.st_mode)) - { - gfc_fatal_error ("%qs is not a directory", path); - return; - } + if (!defer_warn && !gfc_do_check_include_dir (q, warn)) + return; if (head || *list == NULL) { @@ -362,17 +401,20 @@ add_path_to_list (gfc_directorylist **list, const char *path, if (head) *list = dir; dir->use_for_modules = use_for_modules; + dir->warn = warn; dir->path = XCNEWVEC (char, strlen (p) + 2); strcpy (dir->path, p); strcat (dir->path, "/"); /* make '/' last character */ } +/* defer_warn is set to true while parsing the commandline. */ void gfc_add_include_path (const char *path, bool use_for_modules, bool file_dir, - bool warn) + bool warn, bool defer_warn) { - add_path_to_list (&include_dirs, path, use_for_modules, file_dir, warn); + add_path_to_list (&include_dirs, path, use_for_modules, file_dir, warn, + defer_warn); /* For '#include "..."' these directories are automatically searched. */ if (!file_dir) @@ -383,7 +425,7 @@ gfc_add_include_path (const char *path, bool use_for_modules, bool file_dir, void gfc_add_intrinsic_modules_path (const char *path) { - add_path_to_list (&intrinsic_modules_dirs, path, true, false, false); + add_path_to_list (&intrinsic_modules_dirs, path, true, false, false, false); } diff --git a/gcc/fortran/scanner.h b/gcc/fortran/scanner.h index 0bad63f..8782fe6 100644 --- a/gcc/fortran/scanner.h +++ b/gcc/fortran/scanner.h @@ -23,8 +23,8 @@ along with GCC; see the file COPYING3. If not see typedef struct gfc_directorylist { char *path; - bool use_for_modules; struct gfc_directorylist *next; + bool use_for_modules, warn; } gfc_directorylist; diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index bed61e2..3bd8a0f 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -743,7 +743,6 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym) /* Keep variables larger than max-stack-var-size off stack. */ if (!(sym->ns->proc_name && sym->ns->proc_name->attr.recursive) - && !(sym->ns->proc_name && sym->ns->proc_name->attr.is_main_program) && !sym->attr.automatic && sym->attr.save != SAVE_EXPLICIT && sym->attr.save != SAVE_IMPLICIT @@ -757,7 +756,9 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym) || sym->attr.allocatable) && !DECL_ARTIFICIAL (decl)) { - if (flag_max_stack_var_size > 0) + if (flag_max_stack_var_size > 0 + && !(sym->ns->proc_name + && sym->ns->proc_name->attr.is_main_program)) gfc_warning (OPT_Wsurprising, "Array %qs at %L is larger than limit set by " "%<-fmax-stack-var-size=%>, moved from stack to static " diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index e55e0c8..4ca2c3f 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -3803,6 +3803,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, if (clauses->order_concurrent) { c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_ORDER); + OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = clauses->order_unconstrained; omp_clauses = gfc_trans_add_clause (c, omp_clauses); } @@ -5892,6 +5893,8 @@ gfc_split_omp_clauses (gfc_code *code, = code->ext.omp_clauses->collapse; clausesa[GFC_OMP_SPLIT_DISTRIBUTE].order_concurrent = code->ext.omp_clauses->order_concurrent; + clausesa[GFC_OMP_SPLIT_DISTRIBUTE].order_unconstrained + = code->ext.omp_clauses->order_unconstrained; } if (mask & GFC_OMP_MASK_PARALLEL) { @@ -5946,6 +5949,8 @@ gfc_split_omp_clauses (gfc_code *code, = code->ext.omp_clauses->collapse; clausesa[GFC_OMP_SPLIT_DO].order_concurrent = code->ext.omp_clauses->order_concurrent; + clausesa[GFC_OMP_SPLIT_DO].order_unconstrained + = code->ext.omp_clauses->order_unconstrained; } if (mask & GFC_OMP_MASK_SIMD) { @@ -5962,6 +5967,8 @@ gfc_split_omp_clauses (gfc_code *code, = code->ext.omp_clauses->if_exprs[OMP_IF_SIMD]; clausesa[GFC_OMP_SPLIT_SIMD].order_concurrent = code->ext.omp_clauses->order_concurrent; + clausesa[GFC_OMP_SPLIT_SIMD].order_unconstrained + = code->ext.omp_clauses->order_unconstrained; /* And this is copied to all. */ clausesa[GFC_OMP_SPLIT_SIMD].if_expr = code->ext.omp_clauses->if_expr; @@ -367,6 +367,7 @@ static void putenv_from_prefixes (const struct path_prefix *, const char *, bool); static int access_check (const char *, int); static char *find_a_file (const struct path_prefix *, const char *, int, bool); +static char *find_a_program (const char *); static void add_prefix (struct path_prefix *, const char *, const char *, int, int, int); static void add_sysrooted_prefix (struct path_prefix *, const char *, @@ -3052,22 +3053,7 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode, { struct file_at_path_info info; -#ifdef DEFAULT_ASSEMBLER - if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0) - return xstrdup (DEFAULT_ASSEMBLER); -#endif - -#ifdef DEFAULT_LINKER - if (! strcmp (name, "ld") && access (DEFAULT_LINKER, mode) == 0) - return xstrdup (DEFAULT_LINKER); -#endif - -#ifdef DEFAULT_DSYMUTIL - if (! strcmp (name, "dsymutil") && access (DEFAULT_DSYMUTIL, mode) == 0) - return xstrdup (DEFAULT_DSYMUTIL); -#endif - - /* Determine the filename to execute (special case for absolute paths). */ + /* Find the filename in question (special case for absolute paths). */ if (IS_ABSOLUTE_PATH (name)) { @@ -3088,6 +3074,32 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode, file_at_path, &info); } +/* Specialization of find_a_file for programs that also takes into account + configure-specified default programs. */ + +static char* +find_a_program (const char *name) +{ + /* Do not search if default matches query. */ + +#ifdef DEFAULT_ASSEMBLER + if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, X_OK) == 0) + return xstrdup (DEFAULT_ASSEMBLER); +#endif + +#ifdef DEFAULT_LINKER + if (! strcmp (name, "ld") && access (DEFAULT_LINKER, X_OK) == 0) + return xstrdup (DEFAULT_LINKER); +#endif + +#ifdef DEFAULT_DSYMUTIL + if (! strcmp (name, "dsymutil") && access (DEFAULT_DSYMUTIL, X_OK) == 0) + return xstrdup (DEFAULT_DSYMUTIL); +#endif + + return find_a_file (&exec_prefixes, name, X_OK, false); +} + /* Ranking of prefixes in the sort list. -B prefixes are put before all others. */ @@ -3243,8 +3255,7 @@ execute (void) if (wrapper_string) { - string = find_a_file (&exec_prefixes, - argbuf[0], X_OK, false); + string = find_a_program (argbuf[0]); if (string) argbuf[0] = string; insert_wrapper (wrapper_string); @@ -3269,7 +3280,7 @@ execute (void) if (!wrapper_string) { - string = find_a_file (&exec_prefixes, commands[0].prog, X_OK, false); + string = find_a_program(commands[0].prog); if (string) commands[0].argv[0] = string; } @@ -3284,8 +3295,7 @@ execute (void) commands[n_commands].prog = argbuf[i + 1]; commands[n_commands].argv = &(argbuf.address ())[i + 1]; - string = find_a_file (&exec_prefixes, commands[n_commands].prog, - X_OK, false); + string = find_a_program(commands[n_commands].prog); if (string) commands[n_commands].argv[0] = string; n_commands++; @@ -8556,8 +8566,7 @@ driver::maybe_putenv_COLLECT_LTO_WRAPPER () const if (have_c) lto_wrapper_file = NULL; else - lto_wrapper_file = find_a_file (&exec_prefixes, "lto-wrapper", - X_OK, false); + lto_wrapper_file = find_a_program ("lto-wrapper"); if (lto_wrapper_file) { lto_wrapper_file = convert_white_space (lto_wrapper_file); @@ -8671,7 +8680,7 @@ driver::maybe_print_and_exit () const #endif print_prog_name = concat (print_prog_name, use_ld, NULL); } - char *newname = find_a_file (&exec_prefixes, print_prog_name, X_OK, 0); + char *newname = find_a_program (print_prog_name); printf ("%s\n", (newname ? newname : print_prog_name)); return (0); } @@ -9070,7 +9079,7 @@ driver::maybe_run_linker (const char *argv0) const /* We'll use ld if we can't find collect2. */ if (! strcmp (linker_name_spec, "collect2")) { - char *s = find_a_file (&exec_prefixes, "collect2", X_OK, false); + char *s = find_a_program ("collect2"); if (s == NULL) set_static_spec_shared (&linker_name_spec, "ld"); } diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc new file mode 100644 index 0000000..f0c8444 --- /dev/null +++ b/gcc/gimple-predicate-analysis.cc @@ -0,0 +1,2404 @@ +/* Support for simple predicate analysis. + + Copyright (C) 2001-2021 Free Software Foundation, Inc. + Contributed by Xinliang David Li <davidxl@google.com> + Generalized by Martin Sebor <msebor@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/>. */ + +#define INCLUDE_STRING +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "tree-pass.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "diagnostic-core.h" +#include "fold-const.h" +#include "gimple-iterator.h" +#include "tree-ssa.h" +#include "tree-cfg.h" +#include "cfghooks.h" +#include "attribs.h" +#include "builtins.h" +#include "calls.h" +#include "value-query.h" + +#include "gimple-predicate-analysis.h" + +#define DEBUG_PREDICATE_ANALYZER 1 + +/* Find the immediate postdominator of the specified basic block BB. */ + +static inline basic_block +find_pdom (basic_block bb) +{ + basic_block exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun); + if (bb == exit_bb) + return exit_bb; + + if (basic_block pdom = get_immediate_dominator (CDI_POST_DOMINATORS, bb)) + return pdom; + + return exit_bb; +} + +/* Find the immediate dominator of the specified basic block BB. */ + +static inline basic_block +find_dom (basic_block bb) +{ + basic_block entry_bb = ENTRY_BLOCK_PTR_FOR_FN (cfun); + if (bb == entry_bb) + return entry_bb; + + if (basic_block dom = get_immediate_dominator (CDI_DOMINATORS, bb)) + return dom; + + return entry_bb; +} + +/* Return true if BB1 is postdominating BB2 and BB1 is not a loop exit + bb. The loop exit bb check is simple and does not cover all cases. */ + +static bool +is_non_loop_exit_postdominating (basic_block bb1, basic_block bb2) +{ + if (!dominated_by_p (CDI_POST_DOMINATORS, bb2, bb1)) + return false; + + if (single_pred_p (bb1) && !single_succ_p (bb2)) + return false; + + return true; +} + +/* Find BB's closest postdominator that is its control equivalent (i.e., + that's controlled by the same predicate). */ + +static inline basic_block +find_control_equiv_block (basic_block bb) +{ + basic_block pdom = find_pdom (bb); + + /* Skip the postdominating bb that is also a loop exit. */ + if (!is_non_loop_exit_postdominating (pdom, bb)) + return NULL; + + /* If the postdominator is dominated by BB, return it. */ + if (dominated_by_p (CDI_DOMINATORS, pdom, bb)) + return pdom; + + return NULL; +} + +/* Return true if X1 is the negation of X2. */ + +static inline bool +pred_neg_p (const pred_info &x1, const pred_info &x2) +{ + if (!operand_equal_p (x1.pred_lhs, x2.pred_lhs, 0) + || !operand_equal_p (x1.pred_rhs, x2.pred_rhs, 0)) + return false; + + tree_code c1 = x1.cond_code, c2; + if (x1.invert == x2.invert) + c2 = invert_tree_comparison (x2.cond_code, false); + else + c2 = x2.cond_code; + + return c1 == c2; +} + +/* Return whether the condition (VAL CMPC BOUNDARY) is true. */ + +static bool +is_value_included_in (tree val, tree boundary, tree_code cmpc) +{ + /* Only handle integer constant here. */ + if (TREE_CODE (val) != INTEGER_CST || TREE_CODE (boundary) != INTEGER_CST) + return true; + + bool inverted = false; + if (cmpc == GE_EXPR || cmpc == GT_EXPR || cmpc == NE_EXPR) + { + cmpc = invert_tree_comparison (cmpc, false); + inverted = true; + } + + bool result; + if (cmpc == EQ_EXPR) + result = tree_int_cst_equal (val, boundary); + else if (cmpc == LT_EXPR) + result = tree_int_cst_lt (val, boundary); + else + { + gcc_assert (cmpc == LE_EXPR); + result = tree_int_cst_le (val, boundary); + } + + if (inverted) + result ^= 1; + + return result; +} + +/* Format the vector of edges EV as a string. */ + +static std::string +format_edge_vec (const vec<edge> &ev) +{ + std::string str; + + unsigned n = ev.length (); + for (unsigned i = 0; i < n; ++i) + { + char es[32]; + const_edge e = ev[i]; + sprintf (es, "%u", e->src->index); + str += es; + if (i + 1 < n) + str += " -> "; + } + return str; +} + +/* Format the first N elements of the array of vector of edges EVA as + a string. */ + +static std::string +format_edge_vecs (const vec<edge> eva[], unsigned n) +{ + std::string str; + + for (unsigned i = 0; i != n; ++i) + { + str += '{'; + str += format_edge_vec (eva[i]); + str += '}'; + if (i + 1 < n) + str += ", "; + } + return str; +} + +/* Dump a single pred_info to DUMP_FILE. */ + +static void +dump_pred_info (const pred_info &pred) +{ + if (pred.invert) + fprintf (dump_file, "NOT ("); + print_generic_expr (dump_file, pred.pred_lhs); + fprintf (dump_file, " %s ", op_symbol_code (pred.cond_code)); + print_generic_expr (dump_file, pred.pred_rhs); + if (pred.invert) + fputc (')', dump_file); +} + +/* Dump a pred_chain to DUMP_FILE. */ + +static void +dump_pred_chain (const pred_chain &chain) +{ + unsigned np = chain.length (); + if (np > 1) + fprintf (dump_file, "AND ("); + + for (unsigned j = 0; j < np; j++) + { + dump_pred_info (chain[j]); + if (j < np - 1) + fprintf (dump_file, ", "); + else if (j > 0) + fputc (')', dump_file); + } +} + +/* Dump the predicate chain PREDS for STMT, prefixed by MSG. */ + +static void +dump_predicates (gimple *stmt, const pred_chain_union &preds, const char *msg) +{ + fprintf (dump_file, "%s", msg); + if (stmt) + { + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, "is guarded by:\n"); + } + + unsigned np = preds.length (); + if (np > 1) + fprintf (dump_file, "OR ("); + for (unsigned i = 0; i < np; i++) + { + dump_pred_chain (preds[i]); + if (i < np - 1) + fprintf (dump_file, ", "); + else if (i > 0) + fputc (')', dump_file); + } + fputc ('\n', dump_file); +} + +/* Dump the first NCHAINS elements of the DEP_CHAINS array into DUMP_FILE. */ + +static void +dump_dep_chains (const auto_vec<edge> dep_chains[], unsigned nchains) +{ + if (!dump_file) + return; + + for (unsigned i = 0; i != nchains; ++i) + { + const auto_vec<edge> &v = dep_chains[i]; + unsigned n = v.length (); + for (unsigned j = 0; j != n; ++j) + { + fprintf (dump_file, "%u", v[j]->src->index); + if (j + 1 < n) + fprintf (dump_file, " -> "); + } + fputc ('\n', dump_file); + } +} + +/* Return the 'normalized' conditional code with operand swapping + and condition inversion controlled by SWAP_COND and INVERT. */ + +static tree_code +get_cmp_code (tree_code orig_cmp_code, bool swap_cond, bool invert) +{ + tree_code tc = orig_cmp_code; + + if (swap_cond) + tc = swap_tree_comparison (orig_cmp_code); + if (invert) + tc = invert_tree_comparison (tc, false); + + switch (tc) + { + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + break; + default: + return ERROR_MARK; + } + return tc; +} + +/* Return true if PRED is common among all predicate chains in PREDS + (and therefore can be factored out). */ + +static bool +find_matching_predicate_in_rest_chains (const pred_info &pred, + const pred_chain_union &preds) +{ + /* Trival case. */ + if (preds.length () == 1) + return true; + + for (unsigned i = 1; i < preds.length (); i++) + { + bool found = false; + const pred_chain &chain = preds[i]; + unsigned n = chain.length (); + for (unsigned j = 0; j < n; j++) + { + const pred_info &pred2 = chain[j]; + /* Can relax the condition comparison to not use address + comparison. However, the most common case is that + multiple control dependent paths share a common path + prefix, so address comparison should be ok. */ + if (operand_equal_p (pred2.pred_lhs, pred.pred_lhs, 0) + && operand_equal_p (pred2.pred_rhs, pred.pred_rhs, 0) + && pred2.invert == pred.invert) + { + found = true; + break; + } + } + if (!found) + return false; + } + return true; +} + +/* Find a predicate to examine against paths of interest. If there + is no predicate of the "FLAG_VAR CMP CONST" form, try to find one + of that's the form "FLAG_VAR CMP FLAG_VAR" with value range info. + PHI is the phi node whose incoming (interesting) paths need to be + examined. On success, return the comparison code, set defintion + gimple of FLAG_DEF and BOUNDARY_CST. Otherwise return ERROR_MARK. */ + +static tree_code +find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def, + tree *boundary_cst) +{ + tree_code vrinfo_code = ERROR_MARK; + gimple *vrinfo_def = NULL; + tree vrinfo_cst = NULL; + + gcc_assert (preds.length () > 0); + pred_chain chain = preds[0]; + for (unsigned i = 0; i < chain.length (); i++) + { + bool use_vrinfo_p = false; + const pred_info &pred = chain[i]; + tree cond_lhs = pred.pred_lhs; + tree cond_rhs = pred.pred_rhs; + if (cond_lhs == NULL_TREE || cond_rhs == NULL_TREE) + continue; + + tree_code code = get_cmp_code (pred.cond_code, false, pred.invert); + if (code == ERROR_MARK) + continue; + + /* Convert to the canonical form SSA_NAME CMP CONSTANT. */ + if (TREE_CODE (cond_lhs) == SSA_NAME + && is_gimple_constant (cond_rhs)) + ; + else if (TREE_CODE (cond_rhs) == SSA_NAME + && is_gimple_constant (cond_lhs)) + { + std::swap (cond_lhs, cond_rhs); + if ((code = get_cmp_code (code, true, false)) == ERROR_MARK) + continue; + } + /* Check if we can take advantage of FLAG_VAR COMP FLAG_VAR predicate + with value range info. Note only first of such case is handled. */ + else if (vrinfo_code == ERROR_MARK + && TREE_CODE (cond_lhs) == SSA_NAME + && TREE_CODE (cond_rhs) == SSA_NAME) + { + gimple* lhs_def = SSA_NAME_DEF_STMT (cond_lhs); + if (!lhs_def || gimple_code (lhs_def) != GIMPLE_PHI + || gimple_bb (lhs_def) != gimple_bb (phi)) + { + std::swap (cond_lhs, cond_rhs); + if ((code = get_cmp_code (code, true, false)) == ERROR_MARK) + continue; + } + + /* Check value range info of rhs, do following transforms: + flag_var < [min, max] -> flag_var < max + flag_var > [min, max] -> flag_var > min + + We can also transform LE_EXPR/GE_EXPR to LT_EXPR/GT_EXPR: + flag_var <= [min, max] -> flag_var < [min, max+1] + flag_var >= [min, max] -> flag_var > [min-1, max] + if no overflow/wrap. */ + tree type = TREE_TYPE (cond_lhs); + value_range r; + if (!INTEGRAL_TYPE_P (type) + || !get_range_query (cfun)->range_of_expr (r, cond_rhs) + || r.kind () != VR_RANGE) + continue; + + wide_int min = r.lower_bound (); + wide_int max = r.upper_bound (); + if (code == LE_EXPR + && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type))) + { + code = LT_EXPR; + max = max + 1; + } + if (code == GE_EXPR + && min != wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type))) + { + code = GT_EXPR; + min = min - 1; + } + if (code == LT_EXPR) + cond_rhs = wide_int_to_tree (type, max); + else if (code == GT_EXPR) + cond_rhs = wide_int_to_tree (type, min); + else + continue; + + use_vrinfo_p = true; + } + else + continue; + + if ((*flag_def = SSA_NAME_DEF_STMT (cond_lhs)) == NULL) + continue; + + if (gimple_code (*flag_def) != GIMPLE_PHI + || gimple_bb (*flag_def) != gimple_bb (phi) + || !find_matching_predicate_in_rest_chains (pred, preds)) + continue; + + /* Return if any "flag_var comp const" predicate is found. */ + if (!use_vrinfo_p) + { + *boundary_cst = cond_rhs; + return code; + } + /* Record if any "flag_var comp flag_var[vinfo]" predicate is found. */ + else if (vrinfo_code == ERROR_MARK) + { + vrinfo_code = code; + vrinfo_def = *flag_def; + vrinfo_cst = cond_rhs; + } + } + /* Return the "flag_var cmp flag_var[vinfo]" predicate we found. */ + if (vrinfo_code != ERROR_MARK) + { + *flag_def = vrinfo_def; + *boundary_cst = vrinfo_cst; + } + return vrinfo_code; +} + +/* Return true if all interesting opnds are pruned, false otherwise. + PHI is the phi node with interesting operands, OPNDS is the bitmap + of the interesting operand positions, FLAG_DEF is the statement + defining the flag guarding the use of the PHI output, BOUNDARY_CST + is the const value used in the predicate associated with the flag, + CMP_CODE is the comparison code used in the predicate, VISITED_PHIS + is the pointer set of phis visited, and VISITED_FLAG_PHIS is + the pointer to the pointer set of flag definitions that are also + phis. + + Example scenario: + + BB1: + flag_1 = phi <0, 1> // (1) + var_1 = phi <undef, some_val> + + + BB2: + flag_2 = phi <0, flag_1, flag_1> // (2) + var_2 = phi <undef, var_1, var_1> + if (flag_2 == 1) + goto BB3; + + BB3: + use of var_2 // (3) + + Because some flag arg in (1) is not constant, if we do not look into + the flag phis recursively, it is conservatively treated as unknown and + var_1 is thought to flow into use at (3). Since var_1 is potentially + uninitialized a false warning will be emitted. + Checking recursively into (1), the compiler can find out that only + some_val (which is defined) can flow into (3) which is OK. */ + +static bool +prune_phi_opnds (gphi *phi, unsigned opnds, gphi *flag_def, + tree boundary_cst, tree_code cmp_code, + predicate::func_t &eval, + hash_set<gphi *> *visited_phis, + bitmap *visited_flag_phis) +{ + /* The Boolean predicate guarding the PHI definition. Initialized + lazily from PHI in the first call to is_use_guarded() and cached + for subsequent iterations. */ + predicate def_preds (eval); + + unsigned n = MIN (eval.max_phi_args, gimple_phi_num_args (flag_def)); + for (unsigned i = 0; i < n; i++) + { + if (!MASK_TEST_BIT (opnds, i)) + continue; + + tree flag_arg = gimple_phi_arg_def (flag_def, i); + if (!is_gimple_constant (flag_arg)) + { + if (TREE_CODE (flag_arg) != SSA_NAME) + return false; + + gphi *flag_arg_def = dyn_cast<gphi *> (SSA_NAME_DEF_STMT (flag_arg)); + if (!flag_arg_def) + return false; + + tree phi_arg = gimple_phi_arg_def (phi, i); + if (TREE_CODE (phi_arg) != SSA_NAME) + return false; + + gphi *phi_arg_def = dyn_cast<gphi *> (SSA_NAME_DEF_STMT (phi_arg)); + if (!phi_arg_def) + return false; + + if (gimple_bb (phi_arg_def) != gimple_bb (flag_arg_def)) + return false; + + if (!*visited_flag_phis) + *visited_flag_phis = BITMAP_ALLOC (NULL); + + tree phi_result = gimple_phi_result (flag_arg_def); + if (bitmap_bit_p (*visited_flag_phis, SSA_NAME_VERSION (phi_result))) + return false; + + bitmap_set_bit (*visited_flag_phis, SSA_NAME_VERSION (phi_result)); + + /* Now recursively try to prune the interesting phi args. */ + unsigned opnds_arg_phi = eval.phi_arg_set (phi_arg_def); + if (!prune_phi_opnds (phi_arg_def, opnds_arg_phi, flag_arg_def, + boundary_cst, cmp_code, eval, visited_phis, + visited_flag_phis)) + return false; + + bitmap_clear_bit (*visited_flag_phis, SSA_NAME_VERSION (phi_result)); + continue; + } + + /* Now check if the constant is in the guarded range. */ + if (is_value_included_in (flag_arg, boundary_cst, cmp_code)) + { + /* Now that we know that this undefined edge is not pruned. + If the operand is defined by another phi, we can further + prune the incoming edges of that phi by checking + the predicates of this operands. */ + + tree opnd = gimple_phi_arg_def (phi, i); + gimple *opnd_def = SSA_NAME_DEF_STMT (opnd); + if (gphi *opnd_def_phi = dyn_cast <gphi *> (opnd_def)) + { + unsigned opnds2 = eval.phi_arg_set (opnd_def_phi); + if (!MASK_EMPTY (opnds2)) + { + edge opnd_edge = gimple_phi_arg_edge (phi, i); + if (def_preds.is_use_guarded (phi, opnd_edge->src, + opnd_def_phi, opnds2, + visited_phis)) + return false; + } + } + else + return false; + } + } + + return true; +} + +/* Recursively compute the set PHI's incoming edges with "uninteresting" + operands of a phi chain, i.e., those for which EVAL returns false. + CD_ROOT is the control dependence root from which edges are collected + up the CFG nodes that it's dominated by. *EDGES holds the result, and + VISITED is used for detecting cycles. */ + +static void +collect_phi_def_edges (gphi *phi, basic_block cd_root, auto_vec<edge> *edges, + predicate::func_t &eval, hash_set<gimple *> *visited) +{ + if (visited->elements () == 0 + && DEBUG_PREDICATE_ANALYZER + && dump_file) + { + fprintf (dump_file, "%s for cd_root %u and ", + __func__, cd_root->index); + print_gimple_stmt (dump_file, phi, 0); + + } + + if (visited->add (phi)) + return; + + unsigned n = gimple_phi_num_args (phi); + for (unsigned i = 0; i < n; i++) + { + edge opnd_edge = gimple_phi_arg_edge (phi, i); + tree opnd = gimple_phi_arg_def (phi, i); + + if (TREE_CODE (opnd) == SSA_NAME) + { + gimple *def = SSA_NAME_DEF_STMT (opnd); + + if (gimple_code (def) == GIMPLE_PHI + && dominated_by_p (CDI_DOMINATORS, gimple_bb (def), cd_root)) + collect_phi_def_edges (as_a<gphi *> (def), cd_root, edges, eval, + visited); + else if (!eval (opnd)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "\tFound def edge %i -> %i for cd_root %i " + "and operand %u of: ", + opnd_edge->src->index, opnd_edge->dest->index, + cd_root->index, i); + print_gimple_stmt (dump_file, phi, 0); + } + edges->safe_push (opnd_edge); + } + } + else + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "\tFound def edge %i -> %i for cd_root %i " + "and operand %u of: ", + opnd_edge->src->index, opnd_edge->dest->index, + cd_root->index, i); + print_gimple_stmt (dump_file, phi, 0); + } + + if (!eval (opnd)) + edges->safe_push (opnd_edge); + } + } +} + +/* Return an expression corresponding to the predicate PRED. */ + +static tree +build_pred_expr (const pred_info &pred) +{ + tree_code cond_code = pred.cond_code; + tree lhs = pred.pred_lhs; + tree rhs = pred.pred_rhs; + + if (pred.invert) + cond_code = invert_tree_comparison (cond_code, false); + + return build2 (cond_code, TREE_TYPE (lhs), lhs, rhs); +} + +/* Return an expression corresponding to PREDS. */ + +static tree +build_pred_expr (const pred_chain_union &preds, bool invert = false) +{ + tree_code code = invert ? TRUTH_AND_EXPR : TRUTH_OR_EXPR; + tree_code subcode = invert ? TRUTH_OR_EXPR : TRUTH_AND_EXPR; + + tree expr = NULL_TREE; + for (unsigned i = 0; i != preds.length (); ++i) + { + tree subexpr = NULL_TREE; + for (unsigned j = 0; j != preds[i].length (); ++j) + { + const pred_info &pi = preds[i][j]; + tree cond = build_pred_expr (pi); + if (invert) + cond = invert_truthvalue (cond); + subexpr = subexpr ? build2 (subcode, boolean_type_node, + subexpr, cond) : cond; + } + if (expr) + expr = build2 (code, boolean_type_node, expr, subexpr); + else + expr = subexpr; + } + + return expr; +} + +/* Return a bitset of all PHI arguments or zero if there are too many. */ + +unsigned +predicate::func_t::phi_arg_set (gphi *phi) +{ + unsigned n = gimple_phi_num_args (phi); + + if (max_phi_args < n) + return 0; + + /* Set the least significant N bits. */ + return (1U << n) - 1; +} + +/* Determine if the predicate set of the use does not overlap with that + of the interesting paths. The most common senario of guarded use is + in Example 1: + Example 1: + if (some_cond) + { + x = ...; // set x to valid + flag = true; + } + + ... some code ... + + if (flag) + use (x); // use when x is valid + + The real world examples are usually more complicated, but similar + and usually result from inlining: + + bool init_func (int * x) + { + if (some_cond) + return false; + *x = ...; // set *x to valid + return true; + } + + void foo (..) + { + int x; + + if (!init_func (&x)) + return; + + .. some_code ... + use (x); // use when x is valid + } + + Another possible use scenario is in the following trivial example: + + Example 2: + if (n > 0) + x = 1; + ... + if (n > 0) + { + if (m < 2) + ... = x; + } + + Predicate analysis needs to compute the composite predicate: + + 1) 'x' use predicate: (n > 0) .AND. (m < 2) + 2) 'x' default value (non-def) predicate: .NOT. (n > 0) + (the predicate chain for phi operand defs can be computed + starting from a bb that is control equivalent to the phi's + bb and is dominating the operand def.) + + and check overlapping: + (n > 0) .AND. (m < 2) .AND. (.NOT. (n > 0)) + <==> false + + This implementation provides a framework that can handle different + scenarios. (Note that many simple cases are handled properly without + the predicate analysis if jump threading eliminates the merge point + thus makes path-sensitive analysis unnecessary.) + + PHI is the phi node whose incoming (undefined) paths need to be + pruned, and OPNDS is the bitmap holding interesting operand + positions. VISITED is the pointer set of phi stmts being + checked. */ + +bool +predicate::overlap (gphi *phi, unsigned opnds, hash_set<gphi *> *visited) +{ + gimple *flag_def = NULL; + tree boundary_cst = NULL_TREE; + bitmap visited_flag_phis = NULL; + + /* Find within the common prefix of multiple predicate chains + a predicate that is a comparison of a flag variable against + a constant. */ + tree_code cmp_code = find_var_cmp_const (m_preds, phi, &flag_def, + &boundary_cst); + if (cmp_code == ERROR_MARK) + return true; + + /* Now check all the uninit incoming edges have a constant flag + value that is in conflict with the use guard/predicate. */ + gphi *phi_def = as_a<gphi *> (flag_def); + bool all_pruned = prune_phi_opnds (phi, opnds, phi_def, boundary_cst, + cmp_code, m_eval, visited, + &visited_flag_phis); + + if (visited_flag_phis) + BITMAP_FREE (visited_flag_phis); + + return !all_pruned; +} + +/* Return true if two predicates PRED1 and X2 are equivalent. Assume + the expressions have already properly re-associated. */ + +static inline bool +pred_equal_p (const pred_info &pred1, const pred_info &pred2) +{ + if (!operand_equal_p (pred1.pred_lhs, pred2.pred_lhs, 0) + || !operand_equal_p (pred1.pred_rhs, pred2.pred_rhs, 0)) + return false; + + tree_code c1 = pred1.cond_code, c2; + if (pred1.invert != pred2.invert + && TREE_CODE_CLASS (pred2.cond_code) == tcc_comparison) + c2 = invert_tree_comparison (pred2.cond_code, false); + else + c2 = pred2.cond_code; + + return c1 == c2; +} + +/* Return true if PRED tests inequality (i.e., X != Y). */ + +static inline bool +is_neq_relop_p (const pred_info &pred) +{ + + return ((pred.cond_code == NE_EXPR && !pred.invert) + || (pred.cond_code == EQ_EXPR && pred.invert)); +} + +/* Returns true if PRED is of the form X != 0. */ + +static inline bool +is_neq_zero_form_p (const pred_info &pred) +{ + if (!is_neq_relop_p (pred) || !integer_zerop (pred.pred_rhs) + || TREE_CODE (pred.pred_lhs) != SSA_NAME) + return false; + return true; +} + +/* Return true if PRED is equivalent to X != 0. */ + +static inline bool +pred_expr_equal_p (const pred_info &pred, tree expr) +{ + if (!is_neq_zero_form_p (pred)) + return false; + + return operand_equal_p (pred.pred_lhs, expr, 0); +} + +/* Return true if VAL satisfies (x CMPC BOUNDARY) predicate. CMPC can + be either one of the range comparison codes ({GE,LT,EQ,NE}_EXPR and + the like), or BIT_AND_EXPR. EXACT_P is only meaningful for the latter. + Modify the question from VAL & BOUNDARY != 0 to VAL & BOUNDARY == VAL. + For other values of CMPC, EXACT_P is ignored. */ + +static bool +value_sat_pred_p (tree val, tree boundary, tree_code cmpc, + bool exact_p = false) +{ + if (cmpc != BIT_AND_EXPR) + return is_value_included_in (val, boundary, cmpc); + + wide_int andw = wi::to_wide (val) & wi::to_wide (boundary); + if (exact_p) + return andw == wi::to_wide (val); + + return andw.to_uhwi (); +} + +/* Return true if the domain of single predicate expression PRED1 + is a subset of that of PRED2, and false if it cannot be proved. */ + +static bool +subset_of (const pred_info &pred1, const pred_info &pred2) +{ + if (pred_equal_p (pred1, pred2)) + return true; + + if ((TREE_CODE (pred1.pred_rhs) != INTEGER_CST) + || (TREE_CODE (pred2.pred_rhs) != INTEGER_CST)) + return false; + + if (!operand_equal_p (pred1.pred_lhs, pred2.pred_lhs, 0)) + return false; + + tree_code code1 = pred1.cond_code; + if (pred1.invert) + code1 = invert_tree_comparison (code1, false); + tree_code code2 = pred2.cond_code; + if (pred2.invert) + code2 = invert_tree_comparison (code2, false); + + if (code2 == NE_EXPR && code1 == NE_EXPR) + return false; + + if (code2 == NE_EXPR) + return !value_sat_pred_p (pred2.pred_rhs, pred1.pred_rhs, code1); + + if (code1 == EQ_EXPR) + return value_sat_pred_p (pred1.pred_rhs, pred2.pred_rhs, code2); + + if (code1 == code2) + return value_sat_pred_p (pred1.pred_rhs, pred2.pred_rhs, code2, + code1 == BIT_AND_EXPR); + + return false; +} + +/* Return true if the domain of CHAIN1 is a subset of that of CHAIN2. + Return false if it cannot be proven so. */ + +static bool +subset_of (const pred_chain &chain1, const pred_chain &chain2) +{ + unsigned np1 = chain1.length (); + unsigned np2 = chain2.length (); + for (unsigned i2 = 0; i2 < np2; i2++) + { + bool found = false; + const pred_info &info2 = chain2[i2]; + for (unsigned i1 = 0; i1 < np1; i1++) + { + const pred_info &info1 = chain1[i1]; + if (subset_of (info1, info2)) + { + found = true; + break; + } + } + if (!found) + return false; + } + return true; +} + +/* Return true if the domain defined by the predicate chain PREDS is + a subset of the domain of *THIS. Return false if PREDS's domain + is not a subset of any of the sub-domains of *THIS (corresponding + to each individual chains in it), even though it may be still be + a subset of whole domain of *THIS which is the union (ORed) of all + its subdomains. In other words, the result is conservative. */ + +bool +predicate::includes (const pred_chain &chain) const +{ + for (unsigned i = 0; i < m_preds.length (); i++) + if (subset_of (chain, m_preds[i])) + return true; + + return false; +} + +/* Return true if the domain defined by *THIS is a superset of PREDS's + domain. + Avoid building generic trees (and rely on the folding capability + of the compiler), and instead perform brute force comparison of + individual predicate chains (this won't be a computationally costly + since the chains are pretty short). Returning false does not + necessarily mean *THIS is not a superset of *PREDS, only that + it need not be since the analysis cannot prove it. */ + +bool +predicate::superset_of (const predicate &preds) const +{ + for (unsigned i = 0; i < preds.m_preds.length (); i++) + if (!includes (preds.m_preds[i])) + return false; + + return true; +} + +/* Create a predicate of the form OP != 0 and push it the work list CHAIN. */ + +static void +push_to_worklist (tree op, pred_chain *chain, hash_set<tree> *mark_set) +{ + if (mark_set->contains (op)) + return; + mark_set->add (op); + + pred_info arg_pred; + arg_pred.pred_lhs = op; + arg_pred.pred_rhs = integer_zero_node; + arg_pred.cond_code = NE_EXPR; + arg_pred.invert = false; + chain->safe_push (arg_pred); +} + +/* Return a pred_info for a gimple assignment CMP_ASSIGN with comparison + rhs. */ + +static pred_info +get_pred_info_from_cmp (const gimple *cmp_assign) +{ + pred_info pred; + pred.pred_lhs = gimple_assign_rhs1 (cmp_assign); + pred.pred_rhs = gimple_assign_rhs2 (cmp_assign); + pred.cond_code = gimple_assign_rhs_code (cmp_assign); + pred.invert = false; + return pred; +} + +/* If PHI is a degenerate phi with all operands having the same value (relop) + update *PRED to that value and return true. Otherwise return false. */ + +static bool +is_degenerate_phi (gimple *phi, pred_info *pred) +{ + tree op0 = gimple_phi_arg_def (phi, 0); + + if (TREE_CODE (op0) != SSA_NAME) + return false; + + gimple *def0 = SSA_NAME_DEF_STMT (op0); + if (gimple_code (def0) != GIMPLE_ASSIGN) + return false; + + if (TREE_CODE_CLASS (gimple_assign_rhs_code (def0)) != tcc_comparison) + return false; + + pred_info pred0 = get_pred_info_from_cmp (def0); + + unsigned n = gimple_phi_num_args (phi); + for (unsigned i = 1; i < n; ++i) + { + tree op = gimple_phi_arg_def (phi, i); + if (TREE_CODE (op) != SSA_NAME) + return false; + + gimple *def = SSA_NAME_DEF_STMT (op); + if (gimple_code (def) != GIMPLE_ASSIGN) + return false; + + if (TREE_CODE_CLASS (gimple_assign_rhs_code (def)) != tcc_comparison) + return false; + + pred_info pred = get_pred_info_from_cmp (def); + if (!pred_equal_p (pred, pred0)) + return false; + } + + *pred = pred0; + return true; +} + +/* Recursively compute the control dependence chains (paths of edges) + from the dependent basic block, DEP_BB, up to the dominating basic + block, DOM_BB (the head node of a chain should be dominated by it), + storing them in the CD_CHAINS array. + CUR_CD_CHAIN is the current chain being computed. + *NUM_CHAINS is total number of chains in the CD_CHAINS array. + *NUM_CALLS is the number of recursive calls to control unbounded + recursion. + Return true if the information is successfully computed, false if + there is no control dependence or not computed. */ + +static bool +compute_control_dep_chain (basic_block dom_bb, const_basic_block dep_bb, + vec<edge> cd_chains[], unsigned *num_chains, + vec<edge> &cur_cd_chain, unsigned *num_calls, + unsigned depth = 0) +{ + if (*num_calls > (unsigned)param_uninit_control_dep_attempts) + { + if (dump_file) + fprintf (dump_file, "param_uninit_control_dep_attempts exceeded: %u\n", + *num_calls); + return false; + } + ++*num_calls; + + /* FIXME: Use a set instead. */ + unsigned cur_chain_len = cur_cd_chain.length (); + if (cur_chain_len > MAX_CHAIN_LEN) + { + if (dump_file) + fprintf (dump_file, "MAX_CHAIN_LEN exceeded: %u\n", cur_chain_len); + + return false; + } + + if (cur_chain_len > 5) + { + if (dump_file) + fprintf (dump_file, "chain length exceeds 5: %u\n", cur_chain_len); + } + + for (unsigned i = 0; i < cur_chain_len; i++) + { + edge e = cur_cd_chain[i]; + /* Cycle detected. */ + if (e->src == dom_bb) + { + if (dump_file) + fprintf (dump_file, "cycle detected\n"); + return false; + } + } + + if (DEBUG_PREDICATE_ANALYZER && dump_file) + fprintf (dump_file, + "%*s%s (dom_bb = %u, dep_bb = %u, cd_chains = { %s }, ...)\n", + depth, "", __func__, dom_bb->index, dep_bb->index, + format_edge_vecs (cd_chains, *num_chains).c_str ()); + + bool found_cd_chain = false; + + /* Iterate over DOM_BB's successors. */ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, dom_bb->succs) + { + int post_dom_check = 0; + if (e->flags & (EDGE_FAKE | EDGE_ABNORMAL)) + continue; + + basic_block cd_bb = e->dest; + cur_cd_chain.safe_push (e); + while (!is_non_loop_exit_postdominating (cd_bb, dom_bb)) + { + if (cd_bb == dep_bb) + { + /* Found a direct control dependence. */ + if (*num_chains < MAX_NUM_CHAINS) + { + cd_chains[*num_chains] = cur_cd_chain.copy (); + (*num_chains)++; + } + found_cd_chain = true; + /* Check path from next edge. */ + break; + } + + /* Check if DEP_BB is indirectly control-dependent on DOM_BB. */ + if (compute_control_dep_chain (cd_bb, dep_bb, cd_chains, + num_chains, cur_cd_chain, + num_calls, depth + 1)) + { + found_cd_chain = true; + break; + } + + cd_bb = find_pdom (cd_bb); + post_dom_check++; + if (cd_bb == EXIT_BLOCK_PTR_FOR_FN (cfun) + || post_dom_check > MAX_POSTDOM_CHECK) + break; + } + cur_cd_chain.pop (); + gcc_assert (cur_cd_chain.length () == cur_chain_len); + } + + gcc_assert (cur_cd_chain.length () == cur_chain_len); + return found_cd_chain; +} + +/* Return true if PRED can be invalidated by any predicate in GUARD. */ + +static bool +can_be_invalidated_p (const pred_info &pred, const pred_chain &guard) +{ + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "Testing if predicate: "); + dump_pred_info (pred); + fprintf (dump_file, "\n...can be invalidated by a USE guard of: "); + dump_pred_chain (guard); + fputc ('\n', dump_file); + } + + unsigned n = guard.length (); + for (unsigned i = 0; i < n; ++i) + { + if (pred_neg_p (pred, guard[i])) + { + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, " Predicate invalidated by: "); + dump_pred_info (guard[i]); + fputc ('\n', dump_file); + } + return true; + } + } + + return false; +} + +/* Return true if all predicates in PREDS are invalidated by GUARD being + true. */ + +static bool +can_be_invalidated_p (const pred_chain_union &preds, const pred_chain &guard) +{ + if (preds.is_empty ()) + return false; + + if (dump_file && dump_flags & TDF_DETAILS) + dump_predicates (NULL, preds, + "Testing if anything here can be invalidated: "); + + for (unsigned i = 0; i < preds.length (); ++i) + { + const pred_chain &chain = preds[i]; + for (unsigned j = 0; j < chain.length (); ++j) + if (can_be_invalidated_p (chain[j], guard)) + return true; + + /* If we were unable to invalidate any predicate in C, then there + is a viable path from entry to the PHI where the PHI takes + an interesting value and continues to a use of the PHI. */ + return false; + } + return true; +} + +/* Return true if none of the PHI arguments in OPNDS is used given + the use guards in *THIS that guard the PHI's use. */ + +bool +predicate::use_cannot_happen (gphi *phi, unsigned opnds) +{ + if (!m_eval.phi_arg_set (phi)) + return false; + + /* PHI_USE_GUARDS are OR'ed together. If we have more than one + possible guard, there's no way of knowing which guard was true. + Since we need to be absolutely sure that the uninitialized + operands will be invalidated, bail. */ + const pred_chain_union &phi_use_guards = m_preds; + if (phi_use_guards.length () != 1) + return false; + + const pred_chain &use_guard = phi_use_guards[0]; + + /* Look for the control dependencies of all the interesting operands + and build guard predicates describing them. */ + unsigned n = gimple_phi_num_args (phi); + for (unsigned i = 0; i < n; ++i) + { + if (!MASK_TEST_BIT (opnds, i)) + continue; + + edge e = gimple_phi_arg_edge (phi, i); + auto_vec<edge> dep_chains[MAX_NUM_CHAINS]; + auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain; + unsigned num_chains = 0; + unsigned num_calls = 0; + + /* Build the control dependency chain for the PHI argument... */ + if (!compute_control_dep_chain (ENTRY_BLOCK_PTR_FOR_FN (cfun), + e->src, dep_chains, &num_chains, + cur_chain, &num_calls)) + return false; + + if (DEBUG_PREDICATE_ANALYZER && dump_file) + { + fprintf (dump_file, "predicate::use_cannot_happen (...) " + "dep_chains for arg %u:\n\t", i); + dump_dep_chains (dep_chains, num_chains); + } + + /* ...and convert it into a set of predicates guarding its + definition. */ + predicate def_preds (m_eval); + def_preds.init_from_control_deps (dep_chains, num_chains); + if (def_preds.is_empty ()) + /* If there's no predicate there's no basis to rule the use out. */ + return false; + + def_preds.simplify (); + def_preds.normalize (); + + /* Can the guard for this PHI argument be negated by the one + guarding the PHI use? */ + if (!can_be_invalidated_p (def_preds.chain (), use_guard)) + return false; + } + + return true; +} + +/* Implemented simplifications: + + 1) ((x IOR y) != 0) AND (x != 0) is equivalent to (x != 0); + 2) (X AND Y) OR (!X AND Y) is equivalent to Y; + 3) X OR (!X AND Y) is equivalent to (X OR Y); + 4) ((x IAND y) != 0) || (x != 0 AND y != 0)) is equivalent to + (x != 0 AND y != 0) + 5) (X AND Y) OR (!X AND Z) OR (!Y AND Z) is equivalent to + (X AND Y) OR Z + + PREDS is the predicate chains, and N is the number of chains. */ + +/* Implement rule 1 above. PREDS is the AND predicate to simplify + in place. */ + +static void +simplify_1 (pred_chain &chain) +{ + bool simplified = false; + pred_chain s_chain = vNULL; + + unsigned n = chain.length (); + for (unsigned i = 0; i < n; i++) + { + pred_info &a_pred = chain[i]; + + if (!a_pred.pred_lhs + || !is_neq_zero_form_p (a_pred)) + continue; + + gimple *def_stmt = SSA_NAME_DEF_STMT (a_pred.pred_lhs); + if (gimple_code (def_stmt) != GIMPLE_ASSIGN) + continue; + + if (gimple_assign_rhs_code (def_stmt) != BIT_IOR_EXPR) + continue; + + for (unsigned j = 0; j < n; j++) + { + const pred_info &b_pred = chain[j]; + + if (!b_pred.pred_lhs + || !is_neq_zero_form_p (b_pred)) + continue; + + if (pred_expr_equal_p (b_pred, gimple_assign_rhs1 (def_stmt)) + || pred_expr_equal_p (b_pred, gimple_assign_rhs2 (def_stmt))) + { + /* Mark A_PRED for removal from PREDS. */ + a_pred.pred_lhs = NULL; + a_pred.pred_rhs = NULL; + simplified = true; + break; + } + } + } + + if (!simplified) + return; + + /* Remove predicates marked above. */ + for (unsigned i = 0; i < n; i++) + { + pred_info &a_pred = chain[i]; + if (!a_pred.pred_lhs) + continue; + s_chain.safe_push (a_pred); + } + + chain.release (); + chain = s_chain; +} + +/* Implements rule 2 for the OR predicate PREDS: + + 2) (X AND Y) OR (!X AND Y) is equivalent to Y. */ + +bool +predicate::simplify_2 () +{ + bool simplified = false; + + /* (X AND Y) OR (!X AND Y) is equivalent to Y. + (X AND Y) OR (X AND !Y) is equivalent to X. */ + + unsigned n = m_preds.length (); + for (unsigned i = 0; i < n; i++) + { + pred_chain &a_chain = m_preds[i]; + if (a_chain.length () != 2) + continue; + + /* Create copies since the chain may be released below before + the copy is added to the other chain. */ + const pred_info x = a_chain[0]; + const pred_info y = a_chain[1]; + + for (unsigned j = 0; j < n; j++) + { + if (j == i) + continue; + + pred_chain &b_chain = m_preds[j]; + if (b_chain.length () != 2) + continue; + + const pred_info &x2 = b_chain[0]; + const pred_info &y2 = b_chain[1]; + + if (pred_equal_p (x, x2) && pred_neg_p (y, y2)) + { + /* Kill a_chain. */ + b_chain.release (); + a_chain.release (); + b_chain.safe_push (x); + simplified = true; + break; + } + if (pred_neg_p (x, x2) && pred_equal_p (y, y2)) + { + /* Kill a_chain. */ + a_chain.release (); + b_chain.release (); + b_chain.safe_push (y); + simplified = true; + break; + } + } + } + /* Now clean up the chain. */ + if (simplified) + { + pred_chain_union s_preds = vNULL; + for (unsigned i = 0; i < n; i++) + { + if (m_preds[i].is_empty ()) + continue; + s_preds.safe_push (m_preds[i]); + } + m_preds.release (); + m_preds = s_preds; + s_preds = vNULL; + } + + return simplified; +} + +/* Implement rule 3 for the OR predicate PREDS: + + 3) x OR (!x AND y) is equivalent to x OR y. */ + +bool +predicate::simplify_3 () +{ + /* Now iteratively simplify X OR (!X AND Z ..) + into X OR (Z ...). */ + + unsigned n = m_preds.length (); + if (n < 2) + return false; + + bool simplified = false; + for (unsigned i = 0; i < n; i++) + { + const pred_chain &a_chain = m_preds[i]; + + if (a_chain.length () != 1) + continue; + + const pred_info &x = a_chain[0]; + for (unsigned j = 0; j < n; j++) + { + if (j == i) + continue; + + pred_chain b_chain = m_preds[j]; + if (b_chain.length () < 2) + continue; + + for (unsigned k = 0; k < b_chain.length (); k++) + { + const pred_info &x2 = b_chain[k]; + if (pred_neg_p (x, x2)) + { + b_chain.unordered_remove (k); + simplified = true; + break; + } + } + } + } + return simplified; +} + +/* Implement rule 4 for the OR predicate PREDS: + + 2) ((x AND y) != 0) OR (x != 0 AND y != 0) is equivalent to + (x != 0 ANd y != 0). */ + +bool +predicate::simplify_4 () +{ + bool simplified = false; + pred_chain_union s_preds = vNULL; + + unsigned n = m_preds.length (); + for (unsigned i = 0; i < n; i++) + { + pred_chain a_chain = m_preds[i]; + if (a_chain.length () != 1) + continue; + + const pred_info &z = a_chain[0]; + if (!is_neq_zero_form_p (z)) + continue; + + gimple *def_stmt = SSA_NAME_DEF_STMT (z.pred_lhs); + if (gimple_code (def_stmt) != GIMPLE_ASSIGN) + continue; + + if (gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR) + continue; + + for (unsigned j = 0; j < n; j++) + { + if (j == i) + continue; + + pred_chain b_chain = m_preds[j]; + if (b_chain.length () != 2) + continue; + + const pred_info &x2 = b_chain[0]; + const pred_info &y2 = b_chain[1]; + if (!is_neq_zero_form_p (x2) || !is_neq_zero_form_p (y2)) + continue; + + if ((pred_expr_equal_p (x2, gimple_assign_rhs1 (def_stmt)) + && pred_expr_equal_p (y2, gimple_assign_rhs2 (def_stmt))) + || (pred_expr_equal_p (x2, gimple_assign_rhs2 (def_stmt)) + && pred_expr_equal_p (y2, gimple_assign_rhs1 (def_stmt)))) + { + /* Kill a_chain. */ + a_chain.release (); + simplified = true; + break; + } + } + } + /* Now clean up the chain. */ + if (simplified) + { + for (unsigned i = 0; i < n; i++) + { + if (m_preds[i].is_empty ()) + continue; + s_preds.safe_push (m_preds[i]); + } + + m_preds.release (); + m_preds = s_preds; + s_preds = vNULL; + } + + return simplified; +} + +/* Simplify predicates in *THIS. */ + +void +predicate::simplify (gimple *use_or_def, bool is_use) +{ + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "Before simplication "); + dump (use_or_def, is_use ? "[USE]:\n" : "[DEF]:\n"); + } + + unsigned n = m_preds.length (); + for (unsigned i = 0; i < n; i++) + ::simplify_1 (m_preds[i]); + + if (n < 2) + return; + + bool changed; + do + { + changed = false; + if (simplify_2 ()) + changed = true; + + if (simplify_3 ()) + changed = true; + + if (simplify_4 ()) + changed = true; + } + while (changed); +} + +/* Attempt to normalize predicate chains by following UD chains by + building up a big tree of either IOR operations or AND operations, + and converting the IOR tree into a pred_chain_union or the BIT_AND + tree into a pred_chain. + Example: + + _3 = _2 RELOP1 _1; + _6 = _5 RELOP2 _4; + _9 = _8 RELOP3 _7; + _10 = _3 | _6; + _12 = _9 | _0; + _t = _10 | _12; + + then _t != 0 will be normalized into a pred_chain_union + + (_2 RELOP1 _1) OR (_5 RELOP2 _4) OR (_8 RELOP3 _7) OR (_0 != 0) + + Similarly given: + + _3 = _2 RELOP1 _1; + _6 = _5 RELOP2 _4; + _9 = _8 RELOP3 _7; + _10 = _3 & _6; + _12 = _9 & _0; + + then _t != 0 will be normalized into a pred_chain: + (_2 RELOP1 _1) AND (_5 RELOP2 _4) AND (_8 RELOP3 _7) AND (_0 != 0) + */ + +/* Store a PRED in *THIS. */ + +void +predicate::push_pred (const pred_info &pred) +{ + pred_chain chain = vNULL; + chain.safe_push (pred); + m_preds.safe_push (chain); +} + +/* Dump predicates in *THIS for STMT prepended by MSG. */ + +void +predicate::dump (gimple *stmt, const char *msg) const +{ + fprintf (dump_file, "%s", msg); + if (stmt) + { + fputc ('\t', dump_file); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, " is conditional on:\n"); + } + + unsigned np = m_preds.length (); + if (np == 0) + { + fprintf (dump_file, "\t(empty)\n"); + return; + } + + { + tree expr = build_pred_expr (m_preds); + char *str = print_generic_expr_to_str (expr); + fprintf (dump_file, "\t%s (expanded)\n", str); + free (str); + } + + if (np > 1) + fprintf (dump_file, "\tOR ("); + else + fputc ('\t', dump_file); + for (unsigned i = 0; i < np; i++) + { + dump_pred_chain (m_preds[i]); + if (i < np - 1) + fprintf (dump_file, ", "); + else if (i > 0) + fputc (')', dump_file); + } + fputc ('\n', dump_file); +} + +/* Initialize *THIS with the predicates of the control dependence chains + between the basic block DEF_BB that defines a variable of interst and + USE_BB that uses the variable, respectively. */ + +predicate::predicate (basic_block def_bb, basic_block use_bb, func_t &eval) + : m_preds (vNULL), m_eval (eval) +{ + /* Set CD_ROOT to the basic block closest to USE_BB that is the control + equivalent of (is guarded by the same predicate as) DEF_BB that also + dominates USE_BB. */ + basic_block cd_root = def_bb; + while (dominated_by_p (CDI_DOMINATORS, use_bb, cd_root)) + { + /* Find CD_ROOT's closest postdominator that's its control + equivalent. */ + if (basic_block bb = find_control_equiv_block (cd_root)) + if (dominated_by_p (CDI_DOMINATORS, use_bb, bb)) + { + cd_root = bb; + continue; + } + + break; + } + + /* Set DEP_CHAINS to the set of edges between CD_ROOT and USE_BB. + Each DEP_CHAINS element is a series of edges whose conditions + are logical conjunctions. Together, the DEP_CHAINS vector is + used below to initialize an OR expression of the conjunctions. */ + unsigned num_calls = 0; + unsigned num_chains = 0; + auto_vec<edge> dep_chains[MAX_NUM_CHAINS]; + auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain; + + compute_control_dep_chain (cd_root, use_bb, dep_chains, &num_chains, + cur_chain, &num_calls); + + if (DEBUG_PREDICATE_ANALYZER && dump_file) + { + fprintf (dump_file, "predicate::predicate (def_bb = %u, use_bb = %u, func_t) " + "initialized from %u dep_chains:\n\t", + def_bb->index, use_bb->index, num_chains); + dump_dep_chains (dep_chains, num_chains); + } + + /* From the set of edges computed above initialize *THIS as the OR + condition under which the definition in DEF_BB is used in USE_BB. + Each OR subexpression is represented by one element of DEP_CHAINS, + where each element consists of a series of AND subexpressions. */ + init_from_control_deps (dep_chains, num_chains); +} + +/* Release resources in *THIS. */ + +predicate::~predicate () +{ + unsigned n = m_preds.length (); + for (unsigned i = 0; i != n; ++i) + m_preds[i].release (); + m_preds.release (); +} + +/* Copy-assign RHS to *THIS. */ + +predicate& +predicate::operator= (const predicate &rhs) +{ + if (this == &rhs) + return *this; + + /* FIXME: Make this a compile-time constraint? */ + gcc_assert (&m_eval == &rhs.m_eval); + + unsigned n = m_preds.length (); + for (unsigned i = 0; i != n; ++i) + m_preds[i].release (); + m_preds.release (); + + n = rhs.m_preds.length (); + for (unsigned i = 0; i != n; ++i) + { + const pred_chain &chain = rhs.m_preds[i]; + m_preds.safe_push (chain.copy ()); + } + + return *this; +} + +/* For each use edge of PHI, compute all control dependence chains + and convert those to the composite predicates in M_PREDS. + Return true if a nonempty predicate has been obtained. */ + +bool +predicate::init_from_phi_def (gphi *phi) +{ + gcc_assert (is_empty ()); + + basic_block phi_bb = gimple_bb (phi); + /* Find the closest dominating bb to be the control dependence root. */ + basic_block cd_root = find_dom (phi_bb); + if (!cd_root) + return false; + + /* Set DEF_EDGES to the edges to the PHI from the bb's that provide + definitions of each of the PHI operands for which M_EVAL is false. */ + auto_vec<edge> def_edges; + hash_set<gimple *> visited_phis; + collect_phi_def_edges (phi, cd_root, &def_edges, m_eval, &visited_phis); + + unsigned nedges = def_edges.length (); + if (nedges == 0) + return false; + + unsigned num_chains = 0; + auto_vec<edge> dep_chains[MAX_NUM_CHAINS]; + auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain; + for (unsigned i = 0; i < nedges; i++) + { + edge e = def_edges[i]; + unsigned num_calls = 0; + unsigned prev_nc = num_chains; + compute_control_dep_chain (cd_root, e->src, dep_chains, + &num_chains, cur_chain, &num_calls); + + /* Update the newly added chains with the phi operand edge. */ + if (EDGE_COUNT (e->src->succs) > 1) + { + if (prev_nc == num_chains && num_chains < MAX_NUM_CHAINS) + dep_chains[num_chains++] = vNULL; + for (unsigned j = prev_nc; j < num_chains; j++) + dep_chains[j].safe_push (e); + } + } + + /* Convert control dependence chains to the predicate in *THIS under + which the PHI operands are defined to values for which M_EVAL is + false. */ + init_from_control_deps (dep_chains, num_chains); + return !is_empty (); +} + +/* Compute the predicates that guard the use USE_STMT and check if + the incoming paths that have an empty (or possibly empty) definition + can be pruned. Return true if it can be determined that the use of + PHI's def in USE_STMT is guarded by a predicate set that does not + overlap with the predicate sets of all runtime paths that do not + have a definition. + + Return false if the use is not guarded or if it cannot be determined. + USE_BB is the bb of the use (for phi operand use, the bb is not the bb + of the phi stmt, but the source bb of the operand edge). + + OPNDS is a bitmap with a bit set for each PHI operand of interest. + + THIS->M_PREDS contains the (memoized) defining predicate chains of + a PHI. If THIS->M_PREDS is empty, the PHI's defining predicate + chains are computed and stored into THIS->M_PREDS as needed. + + VISITED_PHIS is a pointer set of phis being visited. */ + +bool +predicate::is_use_guarded (gimple *use_stmt, basic_block use_bb, + gphi *phi, unsigned opnds, + hash_set<gphi *> *visited) +{ + if (visited->add (phi)) + return false; + + /* The basic block where the PHI is defined. */ + basic_block def_bb = gimple_bb (phi); + + /* Try to build the predicate expression under which the PHI flows + into its use. This will be empty if the PHI is defined and used + in the same bb. */ + predicate use_preds (def_bb, use_bb, m_eval); + + if (is_non_loop_exit_postdominating (use_bb, def_bb)) + { + if (is_empty ()) + { + /* Lazily initialize *THIS from the PHI and build its use + expression. */ + init_from_phi_def (phi); + m_use_expr = build_pred_expr (use_preds.m_preds); + } + + /* The use is not guarded. */ + return false; + } + + if (use_preds.is_empty ()) + return false; + + /* Try to prune the dead incoming phi edges. */ + if (!use_preds.overlap (phi, opnds, visited)) + { + if (DEBUG_PREDICATE_ANALYZER && dump_file) + fputs ("found predicate overlap\n", dump_file); + + return true; + } + + /* We might be able to prove that if the control dependencies for OPNDS + are true, the control dependencies for USE_STMT can never be true. */ + if (use_preds.use_cannot_happen (phi, opnds)) + return true; + + if (is_empty ()) + { + /* Lazily initialize *THIS from PHI. */ + if (!init_from_phi_def (phi)) + { + m_use_expr = build_pred_expr (use_preds.m_preds); + return false; + } + + simplify (phi); + normalize (phi); + } + + use_preds.simplify (use_stmt, /*is_use=*/true); + use_preds.normalize (use_stmt, /*is_use=*/true); + + /* Return true if the predicate guarding the valid definition (i.e., + *THIS) is a superset of the predicate guarding the use (i.e., + USE_PREDS). */ + if (superset_of (use_preds)) + return true; + + m_use_expr = build_pred_expr (use_preds.m_preds); + + return false; +} + +/* Public interface to the above. */ + +bool +predicate::is_use_guarded (gimple *stmt, basic_block use_bb, gphi *phi, + unsigned opnds) +{ + hash_set<gphi *> visited; + return is_use_guarded (stmt, use_bb, phi, opnds, &visited); +} + +/* Normalize predicate PRED: + 1) if PRED can no longer be normalized, append it to *THIS. + 2) otherwise if PRED is of the form x != 0, follow x's definition + and put normalized predicates into WORK_LIST. */ + +void +predicate::normalize (pred_chain *norm_chain, + pred_info pred, + tree_code and_or_code, + pred_chain *work_list, + hash_set<tree> *mark_set) +{ + if (!is_neq_zero_form_p (pred)) + { + if (and_or_code == BIT_IOR_EXPR) + push_pred (pred); + else + norm_chain->safe_push (pred); + return; + } + + gimple *def_stmt = SSA_NAME_DEF_STMT (pred.pred_lhs); + + if (gimple_code (def_stmt) == GIMPLE_PHI + && is_degenerate_phi (def_stmt, &pred)) + /* PRED has been modified above. */ + work_list->safe_push (pred); + else if (gimple_code (def_stmt) == GIMPLE_PHI && and_or_code == BIT_IOR_EXPR) + { + unsigned n = gimple_phi_num_args (def_stmt); + + /* Punt for a nonzero constant. The predicate should be one guarding + the phi edge. */ + for (unsigned i = 0; i < n; ++i) + { + tree op = gimple_phi_arg_def (def_stmt, i); + if (TREE_CODE (op) == INTEGER_CST && !integer_zerop (op)) + { + push_pred (pred); + return; + } + } + + for (unsigned i = 0; i < n; ++i) + { + tree op = gimple_phi_arg_def (def_stmt, i); + if (integer_zerop (op)) + continue; + + push_to_worklist (op, work_list, mark_set); + } + } + else if (gimple_code (def_stmt) != GIMPLE_ASSIGN) + { + if (and_or_code == BIT_IOR_EXPR) + push_pred (pred); + else + norm_chain->safe_push (pred); + } + else if (gimple_assign_rhs_code (def_stmt) == and_or_code) + { + /* Avoid splitting up bit manipulations like x & 3 or y | 1. */ + if (is_gimple_min_invariant (gimple_assign_rhs2 (def_stmt))) + { + /* But treat x & 3 as a condition. */ + if (and_or_code == BIT_AND_EXPR) + { + pred_info n_pred; + n_pred.pred_lhs = gimple_assign_rhs1 (def_stmt); + n_pred.pred_rhs = gimple_assign_rhs2 (def_stmt); + n_pred.cond_code = and_or_code; + n_pred.invert = false; + norm_chain->safe_push (n_pred); + } + } + else + { + push_to_worklist (gimple_assign_rhs1 (def_stmt), work_list, mark_set); + push_to_worklist (gimple_assign_rhs2 (def_stmt), work_list, mark_set); + } + } + else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) + == tcc_comparison) + { + pred_info n_pred = get_pred_info_from_cmp (def_stmt); + if (and_or_code == BIT_IOR_EXPR) + push_pred (n_pred); + else + norm_chain->safe_push (n_pred); + } + else + { + if (and_or_code == BIT_IOR_EXPR) + push_pred (pred); + else + norm_chain->safe_push (pred); + } +} + +/* Normalize PRED and store the normalized predicates in THIS->M_PREDS. */ + +void +predicate::normalize (const pred_info &pred) +{ + if (!is_neq_zero_form_p (pred)) + { + push_pred (pred); + return; + } + + tree_code and_or_code = ERROR_MARK; + + gimple *def_stmt = SSA_NAME_DEF_STMT (pred.pred_lhs); + if (gimple_code (def_stmt) == GIMPLE_ASSIGN) + and_or_code = gimple_assign_rhs_code (def_stmt); + if (and_or_code != BIT_IOR_EXPR && and_or_code != BIT_AND_EXPR) + { + if (TREE_CODE_CLASS (and_or_code) == tcc_comparison) + { + pred_info n_pred = get_pred_info_from_cmp (def_stmt); + push_pred (n_pred); + } + else + push_pred (pred); + return; + } + + + pred_chain norm_chain = vNULL; + pred_chain work_list = vNULL; + work_list.safe_push (pred); + hash_set<tree> mark_set; + + while (!work_list.is_empty ()) + { + pred_info a_pred = work_list.pop (); + normalize (&norm_chain, a_pred, and_or_code, &work_list, &mark_set); + } + + if (and_or_code == BIT_AND_EXPR) + m_preds.safe_push (norm_chain); + + work_list.release (); +} + +/* Normalize a single predicate PRED_CHAIN and append it to *THIS. */ + +void +predicate::normalize (const pred_chain &chain) +{ + pred_chain work_list = vNULL; + hash_set<tree> mark_set; + for (unsigned i = 0; i < chain.length (); i++) + { + work_list.safe_push (chain[i]); + mark_set.add (chain[i].pred_lhs); + } + + /* Normalized chain of predicates built up below. */ + pred_chain norm_chain = vNULL; + while (!work_list.is_empty ()) + { + pred_info pi = work_list.pop (); + predicate pred (m_eval); + /* The predicate object is not modified here, only NORM_CHAIN and + WORK_LIST are appended to. */ + pred.normalize (&norm_chain, pi, BIT_AND_EXPR, &work_list, &mark_set); + } + + m_preds.safe_push (norm_chain); + work_list.release (); +} + +/* Normalize predicate chains in THIS. */ + +void +predicate::normalize (gimple *use_or_def, bool is_use) +{ + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "Before normalization "); + dump (use_or_def, is_use ? "[USE]:\n" : "[DEF]:\n"); + } + + predicate norm_preds (m_eval); + for (unsigned i = 0; i < m_preds.length (); i++) + { + if (m_preds[i].length () != 1) + norm_preds.normalize (m_preds[i]); + else + norm_preds.normalize (m_preds[i][0]); + } + + *this = norm_preds; + + if (dump_file) + { + fprintf (dump_file, "After normalization "); + dump (use_or_def, is_use ? "[USE]:\n" : "[DEF]:\n"); + } +} + +/* Add a predicate for the condition or logical assignment STMT to CHAIN. + Expand SSA_NAME into constituent subexpressions. Invert the result + if INVERT is true. Return true if the predicate has been added. */ + +static bool +add_pred (pred_chain *chain, gimple *stmt, bool invert) +{ + if (gimple_code (stmt) == GIMPLE_COND) + { + tree lhs = gimple_cond_lhs (stmt); + if (TREE_CODE (lhs) == SSA_NAME) + { + gimple *def = SSA_NAME_DEF_STMT (lhs); + if (is_gimple_assign (def) + && add_pred (chain, def, invert)) + return true; + } + + pred_info pred; + pred.pred_lhs = lhs; + pred.pred_rhs = gimple_cond_rhs (stmt); + pred.cond_code = gimple_cond_code (stmt); + pred.invert = invert; + chain->safe_push (pred); + return true; + } + + if (!is_gimple_assign (stmt)) + return false; + + if (gimple_assign_single_p (stmt)) + // FIXME: handle this? + return false; + + if (TREE_TYPE (gimple_assign_lhs (stmt)) != boolean_type_node) + return false; + + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree_code code = gimple_assign_rhs_code (stmt); + if (code == BIT_AND_EXPR) + { + if (TREE_CODE (rhs1) == SSA_NAME + && add_pred (chain, SSA_NAME_DEF_STMT (rhs1), invert) + && TREE_CODE (rhs2) == SSA_NAME + /* FIXME: Need to handle failure below! */ + && add_pred (chain, SSA_NAME_DEF_STMT (rhs2), invert)) + return true; + } + else if (TREE_CODE_CLASS (code) != tcc_comparison) + return false; + + pred_info pred; + pred.pred_lhs = rhs1; + pred.pred_rhs = rhs2; + pred.cond_code = code; + pred.invert = invert; + chain->safe_push (pred); + return true; +} + +/* Convert the chains of control dependence edges into a set of predicates. + A control dependence chain is represented by a vector edges. DEP_CHAINS + points to an array of NUM_CHAINS dependence chains. One edge in + a dependence chain is mapped to predicate expression represented by + pred_info type. One dependence chain is converted to a composite + predicate that is the result of AND operation of pred_info mapped to + each edge. A composite predicate is represented by a vector of + pred_info. Sets M_PREDS to the resulting composite predicates. */ + +void +predicate::init_from_control_deps (const vec<edge> *dep_chains, + unsigned num_chains) +{ + gcc_assert (is_empty ()); + + bool has_valid_pred = false; + if (num_chains == 0) + return; + + if (num_chains >= MAX_NUM_CHAINS) + { + if (dump_file) + fprintf (dump_file, "MAX_NUM_CHAINS exceeded: %u\n", num_chains); + return; + } + + /* Convert the control dependency chain into a set of predicates. */ + m_preds.reserve (num_chains); + + for (unsigned i = 0; i < num_chains; i++) + { + /* One path through the CFG represents a logical conjunction + of the predicates. */ + const vec<edge> &path = dep_chains[i]; + + has_valid_pred = false; + /* The chain of predicates guarding the definition along this path. */ + pred_chain t_chain{ }; + for (unsigned j = 0; j < path.length (); j++) + { + edge e = path[j]; + basic_block guard_bb = e->src; + /* Ignore empty forwarder blocks. */ + if (empty_block_p (guard_bb) && single_succ_p (guard_bb)) + continue; + + /* An empty basic block here is likely a PHI, and is not one + of the cases we handle below. */ + gimple_stmt_iterator gsi = gsi_last_bb (guard_bb); + if (gsi_end_p (gsi)) + { + has_valid_pred = false; + break; + } + /* Get the conditional controlling the bb exit edge. */ + gimple *cond_stmt = gsi_stmt (gsi); + if (is_gimple_call (cond_stmt) && EDGE_COUNT (e->src->succs) >= 2) + /* Ignore EH edge. Can add assertion on the other edge's flag. */ + continue; + /* Skip if there is essentially one succesor. */ + if (EDGE_COUNT (e->src->succs) == 2) + { + edge e1; + edge_iterator ei1; + bool skip = false; + + FOR_EACH_EDGE (e1, ei1, e->src->succs) + { + if (EDGE_COUNT (e1->dest->succs) == 0) + { + skip = true; + break; + } + } + if (skip) + continue; + } + if (gimple_code (cond_stmt) == GIMPLE_COND) + { + /* The true edge corresponds to the uninteresting condition. + Add the negated predicate(s) for the edge to record + the interesting condition. */ + pred_info one_pred; + one_pred.pred_lhs = gimple_cond_lhs (cond_stmt); + one_pred.pred_rhs = gimple_cond_rhs (cond_stmt); + one_pred.cond_code = gimple_cond_code (cond_stmt); + one_pred.invert = !!(e->flags & EDGE_FALSE_VALUE); + + t_chain.safe_push (one_pred); + + if (DEBUG_PREDICATE_ANALYZER && dump_file) + { + fprintf (dump_file, "one_pred = "); + dump_pred_info (one_pred); + fputc ('\n', dump_file); + } + + has_valid_pred = true; + } + else if (gswitch *gs = dyn_cast<gswitch *> (cond_stmt)) + { + /* Avoid quadratic behavior. */ + if (gimple_switch_num_labels (gs) > MAX_SWITCH_CASES) + { + has_valid_pred = false; + break; + } + /* Find the case label. */ + tree l = NULL_TREE; + unsigned idx; + for (idx = 0; idx < gimple_switch_num_labels (gs); ++idx) + { + tree tl = gimple_switch_label (gs, idx); + if (e->dest == label_to_block (cfun, CASE_LABEL (tl))) + { + if (!l) + l = tl; + else + { + l = NULL_TREE; + break; + } + } + } + /* If more than one label reaches this block or the case + label doesn't have a single value (like the default one) + fail. */ + if (!l + || !CASE_LOW (l) + || (CASE_HIGH (l) + && !operand_equal_p (CASE_LOW (l), CASE_HIGH (l), 0))) + { + has_valid_pred = false; + break; + } + + pred_info one_pred; + one_pred.pred_lhs = gimple_switch_index (gs); + one_pred.pred_rhs = CASE_LOW (l); + one_pred.cond_code = EQ_EXPR; + one_pred.invert = false; + t_chain.safe_push (one_pred); + has_valid_pred = true; + } + else + { + /* Disabled. See PR 90994. + has_valid_pred = false; */ + break; + } + } + + if (!has_valid_pred) + break; + else + m_preds.safe_push (t_chain); + } + + if (DEBUG_PREDICATE_ANALYZER && dump_file) + { + fprintf (dump_file, "init_from_control_deps {%s}:\n", + format_edge_vecs (dep_chains, num_chains).c_str ()); + dump (NULL, ""); + } + + if (has_valid_pred) + gcc_assert (m_preds.length () != 0); + else + /* Clear M_PREDS to indicate failure. */ + m_preds.release (); +} + +/* Return the predicate expression guarding the definition of + the interesting variable. When INVERT is set, return the logical + NOT of the predicate. */ + +tree +predicate::def_expr (bool invert /* = false */) const +{ + /* The predicate is stored in an inverted form. */ + return build_pred_expr (m_preds, !invert); +} + +/* Return the predicate expression guarding the use of the interesting + variable or null if the use predicate hasn't been determined yet. */ + +tree +predicate::use_expr () const +{ + return m_use_expr; +} + +/* Return a logical AND expression with the (optionally inverted) predicate + expression guarding the definition of the interesting variable and one + guarding its use. Return null if the use predicate hasn't yet been + determined. */ + +tree +predicate::expr (bool invert /* = false */) const +{ + if (!m_use_expr) + return NULL_TREE; + + tree expr = build_pred_expr (m_preds, !invert); + return build2 (TRUTH_AND_EXPR, boolean_type_node, expr, m_use_expr); +} diff --git a/gcc/gimple-predicate-analysis.h b/gcc/gimple-predicate-analysis.h new file mode 100644 index 0000000..fbf6f8e --- /dev/null +++ b/gcc/gimple-predicate-analysis.h @@ -0,0 +1,158 @@ +/* Support for simple predicate analysis. + + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Martin Sebor <msebor@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 GIMPLE_PREDICATE_ANALYSIS_H_INCLUDED +#define GIMPLE_PREDICATE_ANALYSIS_H_INCLUDED + +#define MAX_NUM_CHAINS 8 +#define MAX_CHAIN_LEN 5 +#define MAX_POSTDOM_CHECK 8 +#define MAX_SWITCH_CASES 40 + +/* Represents a simple Boolean predicate. */ +struct pred_info +{ + tree pred_lhs; + tree pred_rhs; + enum tree_code cond_code; + bool invert; +}; + +/* The type to represent a sequence of predicates grouped + with .AND. operation. */ +typedef vec<pred_info, va_heap, vl_ptr> pred_chain; + +/* The type to represent a sequence of pred_chains grouped + with .OR. operation. */ +typedef vec<pred_chain, va_heap, vl_ptr> pred_chain_union; + +/* Represents a complex Boolean predicate expression. */ +class predicate +{ + public: + /* Base function object type used to determine whether an expression + is of interest. */ + struct func_t + { + typedef unsigned phi_arg_set_t; + + /* Return true if the argument is an expression of interest. */ + virtual bool operator()(tree) = 0; + /* Return a bitset of PHI arguments of interest. By default returns + bitset with a bit set for each argument. Should be called in + the overriden function first and, if nonzero, the result then + refined as appropriate. */ + virtual phi_arg_set_t phi_arg_set (gphi *); + + /* Maximum number of PHI arguments supported by phi_arg_set(). */ + static constexpr unsigned max_phi_args = + sizeof (phi_arg_set_t) * CHAR_BIT; + }; + + /* Construct with the specified EVAL object. */ + predicate (func_t &eval) + : m_preds (vNULL), m_eval (eval), m_use_expr () { } + + /* Copy. */ + predicate (const predicate &rhs) + : m_preds (vNULL), m_eval (rhs.m_eval), m_use_expr () + { + *this = rhs; + } + + predicate (basic_block, basic_block, func_t &); + + ~predicate (); + + /* Assign. */ + predicate& operator= (const predicate &); + + bool is_empty () const + { + return m_preds.is_empty (); + } + + const pred_chain_union chain () const + { + return m_preds; + } + + /* Return true if the use by a statement in the basic block of + a PHI operand is ruled out (i.e., guarded) by *THIS. */ + bool is_use_guarded (gimple *, basic_block, gphi *, unsigned); + + void init_from_control_deps (const vec<edge> *, unsigned); + + void dump (gimple *, const char *) const; + + void normalize (gimple * = NULL, bool = false); + void simplify (gimple * = NULL, bool = false); + + bool is_use_guarded (gimple *, basic_block, gphi *, unsigned, + hash_set<gphi *> *); + + /* Return the predicate expression guarding the definition of + the interesting variable, optionally inverted. */ + tree def_expr (bool = false) const; + /* Return the predicate expression guarding the use of the interesting + variable. */ + tree use_expr () const; + + tree expr (bool = false) const; + +private: + bool includes (const pred_chain &) const; + bool superset_of (const predicate &) const; + bool overlap (gphi *, unsigned, hash_set<gphi *> *); + bool use_cannot_happen (gphi *, unsigned); + + bool init_from_phi_def (gphi *); + + void push_pred (const pred_info &); + + /* Normalization functions. */ + void normalize (pred_chain *, pred_info, tree_code, pred_chain *, + hash_set<tree> *); + + void normalize (const pred_info &); + void normalize (const pred_chain &); + + /* Simplification functions. */ + bool simplify_2 (); + bool simplify_3 (); + bool simplify_4 (); + +private: + /* Representation of the predicate expression(s). */ + pred_chain_union m_preds; + /* Callback to evaluate an operand. Return true if it's interesting. */ + func_t &m_eval; + /* The predicate expression guarding the use of the interesting + variable. */ + tree m_use_expr; +}; + +/* Bit mask handling macros. */ +#define MASK_SET_BIT(mask, pos) mask |= (1 << pos) +#define MASK_TEST_BIT(mask, pos) (mask & (1 << pos)) +#define MASK_EMPTY(mask) (mask == 0) + +#endif // GIMPLE_PREDICATE_ANALYSIS_H_INCLUDED diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index facf981..b856b21 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -37,8 +37,8 @@ along with GCC; see the file COPYING3. If not see non_null_ref::non_null_ref () { - m_nn.create (0); - m_nn.safe_grow_cleared (num_ssa_names); + m_nn.create (num_ssa_names); + m_nn.quick_grow_cleared (num_ssa_names); bitmap_obstack_initialize (&m_bitmaps); } @@ -760,7 +760,7 @@ ranger_cache::ranger_cache () m_temporal = new temporal_cache; // If DOM info is available, spawn an oracle as well. if (dom_info_available_p (CDI_DOMINATORS)) - m_oracle = new relation_oracle (); + m_oracle = new dom_oracle (); else m_oracle = NULL; diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 7cf8830..d7fa0f2 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -195,7 +195,7 @@ void fur_depend::register_relation (gimple *s, relation_kind k, tree op1, tree op2) { if (m_oracle) - m_oracle->register_relation (s, k, op1, op2); + m_oracle->register_stmt (s, k, op1, op2); } // Register a relation on an edge if there is an oracle. @@ -204,7 +204,7 @@ void fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2) { if (m_oracle) - m_oracle->register_relation (e, k, op1, op2); + m_oracle->register_edge (e, k, op1, op2); } // This version of fur_source will pick a range up from a list of ranges @@ -651,7 +651,17 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src) } } else if (is_a<gcond *> (s)) - postfold_gcond_edges (as_a<gcond *> (s), r, src); + { + basic_block bb = gimple_bb (s); + edge e0 = EDGE_SUCC (bb, 0); + edge e1 = EDGE_SUCC (bb, 1); + + if (!single_pred_p (e0->dest)) + e0 = NULL; + if (!single_pred_p (e1->dest)) + e1 = NULL; + src.register_outgoing_edges (as_a<gcond *> (s), r, e0, e1); + } } else r.set_varying (type); @@ -760,6 +770,10 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src) if (!type) return false; + // Track if all executable arguments are the same. + tree single_arg = NULL_TREE; + bool seen_arg = false; + // Start with an empty range, unioning in each argument's range. r.set_undefined (); for (x = 0; x < gimple_phi_num_args (phi); x++) @@ -767,21 +781,52 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src) tree arg = gimple_phi_arg_def (phi, x); edge e = gimple_phi_arg_edge (phi, x); - // Register potential dependencies for stale value tracking. - if (gimple_range_ssa_p (arg) && src.gori ()) - src.gori ()->register_dependency (phi_def, arg); - // Get the range of the argument on its edge. src.get_phi_operand (arg_range, arg, e); - // If we're recomputing the argument elsewhere, try to refine it. - r.union_ (arg_range); + + if (!arg_range.undefined_p ()) + { + // Register potential dependencies for stale value tracking. + r.union_ (arg_range); + if (gimple_range_ssa_p (arg) && src.gori ()) + src.gori ()->register_dependency (phi_def, arg); + + // Track if all arguments are the same. + if (!seen_arg) + { + seen_arg = true; + single_arg = arg; + } + else if (single_arg != arg) + single_arg = NULL_TREE; + } + // Once the value reaches varying, stop looking. - if (r.varying_p ()) + if (r.varying_p () && single_arg == NULL_TREE) break; } + // If the PHI boils down to a single effective argument, look at it. + if (single_arg) + { + // Symbolic arguments are equivalences. + if (gimple_range_ssa_p (single_arg)) + src.register_relation (phi, EQ_EXPR, phi_def, single_arg); + else if (src.get_operand (arg_range, single_arg) + && arg_range.singleton_p ()) + { + // Numerical arguments that are a constant can be returned as + // the constant. This can help fold later cases where even this + // constant might have been UNDEFINED via an unreachable edge. + r = arg_range; + return true; + } + } + // If SCEV is available, query if this PHI has any knonwn values. - if (scev_initialized_p () && !POINTER_TYPE_P (TREE_TYPE (phi_def))) + if (dom_info_available_p (CDI_DOMINATORS) + && scev_initialized_p () + && !POINTER_TYPE_P (TREE_TYPE (phi_def))) { value_range loop_range; class loop *l = loop_containing_stmt (phi); @@ -1351,8 +1396,7 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, // Register any outgoing edge relations from a conditional branch. void -fold_using_range::postfold_gcond_edges (gcond *s, irange& lhs_range, - fur_source &src) +fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e1) { int_range_max r; int_range<2> e0_range, e1_range; @@ -1364,10 +1408,7 @@ fold_using_range::postfold_gcond_edges (gcond *s, irange& lhs_range, if (!bb) return; - edge e0 = EDGE_SUCC (bb, 0); - if (!single_pred_p (e0->dest)) - e0 = NULL; - else + if (e0) { // If this edge is never taken, ignore it. gcond_edge_range (e0_range, e0); @@ -1377,10 +1418,7 @@ fold_using_range::postfold_gcond_edges (gcond *s, irange& lhs_range, } - edge e1 = EDGE_SUCC (bb, 1); - if (!single_pred_p (e1->dest)) - e1 = NULL; - else + if (e1) { // If this edge is never taken, ignore it. gcond_edge_range (e1_range, e1); @@ -1389,7 +1427,6 @@ fold_using_range::postfold_gcond_edges (gcond *s, irange& lhs_range, e1 = NULL; } - // At least one edge needs to be single pred. if (!e0 && !e1) return; @@ -1405,27 +1442,25 @@ fold_using_range::postfold_gcond_edges (gcond *s, irange& lhs_range, { relation_kind relation = handler->op1_op2_relation (e0_range); if (relation != VREL_NONE) - src.register_relation (e0, relation, ssa1, ssa2); + register_relation (e0, relation, ssa1, ssa2); } if (e1) { relation_kind relation = handler->op1_op2_relation (e1_range); if (relation != VREL_NONE) - src.register_relation (e1, relation, ssa1, ssa2); + register_relation (e1, relation, ssa1, ssa2); } } // Outgoing relations of GORI exports require a gori engine. - if (!src.gori ()) + if (!gori ()) return; - range_query *q = src.query (); // Now look for other relations in the exports. This will find stmts // leading to the condition such as: // c_2 = a_4 < b_7 // if (c_2) - - FOR_EACH_GORI_EXPORT_NAME (*(src.gori ()), bb, name) + FOR_EACH_GORI_EXPORT_NAME (*(gori ()), bb, name) { if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE) continue; @@ -1437,19 +1472,19 @@ fold_using_range::postfold_gcond_edges (gcond *s, irange& lhs_range, tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); if (ssa1 && ssa2) { - if (e0 && src.gori ()->outgoing_edge_range_p (r, e0, name, *q) + if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query) && r.singleton_p ()) { relation_kind relation = handler->op1_op2_relation (r); if (relation != VREL_NONE) - src.register_relation (e0, relation, ssa1, ssa2); + register_relation (e0, relation, ssa1, ssa2); } - if (e1 && src.gori ()->outgoing_edge_range_p (r, e1, name, *q) + if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query) && r.singleton_p ()) { relation_kind relation = handler->op1_op2_relation (r); if (relation != VREL_NONE) - src.register_relation (e1, relation, ssa1, ssa2); + register_relation (e1, relation, ssa1, ssa2); } } } diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index ceed7ba..bc0874b 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -129,6 +129,7 @@ public: tree op2); virtual void register_relation (edge e, relation_kind k, tree op1, tree op2); + void register_outgoing_edges (gcond *, irange &lhs_range, edge e0, edge e1); protected: range_query *m_query; gori_compute *m_gori; @@ -159,7 +160,7 @@ public: tree op2) OVERRIDE; virtual void register_relation (edge e, relation_kind k, tree op1, tree op2) OVERRIDE; -private: +protected: relation_oracle *m_oracle; }; @@ -188,6 +189,5 @@ protected: void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *, fur_source &src); void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src); - void postfold_gcond_edges (gcond *s, irange &lhs_range, fur_source &src); }; #endif // GCC_GIMPLE_RANGE_FOLD_H diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index f788295..f5a3528 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -1214,6 +1214,15 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, int_range_max lhs; unsigned idx; + if ((e->flags & EDGE_EXECUTABLE) == 0) + { + r.set_undefined (); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Outgoing edge %d->%d unexecutable.\n", + e->src->index, e->dest->index); + return true; + } + gcc_checking_assert (gimple_range_ssa_p (name)); // Determine if there is an outgoing edge. gimple *stmt = outgoing.edge_range_p (lhs, e); @@ -1221,22 +1230,6 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, return false; fur_stmt src (stmt, &q); - - // If this edge is never taken, return undefined. - gcond *gc = dyn_cast<gcond *> (stmt); - if (gc) - { - if (((e->flags & EDGE_TRUE_VALUE) && gimple_cond_false_p (gc)) - || ((e->flags & EDGE_FALSE_VALUE) && gimple_cond_true_p (gc))) - { - r.set_undefined (); - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Outgoing edge %d->%d unexecutable.\n", - e->src->index, e->dest->index); - return true; - } - } - // If NAME can be calculated on the edge, use that. if (is_export_p (name, e->src)) { diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index c616b65..e65c799 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -30,22 +30,30 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "gimple-range-path.h" #include "ssa.h" +#include "tree-cfg.h" +#include "gimple-iterator.h" // Internal construct to help facilitate debugging of solver. #define DEBUG_SOLVER (0 && dump_file) -path_range_query::path_range_query (gimple_ranger &ranger) +path_range_query::path_range_query (gimple_ranger &ranger, bool resolve) : m_ranger (ranger) { + if (DEBUG_SOLVER) + fprintf (dump_file, "\n*********** path_range_query ******************\n"); + m_cache = new ssa_global_cache; m_has_cache_entry = BITMAP_ALLOC (NULL); m_path = NULL; + m_resolve = resolve; + m_oracle = new path_oracle (ranger.oracle ()); } path_range_query::~path_range_query () { BITMAP_FREE (m_has_cache_entry); delete m_cache; + delete m_oracle; } // Mark cache entry for NAME as unused. @@ -85,14 +93,15 @@ path_range_query::set_cache (const irange &r, tree name) void path_range_query::dump (FILE *dump_file) { + push_dump_file save (dump_file, dump_flags & ~TDF_DETAILS); + if (m_path->is_empty ()) return; unsigned i; bitmap_iterator bi; - extern void dump_ranger (FILE *, const vec<basic_block> &); - fprintf (dump_file, "Path is (length=%d):\n", m_path->length ()); + fprintf (dump_file, "\nPath is (length=%d):\n", m_path->length ()); dump_ranger (dump_file, *m_path); fprintf (dump_file, "Imports:\n"); @@ -112,6 +121,34 @@ path_range_query::debug () dump (stderr); } +// Return TRUE if NAME is defined outside the current path. + +bool +path_range_query::defined_outside_path (tree name) +{ + gimple *def = SSA_NAME_DEF_STMT (name); + basic_block bb = gimple_bb (def); + + return !bb || !m_path->contains (bb); +} + +// Return the range of NAME on entry to the path. + +void +path_range_query::range_on_path_entry (irange &r, tree name) +{ + int_range_max tmp; + basic_block entry = entry_bb (); + r.set_undefined (); + for (unsigned i = 0; i < EDGE_COUNT (entry->preds); ++i) + { + edge e = EDGE_PRED (entry, i); + if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun) + && m_ranger.range_on_edge (tmp, e, name)) + r.union_ (tmp); + } +} + // Return the range of NAME at the end of the path being analyzed. bool @@ -123,6 +160,16 @@ path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt) if (get_cache (r, name)) return true; + if (m_resolve && defined_outside_path (name)) + { + range_on_path_entry (r, name); + + if (r.varying_p ()) + improve_range_with_equivs (r, name); + + set_cache (r, name); + return true; + } basic_block bb = stmt ? gimple_bb (stmt) : exit_bb (); if (stmt && range_defined_in_block (r, name, bb)) @@ -130,6 +177,9 @@ path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt) if (TREE_CODE (name) == SSA_NAME) r.intersect (gimple_range_global (name)); + if (m_resolve && r.varying_p ()) + improve_range_with_equivs (r, name); + set_cache (r, name); return true; } @@ -151,26 +201,37 @@ path_range_query::range_of_expr (irange &r, tree name, gimple *stmt) return false; } -bool -path_range_query::unreachable_path_p () -{ - return m_undefined_path; -} - -// Return the range of STMT at the end of the path being analyzed. +// Improve the range of NAME with the range of any of its equivalences. -bool -path_range_query::range_of_stmt (irange &r, gimple *stmt, tree) +void +path_range_query::improve_range_with_equivs (irange &r, tree name) { - tree type = gimple_range_type (stmt); + if (TREE_CODE (name) != SSA_NAME) + return; - if (!irange::supports_type_p (type)) - return false; + basic_block entry = entry_bb (); + relation_oracle *oracle = m_ranger.oracle (); - if (!fold_range (r, stmt, this)) - r.set_varying (type); + if (const bitmap_head *equivs = oracle->equiv_set (name, entry)) + { + int_range_max t; + bitmap_iterator bi; + unsigned i; + + EXECUTE_IF_SET_IN_BITMAP (equivs, 0, i, bi) + if (i != SSA_NAME_VERSION (name) && r.varying_p ()) + { + tree equiv = ssa_name (i); + range_on_path_entry (t, equiv); + r.intersect (t); + } + } +} - return true; +bool +path_range_query::unreachable_path_p () +{ + return m_undefined_path; } // Initialize the current path to PATH. The current block is set to @@ -196,10 +257,11 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi) tree name = gimple_phi_result (phi); basic_block bb = gimple_bb (phi); - // We experimented with querying ranger's range_on_entry here, but - // the performance penalty was too high, for hardly any improvements. if (at_entry ()) { + if (m_resolve && m_ranger.range_of_expr (r, name, phi)) + return; + // Try fold just in case we can resolve simple things like PHI <5(99), 6(88)>. if (!fold_range (r, phi, this)) r.set_varying (TREE_TYPE (name)); @@ -217,8 +279,20 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi) tree arg = gimple_phi_arg_def (phi, i); if (!get_cache (r, arg)) - r.set_varying (TREE_TYPE (name)); - + { + if (m_resolve) + { + int_range_max tmp; + // Using both the range on entry to the path, and the + // range on this edge yields significantly better + // results. + range_on_path_entry (r, arg); + m_ranger.range_on_edge (tmp, e_in, arg); + r.intersect (tmp); + return; + } + r.set_varying (TREE_TYPE (name)); + } return; } gcc_unreachable (); @@ -253,10 +327,6 @@ path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb) fprintf (dump_file, "\n"); } - // We may have an artificial statement not in the IL. - if (!bb && r.varying_p ()) - return false; - return true; } @@ -354,6 +424,71 @@ path_range_query::adjust_for_non_null_uses (basic_block bb) } } +// If NAME is a supported SSA_NAME, add it the bitmap in IMPORTS. + +bool +path_range_query::add_to_imports (tree name, bitmap imports) +{ + if (TREE_CODE (name) == SSA_NAME + && irange::supports_type_p (TREE_TYPE (name))) + return bitmap_set_bit (imports, SSA_NAME_VERSION (name)); + return false; +} + +// Add the copies of any SSA names in IMPORTS to IMPORTS. +// +// These are hints for the solver. Adding more elements (within +// reason) doesn't slow us down, because we don't solve anything that +// doesn't appear in the path. On the other hand, not having enough +// imports will limit what we can solve. + +void +path_range_query::add_copies_to_imports () +{ + auto_vec<tree> worklist (bitmap_count_bits (m_imports)); + bitmap_iterator bi; + unsigned i; + + EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi) + { + tree name = ssa_name (i); + worklist.quick_push (name); + } + + while (!worklist.is_empty ()) + { + tree name = worklist.pop (); + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + + if (is_gimple_assign (def_stmt)) + { + // ?? Adding assignment copies doesn't get us much. At the + // time of writing, we got 63 more threaded paths across the + // .ii files from a bootstrap. + add_to_imports (gimple_assign_rhs1 (def_stmt), m_imports); + tree rhs = gimple_assign_rhs2 (def_stmt); + if (rhs && add_to_imports (rhs, m_imports)) + worklist.safe_push (rhs); + rhs = gimple_assign_rhs3 (def_stmt); + if (rhs && add_to_imports (rhs, m_imports)) + worklist.safe_push (rhs); + } + else if (gphi *phi = dyn_cast <gphi *> (def_stmt)) + { + for (size_t i = 0; i < gimple_phi_num_args (phi); ++i) + { + edge e = gimple_phi_arg_edge (phi, i); + tree arg = gimple_phi_arg (phi, i)->def; + + if (TREE_CODE (arg) == SSA_NAME + && m_path->contains (e->src) + && bitmap_set_bit (m_imports, SSA_NAME_VERSION (arg))) + worklist.safe_push (arg); + } + } + } +} + // Precompute the ranges for IMPORTS along PATH. // // IMPORTS are the set of SSA names, any of which could potentially @@ -364,9 +499,16 @@ path_range_query::precompute_ranges (const vec<basic_block> &path, const bitmap_head *imports) { set_path (path); - m_imports = imports; + bitmap_copy (m_imports, imports); m_undefined_path = false; + if (m_resolve) + { + add_copies_to_imports (); + m_oracle->reset_path (); + precompute_relations (path); + } + if (DEBUG_SOLVER) { fprintf (dump_file, "\npath_range_query: precompute_ranges for path: "); @@ -384,6 +526,18 @@ path_range_query::precompute_ranges (const vec<basic_block> &path, { basic_block bb = curr_bb (); + if (m_resolve) + { + gori_compute &gori = m_ranger.gori (); + tree name; + + // Exported booleans along the path, may help conditionals. + // Add them as interesting imports. + FOR_EACH_GORI_EXPORT_NAME (gori, bb, name) + if (TREE_CODE (TREE_TYPE (name)) == BOOLEAN_TYPE) + bitmap_set_bit (m_imports, SSA_NAME_VERSION (name)); + } + precompute_ranges_in_block (bb); adjust_for_non_null_uses (bb); @@ -396,3 +550,178 @@ path_range_query::precompute_ranges (const vec<basic_block> &path, if (DEBUG_SOLVER) dump (dump_file); } + +// A folding aid used to register and query relations along a path. +// When queried, it returns relations as they would appear on exit to +// the path. +// +// Relations are registered on entry so the path_oracle knows which +// block to query the root oracle at when a relation lies outside the +// path. However, when queried we return the relation on exit to the +// path, since the root_oracle ignores the registered. + +class jt_fur_source : public fur_depend +{ +public: + jt_fur_source (gimple *s, path_range_query *, gori_compute *, + const vec<basic_block> &); + relation_kind query_relation (tree op1, tree op2) override; + void register_relation (gimple *, relation_kind, tree op1, tree op2) override; + void register_relation (edge, relation_kind, tree op1, tree op2) override; +private: + basic_block m_entry; +}; + +jt_fur_source::jt_fur_source (gimple *s, + path_range_query *query, + gori_compute *gori, + const vec<basic_block> &path) + : fur_depend (s, gori, query) +{ + gcc_checking_assert (!path.is_empty ()); + + m_entry = path[path.length () - 1]; + + if (dom_info_available_p (CDI_DOMINATORS)) + m_oracle = query->oracle (); + else + m_oracle = NULL; +} + +// Ignore statement and register relation on entry to path. + +void +jt_fur_source::register_relation (gimple *, relation_kind k, tree op1, tree op2) +{ + if (m_oracle) + m_oracle->register_relation (m_entry, k, op1, op2); +} + +// Ignore edge and register relation on entry to path. + +void +jt_fur_source::register_relation (edge, relation_kind k, tree op1, tree op2) +{ + if (m_oracle) + m_oracle->register_relation (m_entry, k, op1, op2); +} + +relation_kind +jt_fur_source::query_relation (tree op1, tree op2) +{ + if (!m_oracle) + return VREL_NONE; + + if (TREE_CODE (op1) != SSA_NAME || TREE_CODE (op2) != SSA_NAME) + return VREL_NONE; + + return m_oracle->query_relation (m_entry, op1, op2); +} + +// Return the range of STMT at the end of the path being analyzed. + +bool +path_range_query::range_of_stmt (irange &r, gimple *stmt, tree) +{ + tree type = gimple_range_type (stmt); + + if (!irange::supports_type_p (type)) + return false; + + // If resolving unknowns, fold the statement as it would have + // appeared at the end of the path. + if (m_resolve) + { + fold_using_range f; + jt_fur_source src (stmt, this, &m_ranger.gori (), *m_path); + if (!f.fold_stmt (r, stmt, src)) + r.set_varying (type); + } + // Otherwise, use the global ranger to fold it as it would appear in + // the original IL. This is more conservative, but faster. + else if (!fold_range (r, stmt, this)) + r.set_varying (type); + + return true; +} + +// Precompute relations on a path. This involves two parts: relations +// along the conditionals joining a path, and relations determined by +// examining PHIs. + +void +path_range_query::precompute_relations (const vec<basic_block> &path) +{ + if (!dom_info_available_p (CDI_DOMINATORS)) + return; + + jt_fur_source src (NULL, this, &m_ranger.gori (), path); + basic_block prev = NULL; + for (unsigned i = path.length (); i > 0; --i) + { + basic_block bb = path[i - 1]; + gimple *stmt = last_stmt (bb); + + precompute_phi_relations (bb, prev); + + // Compute relations in outgoing edges along the path. Skip the + // final conditional which we don't know yet. + if (i > 1 + && stmt + && gimple_code (stmt) == GIMPLE_COND + && irange::supports_type_p (TREE_TYPE (gimple_cond_lhs (stmt)))) + { + basic_block next = path[i - 2]; + int_range<2> r; + gcond *cond = as_a<gcond *> (stmt); + + if (EDGE_SUCC (bb, 0)->dest == next) + gcond_edge_range (r, EDGE_SUCC (bb, 0)); + else if (EDGE_SUCC (bb, 1)->dest == next) + gcond_edge_range (r, EDGE_SUCC (bb, 1)); + else + gcc_unreachable (); + + edge e0 = EDGE_SUCC (bb, 0); + edge e1 = EDGE_SUCC (bb, 1); + src.register_outgoing_edges (cond, r, e0, e1); + } + prev = bb; + } +} + +// Precompute relations for each PHI in BB. For example: +// +// x_5 = PHI<y_9(5),...> +// +// If the path flows through BB5, we can register that x_5 == y_9. + +void +path_range_query::precompute_phi_relations (basic_block bb, basic_block prev) +{ + if (prev == NULL) + return; + + basic_block entry = entry_bb (); + edge e_in = find_edge (prev, bb); + gcc_checking_assert (e_in); + + for (gphi_iterator iter = gsi_start_phis (bb); !gsi_end_p (iter); + gsi_next (&iter)) + { + gphi *phi = iter.phi (); + tree result = gimple_phi_result (phi); + unsigned nargs = gimple_phi_num_args (phi); + + for (size_t i = 0; i < nargs; ++i) + if (e_in == gimple_phi_arg_edge (phi, i)) + { + tree arg = gimple_phi_arg_def (phi, i); + + if (gimple_range_ssa_p (arg)) + m_oracle->register_relation (entry, EQ_EXPR, arg, result); + + break; + } + } +} diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h index c75721f..6f81f21 100644 --- a/gcc/gimple-range-path.h +++ b/gcc/gimple-range-path.h @@ -35,18 +35,21 @@ along with GCC; see the file COPYING3. If not see class path_range_query : public range_query { public: - path_range_query (class gimple_ranger &ranger); + path_range_query (class gimple_ranger &ranger, bool resolve); virtual ~path_range_query (); void precompute_ranges (const vec<basic_block> &path, const bitmap_head *imports); bool range_of_expr (irange &r, tree name, gimple * = NULL) override; bool range_of_stmt (irange &r, gimple *, tree name = NULL) override; bool unreachable_path_p (); + path_oracle *oracle () { return m_oracle; } void dump (FILE *) override; void debug (); private: bool internal_range_of_expr (irange &r, tree name, gimple *); + bool defined_outside_path (tree name); + void range_on_path_entry (irange &r, tree name); // Cache manipulation. void set_cache (const irange &r, tree name); @@ -58,6 +61,11 @@ private: void precompute_ranges_in_block (basic_block bb); void adjust_for_non_null_uses (basic_block bb); void ssa_range_in_phi (irange &r, gphi *phi); + void precompute_relations (const vec<basic_block> &); + void precompute_phi_relations (basic_block bb, basic_block prev); + void improve_range_with_equivs (irange &r, tree name); + void add_copies_to_imports (); + bool add_to_imports (tree name, bitmap imports); // Path navigation. void set_path (const vec<basic_block> &); @@ -79,12 +87,16 @@ private: // Path being analyzed. const vec<basic_block> *m_path; + auto_bitmap m_imports; + gimple_ranger &m_ranger; + non_null_ref m_non_null; + path_oracle *m_oracle; + // Current path position. unsigned m_pos; - const bitmap_head *m_imports; - gimple_ranger &m_ranger; - non_null_ref m_non_null; + // Use ranger to resolve anything not known on entry. + bool m_resolve; // Set if there were any undefined expressions while pre-calculating path. bool m_undefined_path; diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc index 5175d14..2417c21 100644 --- a/gcc/gimple-range-trace.cc +++ b/gcc/gimple-range-trace.cc @@ -176,7 +176,7 @@ push_dump_file::~push_dump_file () // Dump all that ranger knows for the current function. -DEBUG_FUNCTION void +void dump_ranger (FILE *out) { push_dump_file save (out, dump_flags); @@ -201,7 +201,7 @@ debug_ranger () // Note that the blocks are in reverse order, thus the exit block is // path[0]. -DEBUG_FUNCTION void +void dump_ranger (FILE *dump_file, const vec<basic_block> &path) { if (path.length () == 0) diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h index b9546a2..d3e69e0 100644 --- a/gcc/gimple-range-trace.h +++ b/gcc/gimple-range-trace.h @@ -72,4 +72,7 @@ private: dump_flags_t old_dump_flags; }; +void dump_ranger (FILE *); +void dump_ranger (FILE *, const vec<basic_block> &path); + #endif // GCC_GIMPLE_RANGE_TRACE_H diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index d74cea3..625d136 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "cfgloop.h" #include "tree-scalar-evolution.h" #include "gimple-range.h" +#include "domwalk.h" gimple_ranger::gimple_ranger () : tracer ("") { @@ -41,6 +42,7 @@ gimple_ranger::gimple_ranger () : tracer ("") m_oracle = m_cache.oracle (); if (dump_file && (param_evrp_mode & EVRP_MODE_TRACE)) tracer.enable_trace (); + set_all_edges_as_executable (cfun); } bool @@ -164,10 +166,6 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) int_range_max edge_range; gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name))); - // PHI arguments can be constants, catch these here. - if (!gimple_range_ssa_p (name)) - return range_of_expr (r, name); - unsigned idx; if ((idx = tracer.header ("range_on_edge ("))) { @@ -175,16 +173,32 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) 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))); + // Check to see if the edge is executable. + if ((e->flags & EDGE_EXECUTABLE) == 0) + { + r.set_undefined (); + if (idx) + tracer.trailer (idx, "range_on_edge [Unexecutable] ", true, + name, r); + return true; + } - // Check to see if NAME is defined on edge e. - if (m_cache.range_on_edge (edge_range, e, name)) - r.intersect (edge_range); + bool res = true; + if (!gimple_range_ssa_p (name)) + res = range_of_expr (r, name); + else + { + range_on_exit (r, e->src, name); + gcc_checking_assert (r.undefined_p () + || range_compatible_p (r.type(), TREE_TYPE (name))); + + // Check to see if NAME is defined on edge e. + 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); + tracer.trailer (idx, "range_on_edge", res, name, r); return true; } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index f680292..9163dcd 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -7369,6 +7369,18 @@ omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl, default_kind = kind; else if (VAR_P (decl) && TREE_STATIC (decl) && DECL_IN_CONSTANT_POOL (decl)) default_kind = OMP_CLAUSE_DEFAULT_SHARED; + /* For C/C++ default({,first}private), variables with static storage duration + declared in a namespace or global scope and referenced in construct + must be explicitly specified, i.e. acts as default(none). */ + else if ((default_kind == OMP_CLAUSE_DEFAULT_PRIVATE + || default_kind == OMP_CLAUSE_DEFAULT_FIRSTPRIVATE) + && VAR_P (decl) + && is_global_var (decl) + && (DECL_FILE_SCOPE_P (decl) + || (DECL_CONTEXT (decl) + && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)) + && !lang_GNU_Fortran ()) + default_kind = OMP_CLAUSE_DEFAULT_NONE; switch (default_kind) { diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e2abd5f..edfbe46 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -850235e4b974b9c5c2d7a1f9860583bd07f2a45c +e3bfc0889237a5bb8aa7ae30e1cff14f90a5f941 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/input.c b/gcc/input.c index 4b80986..dd753de 100644 --- a/gcc/input.c +++ b/gcc/input.c @@ -1437,6 +1437,11 @@ string_concat_db::record_string_concatenation (int num, location_t *locs) gcc_assert (locs); location_t key_loc = get_key_loc (locs[0]); + /* We don't record data for 'RESERVED_LOCATION_P (key_loc)' key values: + any data now recorded under key 'key_loc' would be overwritten by a + subsequent call with the same key 'key_loc'. */ + if (RESERVED_LOCATION_P (key_loc)) + return; string_concat *concat = new (ggc_alloc <string_concat> ()) string_concat (num, locs); @@ -1460,6 +1465,10 @@ string_concat_db::get_string_concatenation (location_t loc, gcc_assert (out_locs); location_t key_loc = get_key_loc (loc); + /* We don't record data for 'RESERVED_LOCATION_P (key_loc)' key values; see + discussion in 'string_concat_db::record_string_concatenation'. */ + if (RESERVED_LOCATION_P (key_loc)) + return false; string_concat **concat = m_table->get (key_loc); if (!concat) diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 2470937..3119991 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -4652,7 +4652,6 @@ ipa_fn_summary_write (void) info->time.stream_out (ob); bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, info->inlinable, 1); - bp_pack_value (&bp, false, 1); bp_pack_value (&bp, info->fp_expressions, 1); streamer_write_bitpack (&bp); streamer_write_uhwi (ob, vec_safe_length (info->conds)); diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c index a56080b..4d73454 100644 --- a/gcc/lra-constraints.c +++ b/gcc/lra-constraints.c @@ -1276,7 +1276,7 @@ check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED) sclass = dclass = NO_REGS; if (REG_P (dreg)) dclass = get_reg_class (REGNO (dreg)); - gcc_assert (dclass < LIM_REG_CLASSES); + gcc_assert (dclass < LIM_REG_CLASSES && dclass >= NO_REGS); if (dclass == ALL_REGS) /* ALL_REGS is used for new pseudos created by transformations like reload of SUBREG_REG (see function @@ -1288,7 +1288,7 @@ check_and_process_move (bool *change_p, bool *sec_mem_p ATTRIBUTE_UNUSED) return false; if (REG_P (sreg)) sclass = get_reg_class (REGNO (sreg)); - gcc_assert (sclass < LIM_REG_CLASSES); + gcc_assert (sclass < LIM_REG_CLASSES && sclass >= NO_REGS); if (sclass == ALL_REGS) /* See comments above. */ return false; diff --git a/gcc/match.pd b/gcc/match.pd index 097ed2e..a063a15 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4482,9 +4482,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) /* a CMP (-0) -> a CMP 0 */ (if (REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@1))) (cmp @0 { build_real (TREE_TYPE (@1), dconst0); })) + /* (-0) CMP b -> 0 CMP b. */ + (if (TREE_CODE (@0) == REAL_CST + && REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (@0))) + (cmp { build_real (TREE_TYPE (@0), dconst0); } @1)) /* x != NaN is always true, other ops are always false. */ (if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1)) - && ! HONOR_SNANS (@1)) + && !tree_expr_signaling_nan_p (@1) + && !tree_expr_maybe_signaling_nan_p (@0)) + { constant_boolean_node (cmp == NE_EXPR, type); }) + /* NaN != y is always true, other ops are always false. */ + (if (TREE_CODE (@0) == REAL_CST + && REAL_VALUE_ISNAN (TREE_REAL_CST (@0)) + && !tree_expr_signaling_nan_p (@0) + && !tree_expr_signaling_nan_p (@1)) { constant_boolean_node (cmp == NE_EXPR, type); }) /* Fold comparisons against infinity. */ (if (REAL_VALUE_ISINF (TREE_REAL_CST (@1)) diff --git a/gcc/omp-oacc-neuter-broadcast.cc b/gcc/omp-oacc-neuter-broadcast.cc index d48627a..e43338f 100644 --- a/gcc/omp-oacc-neuter-broadcast.cc +++ b/gcc/omp-oacc-neuter-broadcast.cc @@ -53,6 +53,8 @@ #include "tree-cfg.h" #include "omp-offload.h" #include "attribs.h" +#include "targhooks.h" +#include "diagnostic-core.h" /* Loop structure of the function. The entire function is described as a NULL loop. */ @@ -767,16 +769,19 @@ static void find_local_vars_to_propagate (parallel_g *par, unsigned outer_mask, hash_set<tree> *partitioned_var_uses, hash_set<tree> *gang_private_vars, + bitmap writes_gang_private, vec<propagation_set *> *prop_set) { unsigned mask = outer_mask | par->mask; if (par->inner) find_local_vars_to_propagate (par->inner, mask, partitioned_var_uses, - gang_private_vars, prop_set); + gang_private_vars, writes_gang_private, + prop_set); if (par->next) find_local_vars_to_propagate (par->next, outer_mask, partitioned_var_uses, - gang_private_vars, prop_set); + gang_private_vars, writes_gang_private, + prop_set); if (!(mask & GOMP_DIM_MASK (GOMP_DIM_WORKER))) { @@ -797,8 +802,7 @@ find_local_vars_to_propagate (parallel_g *par, unsigned outer_mask, if (!VAR_P (var) || is_global_var (var) || AGGREGATE_TYPE_P (TREE_TYPE (var)) - || !partitioned_var_uses->contains (var) - || gang_private_vars->contains (var)) + || !partitioned_var_uses->contains (var)) continue; if (stmt_may_clobber_ref_p (stmt, var)) @@ -812,6 +816,14 @@ find_local_vars_to_propagate (parallel_g *par, unsigned outer_mask, fprintf (dump_file, "\n"); } + if (gang_private_vars->contains (var)) + { + /* If we write a gang-private variable, we want a + barrier at the end of the block. */ + bitmap_set_bit (writes_gang_private, block->index); + continue; + } + if (!(*prop_set)[block->index]) (*prop_set)[block->index] = new propagation_set; @@ -923,14 +935,6 @@ worker_single_simple (basic_block from, basic_block to, } } } - - gsi = gsi_start_bb (skip_block); - - decl = builtin_decl_explicit (BUILT_IN_GOACC_BARRIER); - gimple *acc_bar = gimple_build_call (decl, 0); - - gsi_insert_before (&gsi, acc_bar, GSI_SAME_STMT); - update_stmt (acc_bar); } /* Build COMPONENT_REF and set TREE_THIS_VOLATILE and TREE_READONLY on it @@ -968,6 +972,8 @@ build_receiver_ref (tree var, tree receiver_decl, field_map_t *fields) static tree build_sender_ref (tree var, tree sender_decl, field_map_t *fields) { + if (POINTER_TYPE_P (TREE_TYPE (sender_decl))) + sender_decl = build_simple_mem_ref (sender_decl); tree field = *fields->get (var); return oacc_build_component_ref (sender_decl, field); } @@ -1005,7 +1011,9 @@ 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, record_field_map_t *record_field_map) + tree record_type, record_field_map_t *record_field_map, + unsigned HOST_WIDE_INT placement, + bool isolate_broadcasts, bool has_gang_private_write) { /* 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 @@ -1016,10 +1024,12 @@ worker_single_copy (basic_block from, basic_block to, tree sender_decl = targetm.goacc.create_worker_broadcast_record (record_type, true, - ".oacc_worker_o"); + ".oacc_worker_o", + placement); tree receiver_decl = targetm.goacc.create_worker_broadcast_record (record_type, false, - ".oacc_worker_i"); + ".oacc_worker_i", + placement); gimple_stmt_iterator gsi = gsi_last_bb (to); if (EDGE_COUNT (to->succs) > 1) @@ -1033,12 +1043,23 @@ worker_single_copy (basic_block from, basic_block to, tree lhs = create_tmp_var (TREE_TYPE (TREE_TYPE (decl))); - gimple *call = gimple_build_call (decl, 1, - build_fold_addr_expr (sender_decl)); + gimple *call + = gimple_build_call (decl, 1, + POINTER_TYPE_P (TREE_TYPE (sender_decl)) + ? sender_decl : build_fold_addr_expr (sender_decl)); gimple_call_set_lhs (call, lhs); gsi_insert_before (&start, call, GSI_NEW_STMT); update_stmt (call); + /* The shared-memory range for this block overflowed. Add a barrier before + the GOACC_single_copy_start call. */ + if (isolate_broadcasts) + { + decl = builtin_decl_explicit (BUILT_IN_GOACC_BARRIER); + gimple *acc_bar = gimple_build_call (decl, 0); + gsi_insert_before (&start, acc_bar, GSI_SAME_STMT); + } + tree conv_tmp = make_ssa_name (TREE_TYPE (receiver_decl)); gimple *conv = gimple_build_assign (conv_tmp, @@ -1075,14 +1096,19 @@ worker_single_copy (basic_block from, basic_block to, edge ef = make_edge (from, barrier_block, EDGE_FALSE_VALUE); ef->probability = et->probability.invert (); - decl = builtin_decl_explicit (BUILT_IN_GOACC_BARRIER); - gimple *acc_bar = gimple_build_call (decl, 0); - gimple_stmt_iterator bar_gsi = gsi_start_bb (barrier_block); - gsi_insert_before (&bar_gsi, acc_bar, GSI_NEW_STMT); - cond = gimple_build_cond (NE_EXPR, recv_tmp, zero_ptr, NULL_TREE, NULL_TREE); - gsi_insert_after (&bar_gsi, cond, GSI_NEW_STMT); + + if (record_type != char_type_node || has_gang_private_write) + { + decl = builtin_decl_explicit (BUILT_IN_GOACC_BARRIER); + gimple *acc_bar = gimple_build_call (decl, 0); + + gsi_insert_before (&bar_gsi, acc_bar, GSI_NEW_STMT); + gsi_insert_after (&bar_gsi, cond, GSI_NEW_STMT); + } + else + gsi_insert_before (&bar_gsi, cond, GSI_NEW_STMT); edge et2 = split_block (barrier_block, cond); et2->flags &= ~EDGE_FALLTHRU; @@ -1206,13 +1232,26 @@ worker_single_copy (basic_block from, basic_block to, } } + /* The shared-memory range for this block overflowed. Add a barrier at the + end. */ + if (isolate_broadcasts) + { + gsi = gsi_start_bb (exit_block); + decl = builtin_decl_explicit (BUILT_IN_GOACC_BARRIER); + gimple *acc_bar = gimple_build_call (decl, 0); + gsi_insert_before (&gsi, acc_bar, GSI_SAME_STMT); + } + /* It's possible for the ET->DEST block (the work done by the active thread) to finish with a control-flow insn, e.g. a UNIQUE function call. Split the block and add SENDER_SEQ in the latter part to avoid having control flow in the middle of a BB. */ decl = builtin_decl_explicit (BUILT_IN_GOACC_SINGLE_COPY_END); - call = gimple_build_call (decl, 1, build_fold_addr_expr (sender_decl)); + call = gimple_build_call (decl, 1, + POINTER_TYPE_P (TREE_TYPE (sender_decl)) + ? sender_decl + : build_fold_addr_expr (sender_decl)); gimple_seq_add_stmt (&sender_seq, call); gsi = gsi_last_bb (body); @@ -1222,12 +1261,17 @@ worker_single_copy (basic_block from, basic_block to, gsi_insert_seq_after (&gsi, sender_seq, GSI_CONTINUE_LINKING); } +typedef hash_map<basic_block, std::pair<unsigned HOST_WIDE_INT, bool> > + blk_offset_map_t; + 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, - record_field_map_t *record_field_map) + record_field_map_t *record_field_map, + blk_offset_map_t *blk_offset_map, + bitmap writes_gang_private) { unsigned mask = outer_mask | par->mask; @@ -1313,12 +1357,72 @@ neuter_worker_single (parallel_g *par, unsigned outer_mask, (*prop_set)[block->index] = 0; } - tree record_type = (tree) block->aux; + bool only_marker_fns = true; + bool join_block = false; + + for (gimple_stmt_iterator gsi = gsi_start_bb (block); + !gsi_end_p (gsi); + gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + if (gimple_code (stmt) == GIMPLE_CALL + && gimple_call_internal_p (stmt, IFN_UNIQUE)) + { + enum ifn_unique_kind k = ((enum ifn_unique_kind) + TREE_INT_CST_LOW (gimple_call_arg (stmt, 0))); + if (k != IFN_UNIQUE_OACC_PRIVATE + && k != IFN_UNIQUE_OACC_JOIN + && k != IFN_UNIQUE_OACC_FORK + && k != IFN_UNIQUE_OACC_HEAD_MARK + && k != IFN_UNIQUE_OACC_TAIL_MARK) + only_marker_fns = false; + else if (k == IFN_UNIQUE_OACC_JOIN) + /* The JOIN marker is special in that it *cannot* be + predicated for worker zero, because it may be lowered + to a barrier instruction and all workers must typically + execute that barrier. We shouldn't be doing any + broadcasts from the join block anyway. */ + join_block = true; + } + else if (gimple_code (stmt) == GIMPLE_CALL + && gimple_call_internal_p (stmt, IFN_GOACC_LOOP)) + /* Empty. */; + else if (gimple_nop_p (stmt)) + /* Empty. */; + else + only_marker_fns = false; + } + + /* We can skip predicating this block for worker zero if the only + thing it contains is marker functions that will be removed in the + oaccdevlow pass anyway. + Don't do this if the block has (any) phi nodes, because those + might define SSA names that need broadcasting. + TODO: We might be able to skip transforming blocks that only + contain some other trivial statements too. */ + if (only_marker_fns && !phi_nodes (block)) + continue; + + gcc_assert (!join_block); if (has_defs) - worker_single_copy (block, block, &def_escapes_block, - &worker_partitioned_uses, record_type, - record_field_map); + { + tree record_type = (tree) block->aux; + std::pair<unsigned HOST_WIDE_INT, bool> *off_rngalloc + = blk_offset_map->get (block); + gcc_assert (!record_type || off_rngalloc); + unsigned HOST_WIDE_INT offset + = off_rngalloc ? off_rngalloc->first : 0; + bool range_allocated + = off_rngalloc ? off_rngalloc->second : true; + bool has_gang_private_write + = bitmap_bit_p (writes_gang_private, block->index); + worker_single_copy (block, block, &def_escapes_block, + &worker_partitioned_uses, record_type, + record_field_map, + offset, !range_allocated, + has_gang_private_write); + } else worker_single_simple (block, block, &def_escapes_block); } @@ -1354,14 +1458,159 @@ 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, record_field_map); + prop_set, partitioned_var_uses, record_field_map, + blk_offset_map, writes_gang_private); if (par->next) neuter_worker_single (par->next, outer_mask, worker_single, vector_single, - prop_set, partitioned_var_uses, record_field_map); + prop_set, partitioned_var_uses, record_field_map, + blk_offset_map, writes_gang_private); +} + +static void +dfs_broadcast_reachable_1 (basic_block bb, sbitmap reachable) +{ + if (bb->flags & BB_VISITED) + return; + + bb->flags |= BB_VISITED; + + if (bb->succs) + { + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->succs) + { + basic_block dest = e->dest; + if (dest->aux) + bitmap_set_bit (reachable, dest->index); + else + dfs_broadcast_reachable_1 (dest, reachable); + } + } +} + +typedef std::pair<int, tree> idx_decl_pair_t; + +typedef auto_vec<splay_tree> used_range_vec_t; + +static int +sort_size_descending (const void *a, const void *b) +{ + const idx_decl_pair_t *pa = (const idx_decl_pair_t *) a; + const idx_decl_pair_t *pb = (const idx_decl_pair_t *) b; + unsigned HOST_WIDE_INT asize = tree_to_uhwi (TYPE_SIZE_UNIT (pa->second)); + unsigned HOST_WIDE_INT bsize = tree_to_uhwi (TYPE_SIZE_UNIT (pb->second)); + return bsize - asize; } +class addr_range +{ +public: + addr_range (unsigned HOST_WIDE_INT addr_lo, unsigned HOST_WIDE_INT addr_hi) + : lo (addr_lo), hi (addr_hi) + { } + addr_range (const addr_range &ar) : lo (ar.lo), hi (ar.hi) + { } + addr_range () : lo (0), hi (0) + { } + + bool invalid () { return lo == 0 && hi == 0; } + + unsigned HOST_WIDE_INT lo; + unsigned HOST_WIDE_INT hi; +}; + static int -execute_omp_oacc_neuter_broadcast () +splay_tree_compare_addr_range (splay_tree_key a, splay_tree_key b) +{ + addr_range *ar = (addr_range *) a; + addr_range *br = (addr_range *) b; + if (ar->lo == br->lo && ar->hi == br->hi) + return 0; + if (ar->hi <= br->lo) + return -1; + else if (ar->lo >= br->hi) + return 1; + return 0; +} + +static void +splay_tree_free_key (splay_tree_key k) +{ + addr_range *ar = (addr_range *) k; + delete ar; +} + +static addr_range +first_fit_range (splay_tree s, unsigned HOST_WIDE_INT size, + unsigned HOST_WIDE_INT align, addr_range *bounds) +{ + splay_tree_node min = splay_tree_min (s); + if (min) + { + splay_tree_node next; + while ((next = splay_tree_successor (s, min->key))) + { + unsigned HOST_WIDE_INT lo = ((addr_range *) min->key)->hi; + unsigned HOST_WIDE_INT hi = ((addr_range *) next->key)->lo; + unsigned HOST_WIDE_INT base = (lo + align - 1) & ~(align - 1); + if (base + size <= hi) + return addr_range (base, base + size); + min = next; + } + + unsigned HOST_WIDE_INT base = ((addr_range *)min->key)->hi; + base = (base + align - 1) & ~(align - 1); + if (base + size <= bounds->hi) + return addr_range (base, base + size); + else + return addr_range (); + } + else + { + unsigned HOST_WIDE_INT lo = bounds->lo; + lo = (lo + align - 1) & ~(align - 1); + if (lo + size <= bounds->hi) + return addr_range (lo, lo + size); + else + return addr_range (); + } +} + +static int +merge_ranges_1 (splay_tree_node n, void *ptr) +{ + splay_tree accum = (splay_tree) ptr; + addr_range ar = *(addr_range *) n->key; + + splay_tree_node old = splay_tree_lookup (accum, n->key); + + /* We might have an overlap. Create a new range covering the + overlapping parts. */ + if (old) + { + addr_range *old_ar = (addr_range *) old->key; + ar.lo = MIN (old_ar->lo, ar.lo); + ar.hi = MAX (old_ar->hi, ar.hi); + splay_tree_remove (accum, old->key); + } + + addr_range *new_ar = new addr_range (ar); + + splay_tree_insert (accum, (splay_tree_key) new_ar, n->value); + + return 0; +} + +static void +merge_ranges (splay_tree accum, splay_tree sp) +{ + splay_tree_foreach (sp, merge_ranges_1, (void *) accum); +} + +static void +oacc_do_neutering (unsigned HOST_WIDE_INT bounds_lo, + unsigned HOST_WIDE_INT bounds_hi) { bb_stmt_map_t bb_stmt_map; auto_bitmap worker_single, vector_single; @@ -1378,18 +1627,17 @@ execute_omp_oacc_neuter_broadcast () /* If this is a routine, calculate MASK as if the outer levels are already partitioned. */ - tree attr = oacc_get_fn_attrib (current_function_decl); - if (attr) - { - tree dims = TREE_VALUE (attr); - unsigned ix; - for (ix = 0; ix != GOMP_DIM_MAX; ix++, dims = TREE_CHAIN (dims)) - { - tree allowed = TREE_PURPOSE (dims); - if (allowed && integer_zerop (allowed)) - mask |= GOMP_DIM_MASK (ix); - } - } + { + tree attr = oacc_get_fn_attrib (current_function_decl); + tree dims = TREE_VALUE (attr); + unsigned ix; + for (ix = 0; ix != GOMP_DIM_MAX; ix++, dims = TREE_CHAIN (dims)) + { + tree allowed = TREE_PURPOSE (dims); + if (allowed && integer_zerop (allowed)) + mask |= GOMP_DIM_MASK (ix); + } + } parallel_g *par = omp_sese_discover_pars (&bb_stmt_map); populate_single_mode_bitmaps (par, worker_single, vector_single, mask, 0); @@ -1406,11 +1654,13 @@ execute_omp_oacc_neuter_broadcast () hash_set<tree> partitioned_var_uses; hash_set<tree> gang_private_vars; + auto_bitmap writes_gang_private; find_gang_private_vars (&gang_private_vars); find_partitioned_var_uses (par, mask, &partitioned_var_uses); find_local_vars_to_propagate (par, mask, &partitioned_var_uses, - &gang_private_vars, &prop_set); + &gang_private_vars, writes_gang_private, + &prop_set); record_field_map_t record_field_map; @@ -1451,8 +1701,122 @@ execute_omp_oacc_neuter_broadcast () } } + sbitmap *reachable + = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), + last_basic_block_for_fn (cfun)); + + bitmap_vector_clear (reachable, last_basic_block_for_fn (cfun)); + + auto_vec<std::pair<int, tree> > priority; + + FOR_ALL_BB_FN (bb, cfun) + { + if (bb->aux) + { + tree record_type = (tree) bb->aux; + + basic_block bb2; + FOR_ALL_BB_FN (bb2, cfun) + bb2->flags &= ~BB_VISITED; + + priority.safe_push (std::make_pair (bb->index, record_type)); + dfs_broadcast_reachable_1 (bb, reachable[bb->index]); + } + } + + sbitmap *inverted + = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), + last_basic_block_for_fn (cfun)); + + bitmap_vector_clear (inverted, last_basic_block_for_fn (cfun)); + + for (int i = 0; i < last_basic_block_for_fn (cfun); i++) + { + sbitmap_iterator bi; + unsigned int j; + EXECUTE_IF_SET_IN_BITMAP (reachable[i], 0, j, bi) + bitmap_set_bit (inverted[j], i); + } + + for (int i = 0; i < last_basic_block_for_fn (cfun); i++) + bitmap_ior (reachable[i], reachable[i], inverted[i]); + + sbitmap_vector_free (inverted); + + used_range_vec_t used_ranges; + + used_ranges.safe_grow_cleared (last_basic_block_for_fn (cfun)); + + blk_offset_map_t blk_offset_map; + + addr_range worker_shm_bounds (bounds_lo, bounds_hi); + + priority.qsort (sort_size_descending); + for (unsigned int i = 0; i < priority.length (); i++) + { + idx_decl_pair_t p = priority[i]; + int blkno = p.first; + tree record_type = p.second; + HOST_WIDE_INT size = tree_to_uhwi (TYPE_SIZE_UNIT (record_type)); + HOST_WIDE_INT align = TYPE_ALIGN_UNIT (record_type); + + splay_tree conflicts = splay_tree_new (splay_tree_compare_addr_range, + splay_tree_free_key, NULL); + + if (!used_ranges[blkno]) + used_ranges[blkno] = splay_tree_new (splay_tree_compare_addr_range, + splay_tree_free_key, NULL); + else + merge_ranges (conflicts, used_ranges[blkno]); + + sbitmap_iterator bi; + unsigned int j; + EXECUTE_IF_SET_IN_BITMAP (reachable[blkno], 0, j, bi) + if (used_ranges[j]) + merge_ranges (conflicts, used_ranges[j]); + + addr_range ar + = first_fit_range (conflicts, size, align, &worker_shm_bounds); + + splay_tree_delete (conflicts); + + if (ar.invalid ()) + { + unsigned HOST_WIDE_INT base + = (bounds_lo + align - 1) & ~(align - 1); + if (base + size > bounds_hi) + error_at (UNKNOWN_LOCATION, "shared-memory region overflow"); + std::pair<unsigned HOST_WIDE_INT, bool> base_inrng + = std::make_pair (base, false); + blk_offset_map.put (BASIC_BLOCK_FOR_FN (cfun, blkno), base_inrng); + } + else + { + splay_tree_node old = splay_tree_lookup (used_ranges[blkno], + (splay_tree_key) &ar); + if (old) + { + fprintf (stderr, "trying to map [%d..%d] but [%d..%d] is " + "already mapped in block %d\n", (int) ar.lo, + (int) ar.hi, (int) ((addr_range *) old->key)->lo, + (int) ((addr_range *) old->key)->hi, blkno); + abort (); + } + + addr_range *arp = new addr_range (ar); + splay_tree_insert (used_ranges[blkno], (splay_tree_key) arp, + (splay_tree_value) blkno); + std::pair<unsigned HOST_WIDE_INT, bool> base_inrng + = std::make_pair (ar.lo, true); + blk_offset_map.put (BASIC_BLOCK_FOR_FN (cfun, blkno), base_inrng); + } + } + + sbitmap_vector_free (reachable); + neuter_worker_single (par, mask, worker_single, vector_single, &prop_set, - &partitioned_var_uses, &record_field_map); + &partitioned_var_uses, &record_field_map, + &blk_offset_map, writes_gang_private); for (auto it : record_field_map) delete it.second; @@ -1479,6 +1843,107 @@ execute_omp_oacc_neuter_broadcast () fprintf (dump_file, "\n\nAfter neutering:\n\n"); dump_function_to_file (current_function_decl, dump_file, dump_flags); } +} + +static int +execute_omp_oacc_neuter_broadcast () +{ + unsigned HOST_WIDE_INT reduction_size[GOMP_DIM_MAX]; + unsigned HOST_WIDE_INT private_size[GOMP_DIM_MAX]; + + for (unsigned i = 0; i < GOMP_DIM_MAX; i++) + { + reduction_size[i] = 0; + private_size[i] = 0; + } + + /* Calculate shared memory size required for reduction variables and + gang-private memory for this offloaded function. */ + basic_block bb; + FOR_ALL_BB_FN (bb, cfun) + { + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); + !gsi_end_p (gsi); + gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + if (!is_gimple_call (stmt)) + continue; + gcall *call = as_a <gcall *> (stmt); + if (!gimple_call_internal_p (call)) + continue; + enum internal_fn ifn_code = gimple_call_internal_fn (call); + switch (ifn_code) + { + default: break; + case IFN_GOACC_REDUCTION: + if (integer_minus_onep (gimple_call_arg (call, 3))) + continue; + else + { + unsigned code = TREE_INT_CST_LOW (gimple_call_arg (call, 0)); + /* Only count reduction variables once: the choice to pick + the setup call is fairly arbitrary. */ + if (code == IFN_GOACC_REDUCTION_SETUP) + { + int level = TREE_INT_CST_LOW (gimple_call_arg (call, 3)); + tree var = gimple_call_arg (call, 2); + tree offset = gimple_call_arg (call, 5); + tree var_type = TREE_TYPE (var); + unsigned HOST_WIDE_INT limit + = (tree_to_uhwi (offset) + + tree_to_uhwi (TYPE_SIZE_UNIT (var_type))); + reduction_size[level] + = MAX (reduction_size[level], limit); + } + } + break; + case IFN_UNIQUE: + { + enum ifn_unique_kind kind + = ((enum ifn_unique_kind) + TREE_INT_CST_LOW (gimple_call_arg (call, 0))); + + if (kind == IFN_UNIQUE_OACC_PRIVATE) + { + HOST_WIDE_INT level + = TREE_INT_CST_LOW (gimple_call_arg (call, 2)); + if (level == -1) + break; + for (unsigned i = 3; + i < gimple_call_num_args (call); + i++) + { + tree arg = gimple_call_arg (call, i); + gcc_assert (TREE_CODE (arg) == ADDR_EXPR); + tree decl = TREE_OPERAND (arg, 0); + unsigned HOST_WIDE_INT align = DECL_ALIGN_UNIT (decl); + private_size[level] = ((private_size[level] + align - 1) + & ~(align - 1)); + unsigned HOST_WIDE_INT decl_size + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (decl))); + private_size[level] += decl_size; + } + } + } + break; + } + } + } + + int dims[GOMP_DIM_MAX]; + for (unsigned i = 0; i < GOMP_DIM_MAX; i++) + dims[i] = oacc_get_fn_dim_size (current_function_decl, i); + + /* Find bounds of shared-memory buffer space we can use. */ + unsigned HOST_WIDE_INT bounds_lo = 0, bounds_hi = 0; + if (targetm.goacc.shared_mem_layout) + targetm.goacc.shared_mem_layout (&bounds_lo, &bounds_hi, dims, + private_size, reduction_size); + + /* Perform worker partitioning unless we know 'num_workers(1)'. */ + if (dims[GOMP_DIM_WORKER] != 1) + oacc_do_neutering (bounds_lo, bounds_hi); return 0; } @@ -1506,11 +1971,21 @@ public: {} /* opt_pass methods: */ - virtual bool gate (function *) + virtual bool gate (function *fun) { - return (flag_openacc - && targetm.goacc.create_worker_broadcast_record); - }; + if (!flag_openacc) + return false; + + if (!targetm.goacc.create_worker_broadcast_record) + return false; + + /* Only relevant for OpenACC offloaded functions. */ + tree attr = oacc_get_fn_attrib (fun->decl); + if (!attr) + return false; + + return true; + } virtual unsigned int execute (function *) { diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index 4ad2879..83b1f0f 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -1087,6 +1087,34 @@ access_ref::inform_access (access_mode mode) const else if (gimple_nop_p (stmt)) /* Handle DECL_PARM below. */ ref = SSA_NAME_VAR (ref); + else if (is_gimple_assign (stmt) + && (gimple_assign_rhs_code (stmt) == MIN_EXPR + || gimple_assign_rhs_code (stmt) == MAX_EXPR)) + { + /* MIN or MAX_EXPR here implies a reference to a known object + and either an unknown or distinct one (the latter being + the result of an invalid relational expression). Determine + the identity of the former and point to it in the note. + TODO: Consider merging with PHI handling. */ + access_ref arg_ref[2]; + tree arg = gimple_assign_rhs1 (stmt); + compute_objsize (arg, /* ostype = */ 1 , &arg_ref[0]); + arg = gimple_assign_rhs2 (stmt); + compute_objsize (arg, /* ostype = */ 1 , &arg_ref[1]); + + /* Use the argument that references a known object with more + space remaining. */ + const bool idx + = (!arg_ref[0].ref || !arg_ref[0].base0 + || (arg_ref[0].base0 && arg_ref[1].base0 + && (arg_ref[0].size_remaining () + < arg_ref[1].size_remaining ()))); + + arg_ref[idx].offrng[0] = offrng[0]; + arg_ref[idx].offrng[1] = offrng[1]; + arg_ref[idx].inform_access (mode); + return; + } } if (DECL_P (ref)) @@ -1463,15 +1491,18 @@ pointer_query::dump (FILE *dump_file, bool contents /* = false */) } /* A helper of compute_objsize_r() to determine the size from an assignment - statement STMT with the RHS of either MIN_EXPR or MAX_EXPR. */ + statement STMT with the RHS of either MIN_EXPR or MAX_EXPR. On success + set PREF->REF to the operand with more or less space remaining, + respectively, if both refer to the same (sub)object, or to PTR if they + might not, and return true. Otherwise, if the identity of neither + operand can be determined, return false. */ static bool -handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, +handle_min_max_size (tree ptr, int ostype, access_ref *pref, ssa_name_limit_t &snlim, pointer_query *qry) { - tree_code code = gimple_assign_rhs_code (stmt); - - tree ptr = gimple_assign_rhs1 (stmt); + const gimple *stmt = SSA_NAME_DEF_STMT (ptr); + const tree_code code = gimple_assign_rhs_code (stmt); /* In a valid MAX_/MIN_EXPR both operands must refer to the same array. Determine the size/offset of each and use the one with more or less @@ -1479,7 +1510,8 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, determined from the other instead, adjusted up or down as appropriate for the expression. */ access_ref aref[2] = { *pref, *pref }; - if (!compute_objsize_r (ptr, ostype, &aref[0], snlim, qry)) + tree arg1 = gimple_assign_rhs1 (stmt); + if (!compute_objsize_r (arg1, ostype, &aref[0], snlim, qry)) { aref[0].base0 = false; aref[0].offrng[0] = aref[0].offrng[1] = 0; @@ -1487,8 +1519,8 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, aref[0].set_max_size_range (); } - ptr = gimple_assign_rhs2 (stmt); - if (!compute_objsize_r (ptr, ostype, &aref[1], snlim, qry)) + tree arg2 = gimple_assign_rhs2 (stmt); + if (!compute_objsize_r (arg2, ostype, &aref[1], snlim, qry)) { aref[1].base0 = false; aref[1].offrng[0] = aref[1].offrng[1] = 0; @@ -1517,6 +1549,13 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, *pref = aref[i1]; else *pref = aref[i0]; + + if (aref[i0].ref != aref[i1].ref) + /* If the operands don't refer to the same (sub)object set + PREF->REF to the SSA_NAME from which STMT was obtained + so that both can be identified in a diagnostic. */ + pref->ref = ptr; + return true; } @@ -1537,6 +1576,10 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, pref->offrng[0] = aref[i0].offrng[0]; pref->offrng[1] = aref[i0].offrng[1]; } + + /* Replace PTR->REF with the SSA_NAME to indicate the expression + might not refer to the same (sub)object. */ + pref->ref = ptr; return true; } @@ -2009,8 +2052,9 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref, if (code == MAX_EXPR || code == MIN_EXPR) { - if (!handle_min_max_size (stmt, ostype, pref, snlim, qry)) + if (!handle_min_max_size (ptr, ostype, pref, snlim, qry)) return false; + qry->put_ref (ptr, *pref); return true; } diff --git a/gcc/target.def b/gcc/target.def index bfa8196..c5d90ca 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -1764,7 +1764,17 @@ of REC to place the new variable in shared GPU memory.\n\ \n\ Presence of this target hook indicates that middle end neutering/broadcasting\n\ be used.", -tree, (tree rec, bool sender, const char *name), +tree, (tree rec, bool sender, const char *name, unsigned HOST_WIDE_INT offset), +NULL) + +DEFHOOK +(shared_mem_layout, +"Lay out a fixed shared-memory region on the target. The LO and HI\n\ +arguments should be set to a range of addresses that can be used for worker\n\ +broadcasting. The dimensions, reduction size and gang-private size\n\ +arguments are for the current offload region.", +void, (unsigned HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, int[], + unsigned HOST_WIDE_INT[], unsigned HOST_WIDE_INT[]), NULL) HOOK_VECTOR_END (goacc) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1c8d4ba..aca4514 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,426 @@ +2021-09-20 Andrew MacLeod <amacleod@redhat.com> + + * gcc.dg/tree-ssa/evrp-ignore.c: New. + +2021-09-20 Matthias Kretz <m.kretz@gsi.de> + + * gcc.dg/associative-math-1.c: New test. + * gcc.dg/associative-math-2.c: New test. + * gcc.dg/no-signed-zeros-1.c: New test. + * gcc.dg/no-signed-zeros-2.c: New test. + * gcc.dg/no-trapping-math-1.c: New test. + * gcc.dg/no-trapping-math-2.c: New test. + * gcc.dg/reciprocal-math-1.c: New test. + * gcc.dg/reciprocal-math-2.c: New test. + * gcc.dg/rounding-math-1.c: New test. + * gcc.dg/rounding-math-2.c: New test. + +2021-09-20 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.dg/gomp/order-5.f90: New test. + * gfortran.dg/gomp/order-6.f90: New test. + * gfortran.dg/gomp/order-7.f90: New test. + * gfortran.dg/gomp/order-8.f90: New test. + * gfortran.dg/gomp/order-9.f90: New test. + +2021-09-20 Christophe Lyon <christophe.lyon@foss.st.com> + Torbjörn SVENSSON <torbjorn.svensson@st.com> + + * lib/prune.exp (prune_gcc_output): Remove .exe suffix from + toolchain executables names. + +2021-09-20 Thomas Schwinge <thomas@codesourcery.com> + + * gcc.dg/plugin/diagnostic-test-string-literals-1.c: Adjust + expected error diagnostics. + +2021-09-20 Richard Biener <rguenther@suse.de> + + PR tree-optimization/65206 + * gcc.dg/torture/20210916.c: New testcase. + * gcc.dg/vect/pr65206.c: Likewise. + +2021-09-19 Martin Sebor <msebor@redhat.com> + + PR middle-end/102403 + * gcc.dg/uninit-pr102403.c: New test. + * gcc.dg/uninit-pr102403-c2.c: New test. + +2021-09-19 Martin Sebor <msebor@redhat.com> + + PR middle-end/102243 + * g++.dg/warn/Wplacement-new-size-10.C: New test. + +2021-09-19 Jeff Law <jeffreyalaw@gmail.com> + + * gfortran.dg/goacc/privatization-1-compute.f90: Make test names + unique. + * gfortran.dg/goacc/routine-external-level-of-parallelism-2.f: + Likewise. + +2021-09-19 Iain Sandoe <iain@sandoe.co.uk> + + * jit.dg/jit.exp (fixed_local_execute): Amend the match and + exit conditions to cater for more platforms. + +2021-09-19 Roger Sayle <roger@nextmovesoftware.com> + + PR middle-end/88173 + * c-c++-common/pr57371-4.c: Tweak/correct test case for QNaNs. + * g++.dg/pr88173-1.C: New test case. + * g++.dg/pr88173-2.C: New test case. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/order-1.c (f2): Add tests for distribute + with order clause. + (f3): Remove. + * c-c++-common/gomp/order-2.c: Don't expect error for distribute + with order clause. + * c-c++-common/gomp/order-5.c: New test. + * c-c++-common/gomp/order-6.c: New test. + * c-c++-common/gomp/clause-dups-1.c (f1): Add tests for + duplicated order clause. + (f9): New function. + * c-c++-common/gomp/clauses-1.c (baz, bar): Don't mix copyin and + order(concurrent) clauses on the same composite construct combined + with distribute, instead split it into two tests, one without + copyin and one without order(concurrent). Add order(concurrent) + clauses to {,{,target} teams} distribute. + * g++.dg/gomp/attrs-1.C (baz, bar): Likewise. + * g++.dg/gomp/attrs-2.C (baz, bar): Likewise. + +2021-09-18 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/default-2.c: New test. + * c-c++-common/gomp/default-3.c: New test. + * g++.dg/gomp/default-1.C: New test. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-vfmaddXXXsh-1a.c: New test. + * gcc.target/i386/avx512fp16-vfmaddXXXsh-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfmsubXXXsh-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfmsubXXXsh-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmaddXXXsh-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmaddXXXsh-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmsubXXXsh-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmsubXXXsh-1b.c: Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-18 H.J. Lu <hjl.tools@gmail.com> + + * gcc.target/i386/avx512fp16-xorsign-1.c: New test. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-neg-1a.c: New test. + * gcc.target/i386/avx512fp16-neg-1b.c: Ditto. + * gcc.target/i386/avx512fp16-scalar-bitwise-1a.c: Ditto. + * gcc.target/i386/avx512fp16-scalar-bitwise-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vector-bitwise-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vector-bitwise-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-neg-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-neg-1b.c: Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-vfmaddXXXph-1a.c: New test. + * gcc.target/i386/avx512fp16-vfmaddXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfmsubXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfmsubXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmaddXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmaddXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmsubXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfnmsubXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmaddXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmaddXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmsubXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmsubXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1b.c: Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test fot new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-vfmaddsubXXXph-1a.c: New test. + * gcc.target/i386/avx512fp16-vfmaddsubXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vfmsubaddXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vfmsubaddXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1b.c: Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-18 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-broadcast-1.c: New test. + * gcc.target/i386/avx512fp16-broadcast-2.c: New test. + +2021-09-18 Jason Merrill <jason@redhat.com> + + * g++.dg/template/dtor5.C: Adjust expected error. + * g++.dg/cpp23/lookup2.C: New test. + * g++.dg/template/dtor11.C: New test. + +2021-09-17 Harald Anlauf <anlauf@gmx.de> + + PR fortran/102366 + * gfortran.dg/pr102366.f90: New test. + +2021-09-17 qing zhao <qing.zhao@oracle.com> + + * gcc.target/i386/auto-init-1.c: Restrict the testing only for + -march=x86-64 and -mtune=generic. Add -fno-stack-protector. + * gcc.target/i386/auto-init-2.c: Restrict the testing only for + -march=x86-64 and -mtune=generic -msse. + * gcc.target/i386/auto-init-3.c: Likewise. + * gcc.target/i386/auto-init-4.c: Likewise. + * gcc.target/i386/auto-init-5.c: Different pattern match for lp64 and + ia32. + * gcc.target/i386/auto-init-6.c: Restrict the testing only for + -march=x86-64 and -mtune-generic -msse. Add -fno-stack-protector. + * gcc.target/i386/auto-init-7.c: Likewise. + * gcc.target/i386/auto-init-8.c: Restrict the testing only for + -march=x86-64 and -mtune=generic -msse.. + * gcc.target/i386/auto-init-padding-1.c: Likewise. + * gcc.target/i386/auto-init-padding-10.c: Likewise. + * gcc.target/i386/auto-init-padding-11.c: Likewise. + * gcc.target/i386/auto-init-padding-12.c: Likewise. + * gcc.target/i386/auto-init-padding-2.c: Likewise. + * gcc.target/i386/auto-init-padding-3.c: Restrict the testing only for + -march=x86-64. Different pattern match for lp64 and ia32. + * gcc.target/i386/auto-init-padding-4.c: Restrict the testing only for + -march=x86-64 and -mtune-generic -msse. + * gcc.target/i386/auto-init-padding-5.c: Likewise. + * gcc.target/i386/auto-init-padding-6.c: Likewise. + * gcc.target/i386/auto-init-padding-7.c: Restrict the testing only for + -march=x86-64 and -mtune-generic -msse. Add -fno-stack-protector. + * gcc.target/i386/auto-init-padding-8.c: Likewise. + * gcc.target/i386/auto-init-padding-9.c: Restrict the testing only for + -march=x86-64. Different pattern match for lp64 and ia32. + +2021-09-17 Martin Sebor <msebor@redhat.com> + + PR middle-end/102200 + * gcc.dg/Wstringop-overflow-62.c: Adjust text of an expected note. + * gcc.dg/Warray-bounds-89.c: New test. + * gcc.dg/Wstringop-overflow-74.c: New test. + * gcc.dg/Wstringop-overflow-75.c: New test. + * gcc.dg/Wstringop-overflow-76.c: New test. + +2021-09-17 Sandra Loosemore <sandra@codesourcery.com> + + * gfortran.dg/PR100914.c: Do not include quadmath.h. Use + _Float128 _Complex instead of __complex128. + * gfortran.dg/PR100914.f90: Add -Wno-pedantic to suppress error + about use of _Float128. + * gfortran.dg/c-interop/typecodes-array-float128-c.c: Use + _Float128 instead of __float128. + * gfortran.dg/c-interop/typecodes-sanity-c.c: Likewise. + * gfortran.dg/c-interop/typecodes-scalar-float128-c.c: Likewise. + * lib/target-supports.exp + (check_effective_target_fortran_real_c_float128): Update comments. + +2021-09-17 Roger Sayle <roger@nextmovesoftware.com> + + PR c/102245 + * gcc.dg/Wint-in-bool-context-4.c: New test case. + +2021-09-17 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/atomic-18.c: Expect same diagnostics in C++ as in + C. + * c-c++-common/gomp/atomic-25.c: Drop c effective target. + * c-c++-common/gomp/atomic-26.c: Likewise. + * c-c++-common/gomp/atomic-27.c: Likewise. + * c-c++-common/gomp/atomic-28.c: Likewise. + * c-c++-common/gomp/atomic-29.c: Likewise. + * c-c++-common/gomp/atomic-30.c: Likewise. Adjust expected diagnostics + for C++ when it differs from C. + (foo): Change return type from double to void. + * g++.dg/gomp/atomic-5.C: Adjust expected diagnostics wording. + * g++.dg/gomp/atomic-20.C: New test. + +2021-09-17 H.J. Lu <hjl.tools@gmail.com> + + * gcc.target/i386/avx-covert-1.c: New file. + * gcc.target/i386/avx-fp-covert-1.c: Likewise. + * gcc.target/i386/avx-int-covert-1.c: Likewise. + * gcc.target/i386/sse-covert-1.c: Likewise. + * gcc.target/i386/sse-fp-covert-1.c: Likewise. + * gcc.target/i386/sse-int-covert-1.c: Likewise. + +2021-09-17 H.J. Lu <hjl.tools@gmail.com> + + PR target/101900 + * gcc.target/i386/pr101900-1.c: New test. + * gcc.target/i386/pr101900-2.c: Likewise. + * gcc.target/i386/pr101900-3.c: Likewise. + +2021-09-17 Eric Botcazou <ebotcazou@adacore.com> + + * gcc.target/sparc/20210917-1.c: New test. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-typecast-1.c: New test. + * gcc.target/i386/avx512fp16-typecast-2.c: Ditto. + * gcc.target/i386/avx512fp16vl-typecast-1.c: Ditto. + * gcc.target/i386/avx512fp16vl-typecast-2.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-vcvtsd2sh-1a.c: New test. + * gcc.target/i386/avx512fp16-vcvtsd2sh-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2sd-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2sd-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2ss-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2ss-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtss2sh-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtss2sh-1b.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-helper.h (V512): Add DF contents. + (src3f): New. + * gcc.target/i386/avx512fp16-vcvtpd2ph-1a.c: New test. + * gcc.target/i386/avx512fp16-vcvtpd2ph-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtph2pd-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtph2pd-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtph2psx-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtph2psx-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtps2ph-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtps2ph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtpd2ph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtpd2ph-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtph2pd-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtph2pd-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtph2psx-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtph2psx-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtps2ph-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvtps2ph-1b.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-vcvttsh2si-1a.c: New test. + * gcc.target/i386/avx512fp16-vcvttsh2si-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttsh2si64-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttsh2si64-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttsh2usi-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttsh2usi-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttsh2usi64-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttsh2usi64-1b.c: Ditto. + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-vcvttph2dq-1a.c: New test. + * gcc.target/i386/avx512fp16-vcvttph2dq-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2qq-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2qq-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2udq-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2udq-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2uqq-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2uqq-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2uw-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2uw-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2w-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvttph2w-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2dq-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2dq-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2qq-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2qq-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2udq-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2udq-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2uqq-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2uqq-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2uw-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2uw-1b.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2w-1a.c: Ditto. + * gcc.target/i386/avx512fp16vl-vcvttph2w-1b.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx512fp16-helper.h (V512): Add int32 + component. + * gcc.target/i386/avx512fp16-vcvtsh2si-1a.c: New test. + * gcc.target/i386/avx512fp16-vcvtsh2si-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2si64-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2si64-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2usi-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2usi-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2usi64-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsh2usi64-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsi2sh-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsi2sh-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsi2sh64-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtsi2sh64-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtusi2sh-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtusi2sh-1b.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtusi2sh64-1a.c: Ditto. + * gcc.target/i386/avx512fp16-vcvtusi2sh64-1b.c: Ditto. + +2021-09-17 liuhongt <hongtao.liu@intel.com> + + * gcc.target/i386/avx-1.c: Add test for new builtins. + * gcc.target/i386/sse-13.c: Ditto. + * gcc.target/i386/sse-23.c: Ditto. + * gcc.target/i386/sse-14.c: Add test for new intrinsics. + * gcc.target/i386/sse-22.c: Ditto. + 2021-09-16 Patrick Palka <ppalka@redhat.com> PR c++/98486 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 604caf0..a17f68d 100644 --- a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c @@ -29,6 +29,12 @@ f1 (int *p) #pragma omp for nowait nowait /* { dg-error "too many 'nowait' clauses" } */ for (i = 0; i < 8; ++i) f0 (); + #pragma omp for schedule(static) order(concurrent) order(concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); + #pragma omp for schedule(static) order(reproducible:concurrent) order(unconstrained:concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); #pragma omp simd collapse(1) collapse(1) /* { dg-error "too many 'collapse' clauses" } */ for (i = 0; i < 8; ++i) f0 (); @@ -207,6 +213,18 @@ f1 (int *p) f0 (); #pragma omp scope nowait nowait /* { dg-error "too many 'nowait' clauses" } */ ; + #pragma omp loop bind(thread) order(concurrent) order(concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); + #pragma omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); + #pragma omp simd order(concurrent) order(concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); + #pragma omp simd order(reproducible:concurrent) order(unconstrained:concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); } #pragma omp declare simd simdlen (4) simdlen (4) /* { dg-error "too many 'simdlen' clauses" } */ @@ -223,3 +241,17 @@ void f6 (int a, int b); void f7 (int a, int b); #pragma omp declare simd linear (a) uniform (a) /* { dg-error "'a' appears more than once in data clauses" } */ void f8 (int a, int b); + +#pragma omp declare target +void +f9 (void) +{ + int i; + #pragma omp distribute dist_schedule(static) order(concurrent) order(concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); + #pragma omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) /* { dg-error "too many 'order' clauses" } */ + for (i = 0; i < 8; ++i) + f0 (); +} +#pragma omp end declare target diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-1.c b/gcc/testsuite/c-c++-common/gomp/clauses-1.c index 378c7bf..742132f 100644 --- a/gcc/testsuite/c-c++-common/gomp/clauses-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clauses-1.c @@ -66,14 +66,27 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s, #pragma omp distribute parallel for \ private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ - lastprivate (l) schedule(static, 4) copyin(t) order(concurrent) allocate (p) + lastprivate (l) schedule(static, 4) copyin(t) allocate (p) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp distribute parallel for \ + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) order(concurrent) allocate (p) for (int i = 0; i < 64; i++) ll++; #pragma omp distribute parallel for simd \ private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ if (parallel: i2) if(simd: i1) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ lastprivate (l) schedule(static, 4) nontemporal(ntm) \ - safelen(8) simdlen(4) aligned(q: 32) copyin(t) order(concurrent) allocate (f) + safelen(8) simdlen(4) aligned(q: 32) copyin(t) allocate (f) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp distribute parallel for simd \ + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) if(simd: i1) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) nontemporal(ntm) \ + safelen(8) simdlen(4) aligned(q: 32) order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; #pragma omp distribute simd \ @@ -156,7 +169,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, ; #pragma omp target teams distribute \ device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) \ - shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) order(concurrent) \ collapse(1) dist_schedule(static, 16) nowait depend(inout: dd[0]) allocate (omp_default_mem_alloc:f) in_reduction(+:r2) for (int i = 0; i < 64; i++) ; @@ -218,7 +231,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, #pragma omp target nowait depend(inout: dd[0]) in_reduction(+:r2) #pragma omp teams distribute \ private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ - collapse(1) dist_schedule(static, 16) allocate (omp_default_mem_alloc: f) + collapse(1) dist_schedule(static, 16) allocate (omp_default_mem_alloc: f) order(concurrent) for (int i = 0; i < 64; i++) ; #pragma omp target @@ -249,20 +262,36 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, ll++; #pragma omp teams distribute parallel for \ private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ - collapse(1) dist_schedule(static, 16) order(concurrent) \ + collapse(1) dist_schedule(static, 16) \ if (parallel: i2) num_threads (nth) proc_bind(spread) \ lastprivate (l) schedule(static, 4) copyin(t) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp teams distribute parallel for \ + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) order(concurrent) \ + if (parallel: i2) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) allocate (f) + for (int i = 0; i < 64; i++) + ll++; #pragma omp teams distribute parallel for simd \ private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ collapse(1) dist_schedule(static, 16) \ if (parallel: i2) num_threads (nth) proc_bind(spread) \ - lastprivate (l) schedule(static, 4) order(concurrent) \ + lastprivate (l) schedule(static, 4) \ safelen(8) simdlen(4) aligned(q: 32) if (simd: i3) nontemporal(ntm) copyin(t) \ allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp teams distribute parallel for simd \ + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ + collapse(1) dist_schedule(static, 16) \ + if (parallel: i2) num_threads (nth) proc_bind(spread) \ + lastprivate (l) schedule(static, 4) order(concurrent) \ + safelen(8) simdlen(4) aligned(q: 32) if (simd: i3) nontemporal(ntm) \ + allocate (f) + for (int i = 0; i < 64; i++) + ll++; #pragma omp teams distribute simd \ private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) \ collapse(1) dist_schedule(static, 16) order(concurrent) \ diff --git a/gcc/testsuite/c-c++-common/gomp/default-2.c b/gcc/testsuite/c-c++-common/gomp/default-2.c new file mode 100644 index 0000000..6378e6e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/default-2.c @@ -0,0 +1,67 @@ +int x; +extern int z; + +void +foo (void) +{ + int y = 0, i; + static int w; + #pragma omp task default(firstprivate) /* { dg-message "note: enclosing 'task'" } */ + { + y++; /* { dg-bogus "'y' not specified in enclosing 'task'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'task'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'task'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'task'" } */ + } + #pragma omp taskloop default(firstprivate) /* { dg-message "note: enclosing 'taskloop'" } */ + for (i = 0; i < 64; i++) + { + y++; /* { dg-bogus "'y' not specified in enclosing 'taskloop'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'taskloop'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'taskloop'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'taskloop'" } */ + } + #pragma omp teams default(firstprivate) /* { dg-message "note: enclosing 'teams'" } */ + { + y++; /* { dg-bogus "'y' not specified in enclosing 'teams'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'teams'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'teams'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'teams'" } */ + } + #pragma omp parallel default(firstprivate) /* { dg-message "note: enclosing 'parallel'" } */ + { + y++; /* { dg-bogus "'y' not specified in enclosing 'parallel'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'parallel'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'parallel'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'parallel'" } */ + } + #pragma omp task default(private) /* { dg-message "note: enclosing 'task'" } */ + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'task'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'task'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'task'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'task'" } */ + } + #pragma omp taskloop default(private) /* { dg-message "note: enclosing 'taskloop'" } */ + for (i = 0; i < 64; i++) + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'taskloop'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'taskloop'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'taskloop'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'taskloop'" } */ + } + #pragma omp teams default(private) /* { dg-message "note: enclosing 'teams'" } */ + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'teams'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'teams'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'teams'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'teams'" } */ + } + #pragma omp parallel default(private) /* { dg-message "note: enclosing 'parallel'" } */ + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'parallel'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'parallel'" } */ + x++; /* { dg-error "'x' not specified in enclosing 'parallel'" } */ + z++; /* { dg-error "'z' not specified in enclosing 'parallel'" } */ + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/default-3.c b/gcc/testsuite/c-c++-common/gomp/default-3.c new file mode 100644 index 0000000..a742a71 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/default-3.c @@ -0,0 +1,14 @@ +void +foo (void) +{ + int i; + #pragma omp task default(copyprivate) /* { dg-error "expected 'none', 'shared', 'private' or 'firstprivate' before 'copyprivate'" } */ + ; + #pragma omp taskloop default(copyprivate) /* { dg-error "expected 'none', 'shared', 'private' or 'firstprivate' before 'copyprivate'" } */ + for (i = 0; i < 64; i++) + ; + #pragma omp teams default(copyprivate) /* { dg-error "expected 'none', 'shared', 'private' or 'firstprivate' before 'copyprivate'" } */ + ; + #pragma omp parallel default(copyprivate) /* { dg-error "expected 'none', 'shared', 'private' or 'firstprivate' before 'copyprivate'" } */ + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/order-1.c b/gcc/testsuite/c-c++-common/gomp/order-1.c index da4b73d..547d061 100644 --- a/gcc/testsuite/c-c++-common/gomp/order-1.c +++ b/gcc/testsuite/c-c++-common/gomp/order-1.c @@ -29,6 +29,9 @@ f2 (int *a) #pragma omp teams distribute parallel for simd order(concurrent) for (i = 0; i < 128; i++) a[i]++; + #pragma omp teams distribute order(concurrent) + for (i = 0; i < 128; i++) + a[i]++; #pragma omp teams { #pragma omp distribute parallel for order(concurrent) @@ -37,17 +40,11 @@ f2 (int *a) #pragma omp distribute parallel for simd order(concurrent) for (i = 0; i < 128; i++) a[i]++; + #pragma omp distribute order(concurrent) + for (i = 0; i < 128; i++) + a[i]++; } #pragma omp taskloop simd order (concurrent) for (i = 0; i < 128; i++) a[i]++; } - -void -f3 (int *a) -{ - int i; - #pragma omp for order(concurrent) order(concurrent) order(concurrent) - for (i = 0; i < 128; i++) - a[i]++; -} diff --git a/gcc/testsuite/c-c++-common/gomp/order-2.c b/gcc/testsuite/c-c++-common/gomp/order-2.c index 1a9adb0..5e044dc 100644 --- a/gcc/testsuite/c-c++-common/gomp/order-2.c +++ b/gcc/testsuite/c-c++-common/gomp/order-2.c @@ -24,7 +24,7 @@ f2 (int *a) { int i; #pragma omp teams - #pragma omp distribute order(concurrent) /* { dg-error "'order' is not valid for '#pragma omp distribute'" } */ + #pragma omp distribute order(concurrent) for (i = 0; i < 128; i++) a[i]++; #pragma omp taskloop order (concurrent) /* { dg-error "'order' is not valid for '#pragma omp taskloop'" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/order-5.c b/gcc/testsuite/c-c++-common/gomp/order-5.c new file mode 100644 index 0000000..17cc8b5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/order-5.c @@ -0,0 +1,101 @@ +void +f1 (int *a) +{ + int i; + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp simd order ( reproducible : concurrent ) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp for simd order(reproducible :concurrent) + for (i = 0; i < 128; i++) + a[i]++; +} + +void +f2 (int *a) +{ + int i; + #pragma omp parallel for order(reproducible: concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp parallel for simd order (reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams distribute parallel for order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams distribute parallel for simd order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams distribute order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams + { + #pragma omp distribute parallel for order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp distribute parallel for simd order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp distribute order(reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + } + #pragma omp taskloop simd order (reproducible:concurrent) + for (i = 0; i < 128; i++) + a[i]++; +} + +void +f3 (int *a) +{ + int i; + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp simd order ( unconstrained : concurrent ) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp for simd order(unconstrained :concurrent) + for (i = 0; i < 128; i++) + a[i]++; +} + +void +f4 (int *a) +{ + int i; + #pragma omp parallel for order(unconstrained: concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp parallel for simd order (unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams distribute parallel for order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams distribute parallel for simd order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams distribute order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp teams + { + #pragma omp distribute parallel for order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp distribute parallel for simd order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + #pragma omp distribute order(unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; + } + #pragma omp taskloop simd order (unconstrained:concurrent) + for (i = 0; i < 128; i++) + a[i]++; +} diff --git a/gcc/testsuite/c-c++-common/gomp/order-6.c b/gcc/testsuite/c-c++-common/gomp/order-6.c new file mode 100644 index 0000000..2127830 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/order-6.c @@ -0,0 +1,412 @@ +void foo (void); +int v; +#ifdef __cplusplus +extern "C" { +#endif +int omp_get_thread_num (void); +int omp_get_num_threads (void); +int omp_target_is_present (const void *, int); +int omp_get_cancellation (void); +#ifdef __cplusplus +} +#endif + +void +f1 (int *a) +{ + int i; + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp parallel /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp simd + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp critical /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + v++; + } + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic write /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + v = a[i]; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp simd order(reproducible:concurrent) + 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 simd order(reproducible:concurrent) + for (i = 0; i < 64; 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" } */ + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + a[i] += omp_target_is_present (a + i, 0); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ + #pragma omp simd order(reproducible:concurrent) + for (i = 0; i < 64; 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" } */ +} + +void +f2 (int *a) +{ + int i; + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp parallel /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp simd + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp critical /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + v++; + } + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic write /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + v = a[i]; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for simd order(reproducible:concurrent) + 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 for simd order(reproducible:concurrent) + for (i = 0; i < 64; 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" } */ + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; i++) + a[i] += omp_target_is_present (a + i, 0); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ + #pragma omp for simd order(reproducible:concurrent) + for (i = 0; i < 64; 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" } */ +} + +void +f3 (int *a) +{ + int i; + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp parallel + foo (); + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp simd + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp critical /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + v++; + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic write /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + v = a[i]; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp task /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + a[i]++; + } + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp taskloop /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp for order(reproducible:concurrent) + 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 for order(reproducible:concurrent) + for (i = 0; i < 64; 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" } */ + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; i++) + a[i] += omp_target_is_present (a + i, 0); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ + #pragma omp for order(reproducible:concurrent) + for (i = 0; i < 64; 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" } */ +} + +void +f4 (int *a) +{ + int i; + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp parallel /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp simd + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp critical /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + v++; + } + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic write /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + v = a[i]; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp simd order(unconstrained:concurrent) + 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 simd order(unconstrained:concurrent) + for (i = 0; i < 64; 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" } */ + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + a[i] += omp_target_is_present (a + i, 0); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ + #pragma omp simd order(unconstrained:concurrent) + for (i = 0; i < 64; 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" } */ +} + +void +f5 (int *a) +{ + int i; + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp parallel /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp simd + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp critical /* { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } */ + foo (); + } + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + v++; + } + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic write /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + v = a[i]; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for simd order(unconstrained:concurrent) + 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 for simd order(unconstrained:concurrent) + for (i = 0; i < 64; 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" } */ + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + a[i] += omp_target_is_present (a + i, 0); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ + #pragma omp for simd order(unconstrained:concurrent) + for (i = 0; i < 64; 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" } */ +} + +void +f6 (int *a) +{ + int i; + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp parallel + foo (); + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp simd + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp critical /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp ordered simd /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + foo (); + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + v++; + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic read /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + a[i] = v; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp atomic write /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c++ } } */ + v = a[i]; /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" "" { target c } } */ + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + #pragma omp task /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + a[i]++; + } + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + { + int j; + #pragma omp taskloop /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } */ + for (j = 0; j < 64; j++) + a[64 * i + j] = i + j; + } + #pragma omp for order(unconstrained:concurrent) + 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 for order(unconstrained:concurrent) + for (i = 0; i < 64; 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" } */ + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; i++) + a[i] += omp_target_is_present (a + i, 0); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ + #pragma omp for order(unconstrained:concurrent) + for (i = 0; i < 64; 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" } */ +} diff --git a/gcc/testsuite/c-c++-common/pr57371-4.c b/gcc/testsuite/c-c++-common/pr57371-4.c index f43f7c2..d938ecd 100644 --- a/gcc/testsuite/c-c++-common/pr57371-4.c +++ b/gcc/testsuite/c-c++-common/pr57371-4.c @@ -13,25 +13,25 @@ void nonfinite(unsigned short x) { { volatile int nonfinite_1; nonfinite_1 = (float) x > QNAN; - /* { dg-final { scan-tree-dump "nonfinite_1 = \\(float\\)" "original" } } */ + /* { dg-final { scan-tree-dump "nonfinite_1 = 0" "original" } } */ } { volatile int nonfinite_2; nonfinite_2 = (float) x >= QNAN; - /* { dg-final { scan-tree-dump "nonfinite_2 = \\(float\\)" "original" } } */ + /* { dg-final { scan-tree-dump "nonfinite_2 = 0" "original" } } */ } { volatile int nonfinite_3; nonfinite_3 = (float) x < QNAN; - /* { dg-final { scan-tree-dump "nonfinite_3 = \\(float\\)" "original" } } */ + /* { dg-final { scan-tree-dump "nonfinite_3 = 0" "original" } } */ } { volatile int nonfinite_4; nonfinite_4 = (float) x <= QNAN; - /* { dg-final { scan-tree-dump "nonfinite_4 = \\(float\\)" "original" } } */ + /* { dg-final { scan-tree-dump "nonfinite_4 = 0" "original" } } */ } { diff --git a/gcc/testsuite/g++.dg/abi/anon4.C b/gcc/testsuite/g++.dg/abi/anon4.C index 088ba99..8200f4b 100644 --- a/gcc/testsuite/g++.dg/abi/anon4.C +++ b/gcc/testsuite/g++.dg/abi/anon4.C @@ -1,4 +1,5 @@ // PR c++/65209 +// { dg-additional-options "-fno-pie" { target sparc*-*-* } } // { dg-final { scan-assembler-not "comdat" } } // Everything involving the anonymous namespace bits should be private, not diff --git a/gcc/testsuite/g++.dg/cpp23/lookup2.C b/gcc/testsuite/g++.dg/cpp23/lookup2.C new file mode 100644 index 0000000..a16afbe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp23/lookup2.C @@ -0,0 +1,6 @@ +// DR 1835 + +template <class T> void f(T t) { t.foo::bar(); } +struct foo { void bar(); }; +struct baz : foo { }; +int main() { f(baz()); } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index c871c51..2a5f2cf 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -63,7 +63,7 @@ foo (int d, int m, int i1, int i2, int p, int *idp, int s, ll++; [[omp::directive (distribute private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) - allocate (omp_default_mem_alloc:f))]] + allocate (omp_default_mem_alloc:f) order(concurrent))]] for (int i = 0; i < 64; i++) ll++; } @@ -85,14 +85,27 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s, [[omp::directive (distribute parallel for private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) - lastprivate (l) schedule(static, 4) copyin(t) order(concurrent) allocate (p))]] + lastprivate (l) schedule(static, 4) copyin(t) allocate (p))]] + for (int i = 0; i < 64; i++) + ll++; + [[omp::directive (distribute parallel for + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) + if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) + lastprivate (l) schedule(static, 4) order(concurrent) allocate (p))]] for (int i = 0; i < 64; i++) ll++; [[omp::directive (distribute parallel for simd private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) if (parallel: i2) if(simd: i1) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) lastprivate (l) schedule(static, 4) nontemporal(ntm) - safelen(8) simdlen(4) aligned(q: 32) copyin(t) order(concurrent) allocate (f))]] + safelen(8) simdlen(4) aligned(q: 32) copyin(t) allocate (f))]] + for (int i = 0; i < 64; i++) + ll++; + [[omp::directive (distribute parallel for simd + private (p) firstprivate (f) collapse(1) dist_schedule(static, 16) + if (parallel: i2) if(simd: i1) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) + lastprivate (l) schedule(static, 4) nontemporal(ntm) + safelen(8) simdlen(4) aligned(q: 32) order(concurrent) allocate (f))]] for (int i = 0; i < 64; i++) ll++; [[omp::directive (distribute simd @@ -207,7 +220,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, ; [[omp::sequence (omp::directive (target teams distribute device(d) map (tofrom: m) if (target: i1) private (p) firstprivate (f) defaultmap(tofrom: scalar) is_device_ptr (idp) - shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) + shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) order(concurrent) collapse(1) dist_schedule(static, 16) nowait depend(inout: dd[0]) allocate (omp_default_mem_alloc:f) in_reduction(+:r2)))]] for (int i = 0; i < 64; i++) ; @@ -292,7 +305,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, [[omp::sequence (directive (target nowait depend(inout: dd[0]) in_reduction(+:r2)), directive (teams distribute private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) - collapse(1) dist_schedule(static, 16) allocate (omp_default_mem_alloc: f)))]] + collapse(1) dist_schedule(static, 16) allocate (omp_default_mem_alloc: f) order(concurrent)))]] for (int i = 0; i < 64; i++) ; [[omp::directive (teams @@ -327,20 +340,36 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, ll++; [[omp::directive (teams distribute parallel for private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) - collapse(1) dist_schedule(static, 16) order(concurrent) + collapse(1) dist_schedule(static, 16) if (parallel: i2) num_threads (nth) proc_bind(spread) lastprivate (l) schedule(static, 4) copyin(t) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (teams distribute parallel for + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) + collapse(1) dist_schedule(static, 16) order(concurrent) + if (parallel: i2) num_threads (nth) proc_bind(spread) + lastprivate (l) schedule(static, 4) allocate (f))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (teams distribute parallel for simd private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) collapse(1) dist_schedule(static, 16) if (parallel: i2) num_threads (nth) proc_bind(spread) - lastprivate (l) schedule(static, 4) order(concurrent) + lastprivate (l) schedule(static, 4) safelen(8) simdlen(4) aligned(q: 32) if (simd: i3) nontemporal(ntm) copyin(t) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (teams distribute parallel for simd + private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) + collapse(1) dist_schedule(static, 16) + if (parallel: i2) num_threads (nth) proc_bind(spread) + lastprivate (l) schedule(static, 4) order(concurrent) + safelen(8) simdlen(4) aligned(q: 32) if (simd: i3) nontemporal(ntm) + allocate (f))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (teams distribute simd private(p) firstprivate (f) shared(s) default(shared) reduction(+:r) num_teams(nte) thread_limit(tl) collapse(1) dist_schedule(static, 16) order(concurrent) diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index 5ec19b3..c00be7f 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -63,7 +63,7 @@ foo (int d, int m, int i1, int i2, int p, int *idp, int s, ll++; [[omp::directive (distribute, private (p),firstprivate (f),collapse(1),dist_schedule(static, 16), - allocate (omp_default_mem_alloc:f))]] + allocate (omp_default_mem_alloc:f),order(concurrent))]] for (int i = 0; i < 64; i++) ll++; } @@ -85,14 +85,27 @@ baz (int d, int m, int i1, int i2, int p, int *idp, int s, [[omp::directive (distribute parallel for, private (p),firstprivate (f),collapse(1),dist_schedule(static, 16), if (parallel: i2),default(shared),shared(s),reduction(+:r),num_threads (nth),proc_bind(spread), - lastprivate (l),schedule(static, 4),copyin(t),order(concurrent),allocate (p))]] + lastprivate (l),schedule(static, 4),copyin(t),allocate (p))]] + for (int i = 0; i < 64; i++) + ll++; + [[omp::directive (distribute parallel for, + private (p),firstprivate (f),collapse(1),dist_schedule(static, 16), + if (parallel: i2),default(shared),shared(s),reduction(+:r),num_threads (nth),proc_bind(spread), + lastprivate (l),schedule(static, 4),order(concurrent),allocate (p))]] for (int i = 0; i < 64; i++) ll++; [[omp::directive (distribute parallel for simd, private (p),firstprivate (f),collapse(1),dist_schedule(static, 16), if (parallel: i2),if(simd: i1),default(shared),shared(s),reduction(+:r),num_threads (nth),proc_bind(spread), lastprivate (l),schedule(static, 4),nontemporal(ntm), - safelen(8),simdlen(4),aligned(q: 32),copyin(t),order(concurrent),allocate (f))]] + safelen(8),simdlen(4),aligned(q: 32),copyin(t),allocate (f))]] + for (int i = 0; i < 64; i++) + ll++; + [[omp::directive (distribute parallel for simd, + private (p),firstprivate (f),collapse(1),dist_schedule(static, 16), + if (parallel: i2),if(simd: i1),default(shared),shared(s),reduction(+:r),num_threads (nth),proc_bind(spread), + lastprivate (l),schedule(static, 4),nontemporal(ntm), + safelen(8),simdlen(4),aligned(q: 32),order(concurrent),allocate (f))]] for (int i = 0; i < 64; i++) ll++; [[omp::directive (distribute simd, @@ -207,7 +220,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, ; [[omp::sequence (omp::directive (target teams distribute, device(d),map (tofrom: m),if (target: i1),private (p),firstprivate (f),defaultmap(tofrom: scalar),is_device_ptr (idp), - shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), + shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl),order(concurrent), collapse(1),dist_schedule(static, 16),nowait depend(inout: dd[0]),allocate (omp_default_mem_alloc:f),in_reduction(+:r2)))]] for (int i = 0; i < 64; i++) ; @@ -292,7 +305,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, [[omp::sequence (directive (target, nowait,depend(inout: dd[0]),in_reduction(+:r2)), directive (teams distribute, private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), - collapse(1),dist_schedule(static, 16),allocate (omp_default_mem_alloc: f)))]] + collapse(1),dist_schedule(static, 16),allocate (omp_default_mem_alloc: f),order(concurrent)))]] for (int i = 0; i < 64; i++) ; [[omp::directive (teams, @@ -327,20 +340,36 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, ll++; [[omp::directive (teams distribute parallel for, private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), - collapse(1),dist_schedule(static, 16),order(concurrent), + collapse(1),dist_schedule(static, 16), if (parallel: i2),num_threads (nth),proc_bind(spread), lastprivate (l),schedule(static, 4),copyin(t),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (teams distribute parallel for, + private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), + collapse(1),dist_schedule(static, 16),order(concurrent), + if (parallel: i2),num_threads (nth),proc_bind(spread), + lastprivate (l),schedule(static, 4),allocate (f))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (teams distribute parallel for simd, private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), collapse(1),dist_schedule(static, 16), if (parallel: i2),num_threads (nth),proc_bind(spread), - lastprivate (l),schedule(static, 4),order(concurrent), + lastprivate (l),schedule(static, 4), safelen(8),simdlen(4),aligned(q: 32),if (simd: i3),nontemporal(ntm),copyin(t), allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (teams distribute parallel for simd, + private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), + collapse(1),dist_schedule(static, 16), + if (parallel: i2),num_threads (nth),proc_bind(spread), + lastprivate (l),schedule(static, 4),order(concurrent), + safelen(8),simdlen(4),aligned(q: 32),if (simd: i3),nontemporal(ntm), + allocate (f))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (teams distribute simd, private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl), collapse(1),dist_schedule(static, 16),order(concurrent), diff --git a/gcc/testsuite/g++.dg/gomp/default-1.C b/gcc/testsuite/g++.dg/gomp/default-1.C new file mode 100644 index 0000000..e39df12 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/default-1.C @@ -0,0 +1,112 @@ +namespace N +{ + int x; + extern int z; +} + +struct S +{ + static int s; +}; + +#if __cpp_variable_templates >= 201304 +template <int N> +int t = N; +#endif + +void +foo (void) +{ + int y = 0, i; + static int w; + #pragma omp task default(firstprivate) /* { dg-message "note: enclosing 'task'" } */ + { + y++; /* { dg-bogus "'y' not specified in enclosing 'task'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'task'" } */ + S::s++; /* { dg-bogus "'S::s' not specified in enclosing 'task'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'task'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'task'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'task'" "" { target c++14 } } */ +#endif + } + #pragma omp taskloop default(firstprivate) /* { dg-message "note: enclosing 'taskloop'" } */ + for (i = 0; i < 64; i++) + { + y++; /* { dg-bogus "'y' not specified in enclosing 'taskloop'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'taskloop'" } */ + S::s++; /* { dg-bogus "'S::s' not specified in enclosing 'taskloop'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'taskloop'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'taskloop'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'taskloop'" "" { target c++14 } } */ +#endif + } + #pragma omp teams default(firstprivate) /* { dg-message "note: enclosing 'teams'" } */ + { + y++; /* { dg-bogus "'y' not specified in enclosing 'teams'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'teams'" } */ + S::s++; /* { dg-bogus "'S::s' not specified in enclosing 'teams'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'teams'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'teams'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'teams'" "" { target c++14 } } */ +#endif + } + #pragma omp parallel default(firstprivate) /* { dg-message "note: enclosing 'parallel'" } */ + { + y++; /* { dg-bogus "'y' not specified in enclosing 'parallel'" } */ + w++; /* { dg-bogus "'w' not specified in enclosing 'parallel'" } */ + S::s++; /* { dg-bogus "'S::s' not specified in enclosing 'parallel'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'parallel'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'parallel'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'parallel'" "" { target c++14 } } */ +#endif + } + #pragma omp task default(private) /* { dg-message "note: enclosing 'task'" } */ + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'task'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'task'" } */ + S::s = 1; /* { dg-bogus "'S::s' not specified in enclosing 'task'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'task'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'task'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'task'" "" { target c++14 } } */ +#endif + } + #pragma omp taskloop default(private) /* { dg-message "note: enclosing 'taskloop'" } */ + for (i = 0; i < 64; i++) + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'taskloop'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'taskloop'" } */ + S::s = 1; /* { dg-bogus "'S::s' not specified in enclosing 'taskloop'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'taskloop'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'taskloop'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'taskloop'" "" { target c++14 } } */ +#endif + } + #pragma omp teams default(private) /* { dg-message "note: enclosing 'teams'" } */ + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'teams'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'teams'" } */ + S::s = 1; /* { dg-bogus "'S::s' not specified in enclosing 'teams'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'teams'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'teams'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'teams'" "" { target c++14 } } */ +#endif + } + #pragma omp parallel default(private) /* { dg-message "note: enclosing 'parallel'" } */ + { + y = 1; /* { dg-bogus "'y' not specified in enclosing 'parallel'" } */ + w = 1; /* { dg-bogus "'w' not specified in enclosing 'parallel'" } */ + S::s = 1; /* { dg-bogus "'S::s' not specified in enclosing 'parallel'" } */ + N::x++; /* { dg-error "'x' not specified in enclosing 'parallel'" } */ + N::z++; /* { dg-error "'z' not specified in enclosing 'parallel'" } */ +#if __cpp_variable_templates >= 201304 + t<5>++; /* { dg-error "'t' not specified in enclosing 'parallel'" "" { target c++14 } } */ +#endif + } +} diff --git a/gcc/testsuite/g++.dg/pr88173-1.C b/gcc/testsuite/g++.dg/pr88173-1.C new file mode 100644 index 0000000..08fcf97 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr88173-1.C @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -std=c++11" } */ + +#define big __builtin_huge_val() +#define nan __builtin_nan("") + +constexpr bool b1 = big > nan; +constexpr bool b2 = nan < big; + diff --git a/gcc/testsuite/g++.dg/pr88173-2.C b/gcc/testsuite/g++.dg/pr88173-2.C new file mode 100644 index 0000000..aa7d784 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr88173-2.C @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fsignaling-nans -std=c++11" } */ + +#define big __builtin_huge_val() +#define nan __builtin_nan("") + +constexpr bool b1 = big > nan; +constexpr bool b2 = nan < big; + diff --git a/gcc/testsuite/g++.dg/template/dtor11.C b/gcc/testsuite/g++.dg/template/dtor11.C new file mode 100644 index 0000000..9bb58b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dtor11.C @@ -0,0 +1,22 @@ +template <class T> +struct B +{ + void f(T *p) + { + p->template A<int>::~A<int>(); + p->A::~A(); + p->~A<int>(); + p->~A(); + p->~T(); + p->T::~T(); + } +}; + +template <class T> +struct A +{ }; + +int main() +{ + B<A<int> >().f(0); +} diff --git a/gcc/testsuite/g++.dg/template/dtor5.C b/gcc/testsuite/g++.dg/template/dtor5.C index 8fa4eeb..d9a1c69 100644 --- a/gcc/testsuite/g++.dg/template/dtor5.C +++ b/gcc/testsuite/g++.dg/template/dtor5.C @@ -11,7 +11,7 @@ template <class T> void f(A<T> *ap) { } template <class T> void g(A<T> *ap) { - ap->~B(); // { dg-error "destructor name" } + ap->~B(); // { dg-error "" } } int main() diff --git a/gcc/testsuite/g++.dg/vect/pr102421.cc b/gcc/testsuite/g++.dg/vect/pr102421.cc new file mode 100644 index 0000000..ccab695 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/pr102421.cc @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-O3" } */ +/* { dg-additional-options "-march=armv8.2-a+sve" { target aarch64-*-* } } */ + +#include <vector> + +template<typename ValueType> +struct BasicVector +{ + ValueType& operator[](int i) { return x_[i]; } + ValueType operator[](int i) const { return x_[i]; } + ValueType x_[3]; +}; +typedef int ivec1[3]; +typedef BasicVector<double> RVec1; +void foo ( + std::vector<RVec1> &x_, + std::vector<RVec1> &xp_, + int homenr, + unsigned short* cFREEZE, + const ivec1* nFreeze) +{ + std::vector<RVec1> xp = xp_; + std::vector<RVec1> x = x_; + for (int i = 0; i < homenr; i++) + { + const int g = cFREEZE[i]; + for (int d = 0; d < 3; d++) + { + if (nFreeze[g][d] == 0) + x[i][d] = xp[i][d]; + } + } +} diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-10.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-10.C new file mode 100644 index 0000000..6b71a83 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-10.C @@ -0,0 +1,13 @@ +/* PR middle-end/102243 - ICE on placement new at global scope + { dg-do compile } + { dg-options "-Wall" } */ + +void *operator new (__SIZE_TYPE__, void *); + +char a[2][sizeof (int)]; + +int *p = new (a[1]) int; + +void *operator new[] (__SIZE_TYPE__, void *p) { return p; } + +int *q = new (a[1]) int[1]; diff --git a/gcc/testsuite/g++.dg/warn/uninit-pr93100.C b/gcc/testsuite/g++.dg/warn/uninit-pr93100.C index 56dc894..e08a36d 100644 --- a/gcc/testsuite/g++.dg/warn/uninit-pr93100.C +++ b/gcc/testsuite/g++.dg/warn/uninit-pr93100.C @@ -1,7 +1,7 @@ /* PR tree-optimization/98508 - Sanitizer disable -Wall and -Wextra { dg-do compile } - { dg-require-effective-target no_fsanitize_address } - { dg-options "-O0 -Wall -fsanitize=address" } */ + { dg-options "-O0 -Wall -fsanitize=address" } + { dg-skip-if "no address sanitizer" { no_fsanitize_address } } */ struct S { diff --git a/gcc/testsuite/g++.target/aarch64/sve/static-var-in-template.C b/gcc/testsuite/g++.target/aarch64/sve/static-var-in-template.C new file mode 100644 index 0000000..74237ff --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve/static-var-in-template.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +#include <arm_sve.h> + +template <int N> +void f() +{ + static svbool_t pg = svwhilelt_b64(0, N); +} + +int main(int argc, char **argv) +{ + f<2>(); + return 0; +} + +/* { dg-error "SVE type 'svbool_t' does not have a fixed size" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-89.c b/gcc/testsuite/gcc.dg/Warray-bounds-89.c new file mode 100644 index 0000000..2604f65 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-89.c @@ -0,0 +1,139 @@ +/* Verify warnings and notes for MIN_EXPRs involving either pointers + to distinct objects or one to a known object and the other to + an unknown one. The relational expressions are strictly invalid + but that should be diagnosed by a separate warning. + { dg-do compile } + { dg-options "-O2 -Warray-bounds -Wno-stringop-overflow" } */ + +/* Verify the note points to the larger of the two objects and mentions + the offset into it (alhough the offset would ideally be a part of + the warning). */ +extern char a3[3]; +extern char a5[5]; // { dg-message "at offset 5 into object 'a5' of size 5" "note" } + +void min_a3_a5 (int i) +{ + char *p = a3 + i; + char *q = a5 + i; + + /* The relational expression below is invalid and should be diagnosed + by its own warning independently of -Warray-bounds. */ + char *d = p < q ? p : q; + + d[4] = 0; + + /* Verify the type in the warning corresponds to the larger of the two + objects. */ + d[5] = 0; // { dg-warning "subscript 5 is outside array bounds of 'char\\\[5]'" } +} + + +// Same as above but with the larger array as the first MIN_EXPR operand. +extern char b4[4]; +extern char b6[6]; // { dg-message "at offset 6 into object 'b6' of size 6" "note" } + +void min_b6_b4 (int i) +{ + char *p = b6 + i; + char *q = b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "subscript 6 is outside array bounds of 'char\\\[6]'" } +} + + +/* Same as above but with the first MIN_EXPR operand pointing to an unknown + object. */ +extern char c7[7]; // { dg-message "at offset 7 into object 'c7' of size 7" "note" } + +void min_p_c7 (char *p, int i) +{ + char *q = c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "subscript 7 is outside array bounds of 'char\\\[7]'" } +} + + +/* Same as above but with the second MIN_EXPR operand pointing to an unknown + object. */ +extern char d8[8]; // { dg-message "at offset 8 into object 'd8' of size 8" "note" } + +void min_d8_p (char *q, int i) +{ + char *p = d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "subscript 8 is outside array bounds of 'char\\\[8]'" } +} + + +/* The following are diagnosed by -Wstringop-overflow but, as a result + of PR 101374, not by -Warray-bounds. */ + +struct A3_5 +{ + char a3[3]; + char a5[5]; // { dg-message "at offset 5 into object 'a5' of size 5" "note" { xfail *-*-* } } +}; + +void min_A3_A5 (int i, struct A3_5 *pa3_5) +{ + char *p = pa3_5->a3 + i; + char *q = pa3_5->a5 + i; + + char *d = p < q ? p : q; + + // d[4] = 0; + d[5] = 0; // { dg-warning "subscript 5 is outside array bounds of 'char\\\[5]'" "pr??????" { xfail *-*-* } } +} + + +struct B4_B6 +{ + char b4[4]; + char b6[6]; // { dg-message "at offset 6 into object 'b6' of size 6" "note" { xfail *-*-* } } +}; + +void min_B6_B4 (int i, struct B4_B6 *pb4_b6) +{ + char *p = pb4_b6->b6 + i; + char *q = pb4_b6->b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "subscript 6 is outside array bounds of 'char\\\[6]'" "pr??????" { xfail *-*-* } } +} + + +struct C7 +{ + char c7[7]; // { dg-message "at offset 7 into object 'c7' of size 7" "note" { xfail *-*-* } } +}; + +void min_p_C7 (char *p, int i, struct C7 *pc7) +{ + char *q = pc7->c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "subscript 7 is outside array bounds of 'char\\\[7]'" "pr??????" { xfail *-*-* } } +} + + +struct D8 +{ + char d8[8]; // { dg-message "at offset 8 into object 'd8' of size 8" "note" { xfail *-*-* } } +}; + +void min_D8_p (char *q, int i, struct D8 *pd8) +{ + char *p = pd8->d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "subscript 8 is outside array bounds of 'char\\\[8]'" "pr??????" { xfail *-*-* } } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c index 318d9bd..4b6d1ab 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c @@ -117,7 +117,7 @@ void test_min (void) { /* Exercise a pointer pointing to a known object plus constant offset with one pointing to an unknown object. */ - char a6[6]; // { dg-message ": destination object 'a6'" "note" } + char a6[6]; // { dg-message "(at offset 1 into )?destination object 'a6'" "note" } char *p1 = ptr; char *p2 = a6 + 1; char *q = MIN (p1, p2); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-70.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-70.c index 82c4d9f..ccfe2ce 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-70.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-70.c @@ -17,8 +17,8 @@ void* warn_loop (void) char *p = __builtin_malloc (15); for (int i = 0; i != 16; ++i) /* The size of the write below depends on the target. When vectorized - the vector size may be 4 or 16, otherwise it may be a series of byte + the vector size may be 4, 8 or 16, otherwise it may be a series of byte assignments. */ - p[i] = i; // { dg-warning "writing (1|2|4|16) bytes? into a region of size (0|1|3|15)" } + p[i] = i; // { dg-warning "writing (1|2|4|8|16) bytes? into a region of size (0|1|3|7|15)" } return p; } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-74.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-74.c new file mode 100644 index 0000000..bacec96 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-74.c @@ -0,0 +1,22 @@ +/* PR middle-end/102200 - ICE on a min of a decl and pointer in a loop + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +extern char a[], n; + +void f (void) +{ + char *p = a; + size_t end = 1; + + while (n) + { + if (p < (char*)end) + *p = ';'; + + if (p > (char*)&end) + p = (char*)&end; + } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-75.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-75.c new file mode 100644 index 0000000..0b242e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-75.c @@ -0,0 +1,133 @@ +/* Verify warnings and notes for MIN_EXPRs involving either pointers + to distinct objects or one to a known object and the other to + an unknown one. The relational expressions are strictly invalid + but that should be diagnosed by a separate warning. + { dg-do compile } + { dg-options "-O2 -Wno-array-bounds" } */ + +/* Verify the note points to the larger of the two objects and mentions + the offset into it (although the offset might be better included in + the warning). */ +extern char a3[3]; +extern char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } + +void min_a3_a5 (int i) +{ + char *p = a3 + i; + char *q = a5 + i; + + /* The relational expression below is invalid and should be diagnosed + by its own warning independently of -Wstringop-overflow. */ + char *d = p < q ? p : q; + + d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +// Same as above but with the larger array as the first MIN_EXPR operand. +extern char b4[4]; +extern char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } + +void min_b6_b4 (int i) +{ + char *p = b6 + i; + char *q = b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the first MIN_EXPR operand pointing to an unknown + object. */ +extern char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } + +void min_p_c7 (char *p, int i) +{ + char *q = c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the second MIN_EXPR operand pointing to an unknown + object. */ +extern char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } + +void min_d8_p (char *q, int i) +{ + char *p = d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct A3_5 +{ + char a3[3]; + char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } +}; + +void min_A3_A5 (int i, struct A3_5 *pa3_5) +{ + char *p = pa3_5->a3 + i; + char *q = pa3_5->a5 + i; + + char *d = p < q ? p : q; + + // d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct B4_B6 +{ + char b4[4]; + char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } +}; + +void min_B6_B4 (int i, struct B4_B6 *pb4_b6) +{ + char *p = pb4_b6->b6 + i; + char *q = pb4_b6->b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct C7 +{ + char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } +}; + +void min_p_C7 (char *p, int i, struct C7 *pc7) +{ + char *q = pc7->c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct D8 +{ + char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } +}; + +void min_D8_p (char *q, int i, struct D8 *pd8) +{ + char *p = pd8->d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-76.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-76.c new file mode 100644 index 0000000..18191a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-76.c @@ -0,0 +1,148 @@ +/* Verify warnings and notes for MAX_EXPRs involving either pointers + to distinct objects or one to a known object and the other to + an unknown one. Unlike for the same object, for unrelated objects + the expected warnings and notes are the same as for MIN_EXPR: when + the order of the objects in the address space cannot be determined + the larger of them is assumed to be used. (This is different for + distinct struct members where the order is given.) + The relational expressions are strictly invalid but that should be + diagnosed by a separate warning. + { dg-do compile } + { dg-options "-O2 -Wno-array-bounds" } */ + +#define MAX(p, q) ((p) > (q) ? (p) : (q)) + +/* Verify that even for MAX_EXPR and like for MIN_EXPR, the note points + to the larger of the two objects and mentions the offset into it + (although the offset might be better included in the warning). */ +extern char a3[3]; +extern char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } + +void max_a3_a5 (int i) +{ + char *p = a3 + i; + char *q = a5 + i; + + /* The relational expression below is invalid and should be diagnosed + by its own warning independently of -Wstringop-overflow. */ + char *d = MAX (p, q); + + d[2] = 0; + d[3] = 0; + d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +// Same as above but with the larger array as the first MAX_EXPR operand. +extern char b4[4]; +extern char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } + +void max_b6_b4 (int i) +{ + char *p = b6 + i; + char *q = b4 + i; + char *d = MAX (p, q); + + d[3] = 0; + d[4] = 0; + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the first MAX_EXPR operand pointing to an unknown + object. */ +extern char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } + +void max_p_c7 (char *p, int i) +{ + char *q = c7 + i; + char *d = MAX (p, q); + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the second MIN_EXPR operand pointing to an unknown + object. */ +extern char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } + +void max_d8_p (char *q, int i) +{ + char *p = d8 + i; + char *d = MAX (p, q); + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct A3_5 +{ + char a3[3]; // { dg-message "at offset 3 into destination object 'a3' of size 3" "pr??????" { xfail *-*-* } } + char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } +}; + +void max_A3_A5 (int i, struct A3_5 *pa3_5) +{ + char *p = pa3_5->a3 + i; + char *q = pa3_5->a5 + i; + + char *d = MAX (p, q); + + d[2] = 0; + d[3] = 0; // { dg-warning "writing 1 byte into a region of size 0" "pr??????" { xfail *-*-* } } + d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct B4_B6 +{ + char b4[4]; + char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } +}; + +void max_B6_B4 (int i, struct B4_B6 *pb4_b6) +{ + char *p = pb4_b6->b6 + i; + char *q = pb4_b6->b4 + i; + char *d = MAX (p, q); + + d[3] = 0; + d[4] = 0; + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct C7 +{ + char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } +}; + +void max_p_C7 (char *p, int i, struct C7 *pc7) +{ + char *q = pc7->c7 + i; + char *d = MAX (p, q); + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct D8 +{ + char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } +}; + +void max_D8_p (char *q, int i, struct D8 *pd8) +{ + char *p = pd8->d8 + i; + char *d = MAX (p, q); + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} diff --git a/gcc/testsuite/gcc.dg/associative-math-1.c b/gcc/testsuite/gcc.dg/associative-math-1.c new file mode 100644 index 0000000..3f9ce5b --- /dev/null +++ b/gcc/testsuite/gcc.dg/associative-math-1.c @@ -0,0 +1,17 @@ +/* Test __ASSOCIATIVE_MATH__ is defined with -fassociative-math. */ +/* { dg-do compile } */ +/* { dg-options "-fassociative-math -fno-signed-zeros -fno-trapping-math" } */ + +#ifndef __ASSOCIATIVE_MATH__ +#error "__ASSOCIATIVE_MATH__ not defined" +#endif + +#pragma GCC optimize "-fno-associative-math" +#ifdef __ASSOCIATIVE_MATH__ +#error "__ASSOCIATIVE_MATH__ defined" +#endif + +#pragma GCC optimize "-fassociative-math" +#ifndef __ASSOCIATIVE_MATH__ +#error "__ASSOCIATIVE_MATH__ not defined" +#endif diff --git a/gcc/testsuite/gcc.dg/associative-math-2.c b/gcc/testsuite/gcc.dg/associative-math-2.c new file mode 100644 index 0000000..764d6f0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/associative-math-2.c @@ -0,0 +1,17 @@ +/* Test __ASSOCIATIVE_MATH__ is not defined with -fno-associative-math. */ +/* { dg-do compile } */ +/* { dg-options "-fno-associative-math" } */ + +#ifdef __ASSOCIATIVE_MATH__ +#error "__ASSOCIATIVE_MATH__ defined" +#endif + +#pragma GCC optimize "-fassociative-math" +#ifndef __ASSOCIATIVE_MATH__ +#error "__ASSOCIATIVE_MATH__ not defined" +#endif + +#pragma GCC optimize "-fno-associative-math" +#ifdef __ASSOCIATIVE_MATH__ +#error "__ASSOCIATIVE_MATH__ defined" +#endif diff --git a/gcc/testsuite/gcc.dg/no-signed-zeros-1.c b/gcc/testsuite/gcc.dg/no-signed-zeros-1.c new file mode 100644 index 0000000..3b9cd71 --- /dev/null +++ b/gcc/testsuite/gcc.dg/no-signed-zeros-1.c @@ -0,0 +1,17 @@ +/* Test __NO_SIGNED_ZEROS__ is defined with -fno-signed-zeros. */ +/* { dg-do compile } */ +/* { dg-options "-fno-signed-zeros" } */ + +#ifndef __NO_SIGNED_ZEROS__ +#error "__NO_SIGNED_ZEROS__ not defined" +#endif + +#pragma GCC optimize "-fsigned-zeros" +#ifdef __NO_SIGNED_ZEROS__ +#error "__NO_SIGNED_ZEROS__ defined" +#endif + +#pragma GCC optimize "-fno-signed-zeros" +#ifndef __NO_SIGNED_ZEROS__ +#error "__NO_SIGNED_ZEROS__ not defined" +#endif diff --git a/gcc/testsuite/gcc.dg/no-signed-zeros-2.c b/gcc/testsuite/gcc.dg/no-signed-zeros-2.c new file mode 100644 index 0000000..865a29f --- /dev/null +++ b/gcc/testsuite/gcc.dg/no-signed-zeros-2.c @@ -0,0 +1,17 @@ +/* Test __NO_SIGNED_ZEROS__ is not defined with -fsigned-zeros. */ +/* { dg-do compile } */ +/* { dg-options "-fsigned-zeros" } */ + +#ifdef __NO_SIGNED_ZEROS__ +#error "__NO_SIGNED_ZEROS__ defined" +#endif + +#pragma GCC optimize "-fno-signed-zeros" +#ifndef __NO_SIGNED_ZEROS__ +#error "__NO_SIGNED_ZEROS__ not defined" +#endif + +#pragma GCC optimize "-fsigned-zeros" +#ifdef __NO_SIGNED_ZEROS__ +#error "__NO_SIGNED_ZEROS__ defined" +#endif diff --git a/gcc/testsuite/gcc.dg/no-trapping-math-1.c b/gcc/testsuite/gcc.dg/no-trapping-math-1.c new file mode 100644 index 0000000..f4faec9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/no-trapping-math-1.c @@ -0,0 +1,17 @@ +/* Test __NO_TRAPPING_MATH__ is defined with -fno-trapping-math. */ +/* { dg-do compile } */ +/* { dg-options "-fno-trapping-math" } */ + +#ifndef __NO_TRAPPING_MATH__ +#error "__NO_TRAPPING_MATH__ not defined" +#endif + +#pragma GCC optimize "-ftrapping-math" +#ifdef __NO_TRAPPING_MATH__ +#error "__NO_TRAPPING_MATH__ defined" +#endif + +#pragma GCC optimize "-fno-trapping-math" +#ifndef __NO_TRAPPING_MATH__ +#error "__NO_TRAPPING_MATH__ not defined" +#endif diff --git a/gcc/testsuite/gcc.dg/no-trapping-math-2.c b/gcc/testsuite/gcc.dg/no-trapping-math-2.c new file mode 100644 index 0000000..1904b5d --- /dev/null +++ b/gcc/testsuite/gcc.dg/no-trapping-math-2.c @@ -0,0 +1,17 @@ +/* Test __NO_TRAPPING_MATH__ is not defined with -ftrapping-math. */ +/* { dg-do compile } */ +/* { dg-options "-ftrapping-math" } */ + +#ifdef __NO_TRAPPING_MATH__ +#error "__NO_TRAPPING_MATH__ defined" +#endif + +#pragma GCC optimize "-fno-trapping-math" +#ifndef __NO_TRAPPING_MATH__ +#error "__NO_TRAPPING_MATH__ not defined" +#endif + +#pragma GCC optimize "-ftrapping-math" +#ifdef __NO_TRAPPING_MATH__ +#error "__NO_TRAPPING_MATH__ defined" +#endif diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c index 4cba87b..8818192 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c @@ -332,8 +332,8 @@ pr87652 (const char *stem, int counter) OFFSET + end_idx); \ } while (0) -/* { dg-error "unable to read substring location: unable to read source line" "" { target c } 329 } */ -/* { dg-error "unable to read substring location: failed to get ordinary maps" "" { target c++ } 329 } */ +/* { dg-error "unable to read substring location: failed to get ordinary maps" "" { target c } 329 } */ +/* { dg-error "unable to read substring location: macro expansion" "" { target c++ } 329 } */ /* { dg-begin-multiline-output "" } __emit_string_literal_range(__FILE__":%5d: " format, \ ^~~~~~~~ diff --git a/gcc/testsuite/gcc.dg/pr91441.c b/gcc/testsuite/gcc.dg/pr91441.c index 4f7a8fb..4c785f6 100644 --- a/gcc/testsuite/gcc.dg/pr91441.c +++ b/gcc/testsuite/gcc.dg/pr91441.c @@ -1,11 +1,11 @@ /* PR target/91441 */ /* { dg-do compile } */ -/* { dg-require-effective-target no_fsanitize_address }*/ /* { dg-options "--param asan-stack=1 -fsanitize=kernel-address" } */ +/* { dg-skip-if "no address sanitizer" { no_fsanitize_address } } */ int *bar(int *); int *f( int a) { return bar(&a); } -/* { dg-warning ".'-fsanitize=kernel-address' with stack protection is not supported without '-fasan-shadow-offset=' for this target" "" { target *-*-* } 0 } */ +/* { dg-warning ".'-fsanitize=kernel-address' with stack protection is not supported without '-fasan-shadow-offset=' for this target" "" { target riscv*-*-* } 0 } */ diff --git a/gcc/testsuite/gcc.dg/pr96260.c b/gcc/testsuite/gcc.dg/pr96260.c index 734832f..587afb7 100644 --- a/gcc/testsuite/gcc.dg/pr96260.c +++ b/gcc/testsuite/gcc.dg/pr96260.c @@ -1,7 +1,7 @@ /* PR target/96260 */ /* { dg-do compile } */ -/* { dg-require-effective-target no_fsanitize_address }*/ /* { dg-options "--param asan-stack=1 -fsanitize=kernel-address -fasan-shadow-offset=0x100000" } */ +/* { dg-skip-if "no address sanitizer" { no_fsanitize_address } } */ int *bar(int *); int *f( int a) diff --git a/gcc/testsuite/gcc.dg/pr96307.c b/gcc/testsuite/gcc.dg/pr96307.c index cd1c17c9..89002b8 100644 --- a/gcc/testsuite/gcc.dg/pr96307.c +++ b/gcc/testsuite/gcc.dg/pr96307.c @@ -1,7 +1,7 @@ /* PR target/96307 */ /* { dg-do compile } */ -/* { dg-require-effective-target no_fsanitize_address }*/ /* { dg-additional-options "-fsanitize=kernel-address --param=asan-instrumentation-with-call-threshold=8" } */ +/* { dg-skip-if "no address sanitizer" { no_fsanitize_address } } */ #include <limits.h> enum a {test1, test2, test3=INT_MAX}; diff --git a/gcc/testsuite/gcc.dg/reciprocal-math-1.c b/gcc/testsuite/gcc.dg/reciprocal-math-1.c new file mode 100644 index 0000000..49173e2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/reciprocal-math-1.c @@ -0,0 +1,17 @@ +/* Test __RECIPROCAL_MATH__ is defined with -freciprocal-math. */ +/* { dg-do compile } */ +/* { dg-options "-freciprocal-math" } */ + +#ifndef __RECIPROCAL_MATH__ +#error "__RECIPROCAL_MATH__ not defined" +#endif + +#pragma GCC optimize "-fno-reciprocal-math" +#ifdef __RECIPROCAL_MATH__ +#error "__RECIPROCAL_MATH__ defined" +#endif + +#pragma GCC optimize "-freciprocal-math" +#ifndef __RECIPROCAL_MATH__ +#error "__RECIPROCAL_MATH__ not defined" +#endif diff --git a/gcc/testsuite/gcc.dg/reciprocal-math-2.c b/gcc/testsuite/gcc.dg/reciprocal-math-2.c new file mode 100644 index 0000000..959baa7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/reciprocal-math-2.c @@ -0,0 +1,17 @@ +/* Test __RECIPROCAL_MATH__ is not defined with -fno-reciprocal-math. */ +/* { dg-do compile } */ +/* { dg-options "-fno-reciprocal-math" } */ + +#ifdef __RECIPROCAL_MATH__ +#error "__RECIPROCAL_MATH__ defined" +#endif + +#pragma GCC optimize "-freciprocal-math" +#ifndef __RECIPROCAL_MATH__ +#error "__RECIPROCAL_MATH__ not defined" +#endif + +#pragma GCC optimize "-fno-reciprocal-math" +#ifdef __RECIPROCAL_MATH__ +#error "__RECIPROCAL_MATH__ defined" +#endif diff --git a/gcc/testsuite/gcc.dg/rounding-math-1.c b/gcc/testsuite/gcc.dg/rounding-math-1.c new file mode 100644 index 0000000..3b13549 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rounding-math-1.c @@ -0,0 +1,17 @@ +/* Test __ROUNDING_MATH__ is defined with -frounding-math. */ +/* { dg-do compile } */ +/* { dg-options "-frounding-math" } */ + +#ifndef __ROUNDING_MATH__ +#error "__ROUNDING_MATH__ not defined" +#endif + +#pragma GCC optimize "-fno-rounding-math" +#ifdef __ROUNDING_MATH__ +#error "__ROUNDING_MATH__ defined" +#endif + +#pragma GCC optimize "-frounding-math" +#ifndef __ROUNDING_MATH__ +#error "__ROUNDING_MATH__ not defined" +#endif diff --git a/gcc/testsuite/gcc.dg/rounding-math-2.c b/gcc/testsuite/gcc.dg/rounding-math-2.c new file mode 100644 index 0000000..6468a84 --- /dev/null +++ b/gcc/testsuite/gcc.dg/rounding-math-2.c @@ -0,0 +1,17 @@ +/* Test __ROUNDING_MATH__ is not defined with -fno-rounding-math. */ +/* { dg-do compile } */ +/* { dg-options "-fno-rounding-math" } */ + +#ifdef __ROUNDING_MATH__ +#error "__ROUNDING_MATH__ defined" +#endif + +#pragma GCC optimize "-frounding-math" +#ifndef __ROUNDING_MATH__ +#error "__ROUNDING_MATH__ not defined" +#endif + +#pragma GCC optimize "-fno-rounding-math" +#ifdef __ROUNDING_MATH__ +#error "__ROUNDING_MATH__ defined" +#endif diff --git a/gcc/testsuite/gcc.dg/torture/20210916.c b/gcc/testsuite/gcc.dg/torture/20210916.c new file mode 100644 index 0000000..0ea6d45 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/20210916.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ + +typedef union tree_node *tree; +struct tree_base { + unsigned : 1; + unsigned lang_flag_2 : 1; +}; +struct tree_type { + tree main_variant; +}; +union tree_node { + struct tree_base base; + struct tree_type type; +}; +tree finish_struct_t, finish_struct_x; +void finish_struct() +{ + for (; finish_struct_t->type.main_variant;) + finish_struct_x->base.lang_flag_2 = 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/evrp-ignore.c b/gcc/testsuite/gcc.dg/tree-ssa/evrp-ignore.c new file mode 100644 index 0000000..9bfaed6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/evrp-ignore.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp -fno-tree-fre -fdisable-tree-ethread" } */ + +void kill(void); + +void foo (int x, int y, int z) +{ + // Establish y = [-INF, 54] + if (y < 55) + return; + + // Establish z == x + if (z != x) + return; + + // EVRP should transform this to if (0 != 0) + if (y < 30) + x = 0; + + // # x_1 = PHI <x_5(D)(6), 0(7)> + // The earlier transformation should make the edge from bb7 + // unexecutable, allowing x_1 == x_5 to be registered, and + // then fold away this condition as well. + if (x != z) + kill(); + +} +/* { dg-final { scan-tree-dump-not "kill" "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/uninit-pr102403-c2.c b/gcc/testsuite/gcc.dg/uninit-pr102403-c2.c new file mode 100644 index 0000000..8181143 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-pr102403-c2.c @@ -0,0 +1,34 @@ +/* PR middle-end/102403 - ICE in init_from_control_deps, at + gimple-predicate-analysis.cc:2364 + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +extern int a[], b, c, d, e, f, g, h; + +inline void foo (void) { b = 1 ^ a[b ^ (c & 1)]; } + +void bar (void); + +int main (void) +{ + if (!f && ~h) + { + if (g) + goto L2; + } + else + { + int m = 0; // { dg-message "declared here" } + L1: + e = m; + L2: + m ^= 1; // { dg-warning "-Wmaybe-uninitialized" } + if (d) + bar (); + + for (int j = 0; j < 10; j++) + foo (); + + goto L1; + } +} diff --git a/gcc/testsuite/gcc.dg/uninit-pr102403.c b/gcc/testsuite/gcc.dg/uninit-pr102403.c new file mode 100644 index 0000000..1e62e98 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-pr102403.c @@ -0,0 +1,49 @@ +/* PR middle-end/102403 - ICE in init_from_control_deps, at + gimple-predicate-analysis.cc:2364 + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +int __fmaf (void) +{ + int a = 0; + int b, c, d, e, f; + + int r = 0; + + switch (b) // { dg-warning "-Wuninitialized" } + { + default: + c |= 1; + + case 0: + if (c == 0) + a = 1; + + switch (d) { + case 15: + f = c; + break; + + case 11: + case 6: + case 4: + f = c; + case 10: + e = a; + } + + if (e == 0) // { dg-warning "-Wmaybe-uninitialized" } + f = 0; + + r = f; + } + + // The return statement below gets the unhelpful warning: + // 'f' may be used uninitialized in this function [-Wmaybe-uninitialized] + return r; +} + +/* Prune out warnings issued on the wrong lines, such as: + uninit-pr102403.c:9:13: warning: ‘d’ is used uninitialized [-Wuninitialized] + { dg-prune-output "-Wuninitialized" } + { dg-prune-output "-Wmaybe-uninitialized" } */ diff --git a/gcc/testsuite/gcc.dg/uninit-pr93100.c b/gcc/testsuite/gcc.dg/uninit-pr93100.c index 531a5c3..7cb0222 100644 --- a/gcc/testsuite/gcc.dg/uninit-pr93100.c +++ b/gcc/testsuite/gcc.dg/uninit-pr93100.c @@ -1,7 +1,7 @@ /* PR tree-optimization/93100 - gcc -fsanitize=address inhibits -Wuninitialized { dg-do compile } { dg-options "-Wall -fsanitize=address" } - { dg-skip-if "sanitize address" { "powerpc-ibm-aix*" } } */ + { dg-skip-if "no address sanitizer" { no_fsanitize_address } } */ struct A { diff --git a/gcc/testsuite/gcc.dg/vect/pr65206.c b/gcc/testsuite/gcc.dg/vect/pr65206.c new file mode 100644 index 0000000..3b62626 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr65206.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_double } */ +/* { dg-additional-options "-fno-trapping-math -fno-allow-store-data-races" } */ +/* { dg-additional-options "-mavx" { target avx } } */ + +#define N 1024 + +double a[N], b[N]; + +void foo () +{ + for (int i = 0; i < N; ++i) + if (b[i] < 3.) + a[i] += b[i]; +} + +/* We get a .MASK_STORE because while the load of a[i] does not trap + the store would introduce store data races. Make sure we still + can handle the data dependence with zero distance. */ + +/* { dg-final { scan-tree-dump-not "versioning for alias required" "vect" { target { vect_masked_store || avx } } } } */ +/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { target { vect_masked_store || avx } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-1.c b/gcc/testsuite/gcc.target/i386/auto-init-1.c index b7690df..3391be1 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-1.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-1.c @@ -1,6 +1,6 @@ /* Verify zero initialization for integer and pointer type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand -fno-stack-protector -march=x86-64 -mtune=generic" } */ #ifndef __cplusplus # define bool _Bool diff --git a/gcc/testsuite/gcc.target/i386/auto-init-2.c b/gcc/testsuite/gcc.target/i386/auto-init-2.c index e76fc25..b23f733 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-2.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-2.c @@ -1,6 +1,6 @@ /* Verify pattern initialization for integer and pointer type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ #ifndef __cplusplus # define bool _Bool @@ -31,6 +31,8 @@ void foo() /* { dg-final { scan-rtl-dump-times "0xfffffffffffffffe" 2 "expand" } } */ /* { dg-final { scan-rtl-dump-times "0xfffffffffffffefe" 1 "expand" } } */ -/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 2 "expand" } } */ -/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefe" 3 "expand" } } */ +/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 2 "expand" { target lp64 } } } */ +/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefe" 3 "expand" { target lp64 } } } */ +/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 4 "expand" { target ia32 } } } */ +/* { dg-final { scan-rtl-dump-times "0xfefefefefefefefe" 1 "expand" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-3.c b/gcc/testsuite/gcc.target/i386/auto-init-3.c index 300ddfb..df31761 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-3.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-3.c @@ -1,6 +1,6 @@ /* Verify zero initialization for floating point type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -march=x86-64 -mtune=generic" } */ long double result; @@ -14,4 +14,5 @@ long double foo() return result; } -/* { dg-final { scan-assembler-times "pxor\t\\\%xmm0, \\\%xmm0" 3 } } */ +/* { dg-final { scan-assembler-times "pxor\t\\\%xmm0, \\\%xmm0" 3 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "fldz" 3 { target ia32} } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-4.c b/gcc/testsuite/gcc.target/i386/auto-init-4.c index abe0b7e..554a2c5 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-4.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-4.c @@ -1,6 +1,6 @@ /* Verify pattern initialization for floating point type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ long double result; @@ -14,7 +14,9 @@ long double foo() return result; } -/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 1 "expand" } } */ -/* { dg-final { scan-rtl-dump-times "\\\[0xfefefefefefefefe\\\]" 1 "expand" } } */ -/* { dg-final { scan-rtl-dump-times "0xfffffffffffffffe\\\]\\\) repeated x16" 1 "expand" } } */ +/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 1 "expand" { target lp64 } } } */ +/* { dg-final { scan-rtl-dump-times "\\\[0xfefefefefefefefe\\\]" 1 "expand" { target lp64 } } } */ +/* { dg-final { scan-rtl-dump-times "0xfffffffffffffffe\\\]\\\) repeated x16" 1 "expand" { target lp64 } } } */ +/* { dg-final { scan-rtl-dump-times "0xfffffffffefefefe" 2 "expand" { target ia32 } } } */ +/* { dg-final { scan-rtl-dump-times "\\\[0xfefefefefefefefe\\\]" 2 "expand" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-5.c b/gcc/testsuite/gcc.target/i386/auto-init-5.c index b2e708c..27d971f 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-5.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-5.c @@ -1,6 +1,6 @@ /* Verify zero initialization for complex type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=zero" } */ _Complex long double result; @@ -15,6 +15,7 @@ _Complex long double foo() return result; } -/* { dg-final { scan-assembler-times "\\.long\t0" 14 } } */ +/* { dg-final { scan-assembler-times "\\.long\t0" 14 { target lp64 } } } */ +/* { dg-final { scan-assembler-times "\\.long\t0" 12 { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-6.c b/gcc/testsuite/gcc.target/i386/auto-init-6.c index c79c039..f75081e 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-6.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-6.c @@ -1,6 +1,6 @@ /* Verify pattern initialization for complex type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ _Complex long double result; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-7.c b/gcc/testsuite/gcc.target/i386/auto-init-7.c index 0114379..7e32576 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-7.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-7.c @@ -1,6 +1,6 @@ /* Verify zero initialization for array, union, and structure type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand -march=x86-64 -mtune=generic -fno-stack-protector -msse" } */ struct S { diff --git a/gcc/testsuite/gcc.target/i386/auto-init-8.c b/gcc/testsuite/gcc.target/i386/auto-init-8.c index 28fbeb7..666ee14 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-8.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-8.c @@ -1,6 +1,6 @@ /* Verify pattern initialization for array, union, and structure type automatic variables. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct S { diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-1.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-1.c index a238b8b..149a04f 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-1.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-1.c @@ -1,7 +1,7 @@ /* Verify zero initialization for structure type automatic variables with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_aligned { int internal1; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-10.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-10.c index 3fc6b07..1125bcf 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-10.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-10.c @@ -1,7 +1,7 @@ /* Verify pattern initialization for array type with structure element with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_trailing_hole { int one; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-11.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-11.c index cc982b9..4f90ad2 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-11.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-11.c @@ -1,7 +1,7 @@ /* Verify zero initialization for union type with structure field with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_trailing_hole { int one; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-12.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-12.c index 0fbdb6c..21a1ee2 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-12.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-12.c @@ -1,7 +1,7 @@ /* Verify pattern initialization for union type with structure field with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_trailing_hole { int one; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-2.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-2.c index 5739aa1..483b79a 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-2.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-2.c @@ -1,7 +1,7 @@ /* Verify pattern initialization for structure type automatic variables with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_aligned { int internal1; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-3.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-3.c index 8a6d764..220a9f2 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-3.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-3.c @@ -1,7 +1,7 @@ /* Verify zero initialization for nested structure type automatic variables with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -march=x86-64" } */ struct test_aligned { unsigned internal1; @@ -24,7 +24,9 @@ int foo () } /* { dg-final { scan-assembler "movl\t\\\$0," } } */ -/* { dg-final { scan-assembler "movl\t\\\$16," } } */ -/* { dg-final { scan-assembler "rep stosq" } } */ +/* { dg-final { scan-assembler "movl\t\\\$16," { target lp64 } } } */ +/* { dg-final { scan-assembler "rep stosq" { target lp64 } } } */ +/* { dg-final { scan-assembler "movl\t\\\$32," { target ia32 } } } */ +/* { dg-final { scan-assembler "rep stosl" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-4.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-4.c index d7be326..2908b3f 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-4.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-4.c @@ -1,7 +1,7 @@ /* Verify pattern initialization for nested structure type automatic variables with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_aligned { unsigned internal1; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-5.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-5.c index 569b09a..e17a621 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-5.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-5.c @@ -1,7 +1,7 @@ /* Verify zero initialization for structure type automatic variables with tail padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_trailing_hole { char *one; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-6.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-6.c index 4e0b614..754f8af 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-6.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-6.c @@ -1,7 +1,7 @@ /* Verify pattern initialization for structure type automatic variables with tail padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse" } */ struct test_trailing_hole { char *one; diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-7.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-7.c index b5abffb..c136e1c 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-7.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-7.c @@ -1,7 +1,7 @@ /* Verify zero initialization for structure type automatic variables with padding and has explicit initialization. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand -march=x86-64 -mtune=generic -msse -fno-stack-protector" } */ struct test_trailing_hole { int one; @@ -17,6 +17,7 @@ int foo () return var.four; } -/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */ +/* { dg-final { scan-rtl-dump-times "const_int 0 \\\[0\\\]\\\) repeated x16" 1 "expand" { target ia32 } } } */ +/* { dg-final { scan-rtl-dump-times "const_int 0 \\\[0\\\]\\\)" 1 "expand" { target lp64 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-8.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-8.c index 66591cf..45baa3c 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-8.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-8.c @@ -1,7 +1,7 @@ /* Verify pattern initialization for structure type automatic variables with padding and has explicit initialization. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=pattern" } */ +/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand -march=x86-64 -mtune=generic -msse -fno-stack-protector" } */ struct test_trailing_hole { int one; @@ -17,6 +17,5 @@ int foo () return var.four; } -/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */ - - +/* { dg-final { scan-rtl-dump-times "const_int 0 \\\[0\\\]\\\) repeated x16" 1 "expand" { target ia32 } } } */ +/* { dg-final { scan-rtl-dump-times "const_int 0 \\\[0\\\]\\\)" 1 "expand" { target lp64 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/auto-init-padding-9.c b/gcc/testsuite/gcc.target/i386/auto-init-padding-9.c index 1ff900f..eafa327 100644 --- a/gcc/testsuite/gcc.target/i386/auto-init-padding-9.c +++ b/gcc/testsuite/gcc.target/i386/auto-init-padding-9.c @@ -1,7 +1,7 @@ /* Verify zero initialization for array type with structure element with padding. */ /* { dg-do compile } */ -/* { dg-options "-ftrivial-auto-var-init=zero" } */ +/* { dg-options "-ftrivial-auto-var-init=zero -march=x86-64" } */ struct test_trailing_hole { int one; @@ -19,4 +19,7 @@ int foo () } /* { dg-final { scan-assembler "movl\t\\\$0," } } */ -/* { dg-final { scan-assembler "rep stosq" } } */ +/* { dg-final { scan-assembler "movl\t\\\$20," { target lp64} } } */ +/* { dg-final { scan-assembler "rep stosq" { target lp64 } } } */ +/* { dg-final { scan-assembler "movl\t\\\$40," { target ia32} } } */ +/* { dg-final { scan-assembler "rep stosl" { target ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/avx-1.c b/gcc/testsuite/gcc.target/i386/avx-1.c index add3e0c..a04c678 100644 --- a/gcc/testsuite/gcc.target/i386/avx-1.c +++ b/gcc/testsuite/gcc.target/i386/avx-1.c @@ -757,6 +757,36 @@ #define __builtin_ia32_vcvtsh2sd_mask_round(A, B, C, D, E) __builtin_ia32_vcvtsh2sd_mask_round(A, B, C, D, 8) #define __builtin_ia32_vcvtss2sh_mask_round(A, B, C, D, E) __builtin_ia32_vcvtss2sh_mask_round(A, B, C, D, 8) #define __builtin_ia32_vcvtsd2sh_mask_round(A, B, C, D, E) __builtin_ia32_vcvtsd2sh_mask_round(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_mask(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_mask(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_mask(A, B, C, D, E) __builtin_ia32_vfmaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfmaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfmaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_mask(A, B, C, D, E) __builtin_ia32_vfnmaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfnmaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfnmaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_mask(A, B, C, D, E) __builtin_ia32_vfmsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfmsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfmsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_mask(A, B, C, D, E) __builtin_ia32_vfnmsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfnmsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfnmsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_mask(A, B, C, D, E) __builtin_ia32_vfmaddsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_mask3(A, B, C, D, E) __builtin_ia32_vfmaddsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_maskz(A, B, C, D, E) __builtin_ia32_vfmaddsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_mask(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_mask3(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_maskz(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_mask(A, B, C, D, E) __builtin_ia32_vfmsubsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_mask3(A, B, C, D, E) __builtin_ia32_vfmsubsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_maskz(A, B, C, D, E) __builtin_ia32_vfmsubsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_mask(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_mask3(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_maskz(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_maskz(A, B, C, D, 8) /* avx512fp16vlintrin.h */ #define __builtin_ia32_cmpph128_mask(A, B, C, D) __builtin_ia32_cmpph128_mask(A, B, 1, D) diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-broadcast-1.c b/gcc/testsuite/gcc.target/i386/avx512fp16-broadcast-1.c new file mode 100644 index 0000000..3e2397f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-broadcast-1.c @@ -0,0 +1,33 @@ +/* PR target/87767 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ +/* { dg-additional-options "-mdynamic-no-pic" { target { *-*-darwin* && ia32 } } } +/* { dg-final { scan-assembler-times "\[^\n\]*\\\{1to8\\\}" 4 } } */ +/* { dg-final { scan-assembler-times "\[^\n\]*\\\{1to16\\\}" 4 } } */ +/* { dg-final { scan-assembler-times "\[^\n\]*\\\{1to32\\\}" 4 } } */ + +typedef _Float16 v8hf __attribute__ ((vector_size (16))); +typedef _Float16 v16hf __attribute__ ((vector_size (32))); +typedef _Float16 v32hf __attribute__ ((vector_size (64))); + +#define CONSTANT 101; +#define FOO(VTYPE, OP_NAME, OP) \ +VTYPE \ + __attribute__ ((noipa)) \ +foo_##OP_NAME##_##VTYPE (VTYPE a) \ +{ \ + return a OP CONSTANT; \ +} \ + +FOO (v8hf, add, +); +FOO (v16hf, add, +); +FOO (v32hf, add, +); +FOO (v8hf, sub, -); +FOO (v16hf, sub, -); +FOO (v32hf, sub, -); +FOO (v8hf, mul, *); +FOO (v16hf, mul, *); +FOO (v32hf, mul, *); +FOO (v8hf, div, /); +FOO (v16hf, div, /); +FOO (v32hf, div, /); diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-broadcast-2.c b/gcc/testsuite/gcc.target/i386/avx512fp16-broadcast-2.c new file mode 100644 index 0000000..016e0ea --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-broadcast-2.c @@ -0,0 +1,53 @@ +/* PR target/87767 */ +/* { dg-do run } */ +/* { dg-options "-O1 -mavx512fp16 -mavx512dq -mavx512vl" } */ +/* { dg-require-effective-target avx512dq } */ +/* { dg-require-effective-target avx512vl } */ +/* { dg-require-effective-target avx512fp16 } */ + +#define AVX512DQ +#define AVX512VL +#define AVX512FP16 +#include "avx512f-helper.h" + +#include "avx512fp16-broadcast-1.c" + +#define RTEST(VTYPE, TYPE, N, OP_NAME, OP) \ + do \ + { \ + TYPE exp[N], src[N]; \ + VTYPE res; \ + for (int i = 0; i < N; i++) \ + src[i] = 2.0 * i - 8.4; \ + res = foo_##OP_NAME##_##VTYPE (*(VTYPE*)&src[0]); \ + for (int i = 0; i < N; i ++) \ + exp[i] = src[i] OP CONSTANT; \ + for (int j = 0; j < N; j++) \ + { \ + if (res[j] != exp[j]) \ + abort(); \ + } \ + } \ + while (0) + +void +test_256 (void) +{ + RTEST (v8hf, _Float16, 8, add, +); + RTEST (v16hf, _Float16, 16, add, +); + RTEST (v32hf, _Float16, 32, add, +); + RTEST (v8hf, _Float16, 8, sub, -); + RTEST (v16hf, _Float16, 16, sub, -); + RTEST (v32hf, _Float16, 32, sub, -); + RTEST (v8hf, _Float16, 8, mul, *); + RTEST (v16hf, _Float16, 16, mul, *); + RTEST (v32hf, _Float16, 32, mul, *); + RTEST (v8hf, _Float16, 8, div, /); + RTEST (v16hf, _Float16, 16, div, /); + RTEST (v32hf, _Float16, 32, div, /); +} + +void +test_128 (void) +{ +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-neg-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-neg-1a.c new file mode 100644 index 0000000..bf7693e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-neg-1a.c @@ -0,0 +1,19 @@ +/* { dg-do compile} */ +/* { dg-options "-O2 -mavx512fp16" } */ + +/* { dg-final { scan-assembler-times "vpxord\[ \\t\]+\[^\n\r\]*%zmm0" 1 } } */ +/* { dg-final { scan-assembler-times "vxorps\[ \\t\]+\[^\n\r\]*%xmm0" 1 } } */ + +#include<immintrin.h> + +_Float16 +neghf (_Float16 a) +{ + return -a; +} + +__m512h +neghf512 (__m512h a) +{ + return -a; +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-neg-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-neg-1b.c new file mode 100644 index 0000000..770f7b2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-neg-1b.c @@ -0,0 +1,33 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +static void +test_512 (void) +{ + V512 v1, v2, v3, v4, exp, res; + int i; + init_src(); + + unpack_ph_2twops(src1, &v1, &v2); + v1.f32[0] = -v1.f32[0]; + exp = pack_twops_2ph(v1, v2); + res.zmmh = src1.zmmh; + res.f16[0] = -res.f16[0]; + check_results(&res, &exp, 32, "neg"); + + unpack_ph_2twops(src1, &v1, &v2); + for (i=0; i<16; i++) + { + v1.f32[i] = -v1.f32[i]; + v2.f32[i] = -v2.f32[i]; + } + exp = pack_twops_2ph(v1, v2); + res.zmmh = -src1.zmmh; + check_results(&res, &exp, 32, "neg"); + if (n_errs != 0) { + abort (); + } +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-scalar-bitwise-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-scalar-bitwise-1a.c new file mode 100644 index 0000000..a9e45fb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-scalar-bitwise-1a.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -mavx512fp16 -mavx512vl" } */ + +_Float16 +f1 (_Float16 x) +{ + return __builtin_fabsf16 (x); +} + +_Float16 +f2 (_Float16 x, _Float16 y) +{ + return __builtin_copysignf16 (x, y); +} + +_Float16 +f3 (_Float16 x) +{ + return -x; +} + +_Float16 +f4 (_Float16 x, _Float16 y) +{ + return x * __builtin_copysignf16 (1, y); +} + + +/* { dg-final { scan-assembler-times "vandps\[^\n\r\]*xmm\[0-9\]" 1 } } */ +/* { dg-final { scan-assembler-times "vpternlogd\[^\n\r\]*xmm\[0-9\]" 2 } } */ +/* { dg-final { scan-assembler-times "vxorps\[^\n\r\]*xmm\[0-9\]" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-scalar-bitwise-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-scalar-bitwise-1b.c new file mode 100644 index 0000000..7a29251 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-scalar-bitwise-1b.c @@ -0,0 +1,82 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-Ofast -mavx512fp16 -mavx512dq" } */ + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +void NOINLINE +emulate_absneg_ph (V512 * dest, V512 op1, int abs) +{ + V512 v1, v2, v3, v4; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(*dest, &v3, &v4); + + for (i = 0; i != 16; i++) { + if (abs) { + v3.f32[i] = __builtin_fabsf (v1.f32[i]); + v4.f32[i] = __builtin_fabsf (v2.f32[i]); + } + else { + v3.f32[i] = -v1.f32[i]; + v4.f32[i] = -v2.f32[i]; + } + } + *dest = pack_twops_2ph(v3, v4); +} + +void NOINLINE +emulate_copysign_ph (V512 * dest, V512 op1, V512 op2, int xorsign) +{ + V512 v1, v2, v3, v4, v5, v6; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v5, &v6); + + for (i = 0; i != 16; i++) { + if (xorsign) { + v5.f32[i] = v1.f32[i] * __builtin_copysignf (1, v3.f32[i]); + v6.f32[i] = v2.f32[i] * __builtin_copysignf (1, v4.f32[i]); + } + else { + v5.f32[i] = __builtin_copysignf (v1.f32[i], v3.f32[i]); + v6.f32[i] = __builtin_copysignf (v2.f32[i], v4.f32[i]); + } + } + *dest = pack_twops_2ph(v5, v6); +} + +void +test_512 (void) +{ + V512 res, exp; + + init_src (); + + /* Abs for float16. */ + emulate_absneg_ph (&exp, src1, 1); + res.f16[0] = __builtin_fabsf16 (src1.f16[0]); + check_results (&res, &exp, 1, "abs_float16"); + + /* Neg for float16. */ + emulate_absneg_ph (&exp, src1, 0); + res.f16[0] = -(src1.f16[0]); + check_results (&res, &exp, 1, "neg_float16"); + + /* Copysign for float16. */ + emulate_copysign_ph (&exp, src1, src2, 0); + res.f16[0] = __builtin_copysignf16 (src1.f16[0], src2.f16[0]); + check_results (&res, &exp, 1, "copysign_float16"); + + /* Xorsign for float16. */ + emulate_copysign_ph (&exp, src1, src2, 1); + res.f16[0] = src1.f16[0] * __builtin_copysignf16 (1, src2.f16[0]); + check_results (&res, &exp, 1, "xorsign_float16"); + + if (n_errs != 0) { + abort (); + } +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vector-bitwise-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vector-bitwise-1a.c new file mode 100644 index 0000000..758aec1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vector-bitwise-1a.c @@ -0,0 +1,121 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -mavx512vl -mavx512fp16 -mprefer-vector-width=512" } */ + +#include<immintrin.h> +__m128h +f1 (__m128h x) +{ + int i = 0; + __m128h y; + for (; i != 8; i++) + y[i] = __builtin_fabsf16 (x[i]); + return y; +} + +__m256h +f2 (__m256h x) +{ + int i = 0; + __m256h y; + for (; i != 16; i++) + y[i] = __builtin_fabsf16 (x[i]); + return y; +} + +__m512h +f3 (__m512h x) +{ + int i = 0; + __m512h y; + for (; i != 32; i++) + y[i] = __builtin_fabsf16 (x[i]); + return y; +} + +__m128h +f4 (__m128h x) +{ + return -x; +} + +__m256h +f5 (__m256h x) +{ + return -x; +} + +__m512h +f6 (__m512h x) +{ + return -x; +} + +__m128h +f7 (__m128h x, __m128h y) +{ + int i = 0; + __m128h z; + for (; i != 8; i++) + z[i] = __builtin_copysignf16 (x[i], y[i]); + return z; +} + +__m256h +f8 (__m256h x, __m256h y) +{ + int i = 0; + __m256h z; + for (; i != 16; i++) + z[i] = __builtin_copysignf16 (x[i], y[i]); + return z; +} + +__m512h +f9 (__m512h x, __m512h y) +{ + int i = 0; + __m512h z; + for (; i != 32; i++) + z[i] = __builtin_copysignf16 (x[i], y[i]); + return z; +} + +__m128h +f10 (__m128h x, __m128h y) +{ + int i = 0; + __m128h z; + for (; i != 8; i++) + z[i] = x[i] * __builtin_copysignf16 (1, y[i]); + return z; +} + +__m256h +f11 (__m256h x, __m256h y) +{ + int i = 0; + __m256h z; + for (; i != 16; i++) + z[i] = x[i] * __builtin_copysignf16 (1, y[i]); + return z; +} + +__m512h +f12 (__m512h x, __m512h y) +{ + int i = 0; + __m512h z; + for (; i != 32; i++) + z[i] = x[i] * __builtin_copysignf16 (1, y[i]); + return z; +} + +/* { dg-final { scan-assembler "vandps\[^\n\r\]*xmm0" } } */ +/* { dg-final { scan-assembler "vandps\[^\n\r\]*ymm0" } } */ +/* { dg-final { scan-assembler "vpandd\[^\n\r\]*zmm0" } } */ +/* { dg-final { scan-assembler-times "vxorps\[^\n\r\]*xmm0" 1 } } */ +/* { dg-final { scan-assembler-times "vxorps\[^\n\r\]*ymm0" 1 } } */ +/* { dg-final { scan-assembler-times "vpxord\[^\n\r\]*zmm0" 1 } } */ +/* { dg-final { scan-assembler-times "vpternlogd\[^\n\r\]*xmm\[0-9\]" 2 } } */ +/* { dg-final { scan-assembler-times "vpternlogd\[^\n\r\]*ymm\[0-9\]" 2 } } */ +/* { dg-final { scan-assembler-times "vpternlogd\[^\n\r\]*zmm\[0-9\]" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vector-bitwise-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vector-bitwise-1b.c new file mode 100644 index 0000000..1398b36 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vector-bitwise-1b.c @@ -0,0 +1,119 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-Ofast -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +void NOINLINE +emulate_absneg_ph (V512 * dest, V512 op1, int abs) +{ + V512 v1, v2, v3, v4; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(*dest, &v3, &v4); + + for (i = 0; i != 16; i++) { + if (abs) { + v3.f32[i] = __builtin_fabsf (v1.f32[i]); + v4.f32[i] = __builtin_fabsf (v2.f32[i]); + } + else { + v3.f32[i] = -v1.f32[i]; + v4.f32[i] = -v2.f32[i]; + } + } + *dest = pack_twops_2ph(v3, v4); +} + +void NOINLINE +emulate_copysign_ph (V512 * dest, V512 op1, V512 op2, int xorsign) +{ + V512 v1, v2, v3, v4, v5, v6; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v5, &v6); + + for (i = 0; i != 16; i++) { + if (xorsign) { + v5.f32[i] = v1.f32[i] * __builtin_copysignf (1, v3.f32[i]); + v6.f32[i] = v2.f32[i] * __builtin_copysignf (1, v4.f32[i]); + } + else { + v5.f32[i] = __builtin_copysignf (v1.f32[i], v3.f32[i]); + v6.f32[i] = __builtin_copysignf (v2.f32[i], v4.f32[i]); + } + } + *dest = pack_twops_2ph(v5, v6); +} + + +void +test_512 (void) +{ + V512 res, exp; + + init_src (); + + /* Abs for vector float16. */ + emulate_absneg_ph (&exp, src1, 1); + for (int i = 0; i != 8; i++) + res.f16[i] = __builtin_fabsf16 (src1.f16[i]); + check_results (&res, &exp, 8, "abs_m128h"); + + for (int i = 0; i != 16; i++) + res.f16[i] = __builtin_fabsf16 (src1.f16[i]); + check_results (&res, &exp, 16, "abs_m256h"); + + for (int i = 0; i != 32; i++) + res.f16[i] = __builtin_fabsf16 (src1.f16[i]); + check_results (&res, &exp, 32, "abs_m512h"); + + /* Neg for vector float16. */ + emulate_absneg_ph (&exp, src1, 0); + for (int i = 0; i != 8; i++) + res.f16[i] = -(src1.f16[i]); + check_results (&res, &exp, 8, "neg_m128h"); + + for (int i = 0; i != 16; i++) + res.f16[i] = -(src1.f16[i]); + check_results (&res, &exp, 16, "neg_m256h"); + + for (int i = 0; i != 32; i++) + res.f16[i] = -(src1.f16[i]); + check_results (&res, &exp, 32, "neg_m512h"); + + /* Copysign for vector float16. */ + emulate_copysign_ph (&exp, src1, src2, 0); + for (int i = 0; i != 8; i++) + res.f16[i] = __builtin_copysignf16 (src1.f16[i], src2.f16[i]); + check_results (&res, &exp, 8, "copysign_m128h"); + + for (int i = 0; i != 16; i++) + res.f16[i] = __builtin_copysignf16 (src1.f16[i], src2.f16[i]); + check_results (&res, &exp, 16, "copysign_m256h"); + + for (int i = 0; i != 32; i++) + res.f16[i] = __builtin_copysignf16 (src1.f16[i], src2.f16[i]); + check_results (&res, &exp, 32, "copysign_m512h"); + + /* Xorsign for vector float16. */ + emulate_copysign_ph (&exp, src1, src2, 1); + for (int i = 0; i != 8; i++) + res.f16[i] = src1.f16[i] * __builtin_copysignf16 (1, src2.f16[i]); + check_results (&res, &exp, 8, "xorsign_m128h"); + + for (int i = 0; i != 16; i++) + res.f16[i] = src1.f16[i] * __builtin_copysignf16 (1, src2.f16[i]); + check_results (&res, &exp, 16, "xorsign_m256h"); + + for (int i = 0; i != 32; i++) + res.f16[i] = src1.f16[i] * __builtin_copysignf16 (1, src2.f16[i]); + check_results (&res, &exp, 32, "xorsign_m512h"); + + if (n_errs != 0) { + abort (); + } +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXph-1a.c new file mode 100644 index 0000000..f9e2777 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmadd231ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd231ph\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m512h x1, x2, x3; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x1 = _mm512_fmadd_ph (x1, x2, x3); + x1 = _mm512_mask_fmadd_ph (x1, m, x2, x3); + x3 = _mm512_mask3_fmadd_ph (x1, x2, x3, m); + x1 = _mm512_maskz_fmadd_ph (m, x1, x2, x3); + x1 = _mm512_fmadd_round_ph (x1, x2, x3, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + x1 = _mm512_mask_fmadd_round_ph (x1, m, x2, x3, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + x3 = _mm512_mask3_fmadd_round_ph (x1, x2, x3, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + x1 = _mm512_maskz_fmadd_round_ph (m, x1, x2, x3, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXph-1b.c new file mode 100644 index 0000000..71c2b8f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXph-1b.c @@ -0,0 +1,160 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS (AVX512F_LEN / 16) + +void NOINLINE +EMULATE(fmadd_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = v1.f32[i] * v3.f32[i] + v7.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = v2.f32[i] * v4.f32[i] + v8.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void NOINLINE +EMULATE(m_fmadd_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = v7.f32[i] * v1.f32[i] + v3.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = v8.f32[i] * v2.f32[i] + v4.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void +TEST (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + EMULATE(fmadd_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmadd_ph) (HF(src1), HF(src2), + HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmadd_ph); + + init_dest(&res, &exp); + EMULATE(m_fmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmadd_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2)); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmadd_ph); + + init_dest(&res, &exp); + EMULATE(fmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmadd_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmadd_ph); + + init_dest(&res, &exp); + EMULATE(fmadd_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmadd_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmadd_ph); + +#if AVX512F_LEN == 512 + init_dest(&res, &exp); + EMULATE(fmadd_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmadd_round_ph) (HF(src1), HF(src2), + HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmadd_ph); + + init_dest(&res, &exp); + EMULATE(m_fmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmadd_round_ph) (HF(res), MASK_VALUE, HF(src1), + HF(src2), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmadd_ph); + + EMULATE(fmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmadd_round_ph) (HF(src1), HF(src2), HF(res), + MASK_VALUE, _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmadd_ph); + + init_dest(&res, &exp); + EMULATE(fmadd_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmadd_round_ph) (ZMASK_VALUE, HF(src1), HF(src2), + HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmadd_ph); +#endif + + if (n_errs != 0) { + abort (); + } +} + + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXsh-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXsh-1a.c new file mode 100644 index 0000000..472454d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXsh-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmadd...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmadd231sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...sh\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...sh\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd231sh\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...sh\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m128h a, b, c; +volatile __mmask8 m; + +void extern +avx512f_test (void) +{ + a = _mm_fmadd_sh (a, b, c); + a = _mm_mask_fmadd_sh (a, m, b, c); + c = _mm_mask3_fmadd_sh (a, b, c, m); + a = _mm_maskz_fmadd_sh (m, a, b, c); + a = _mm_fmadd_round_sh (a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + a = _mm_mask_fmadd_round_sh (a, m, b, c, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + c = _mm_mask3_fmadd_round_sh (a, b, c, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + a = _mm_maskz_fmadd_round_sh (m, a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXsh-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXsh-1b.c new file mode 100644 index 0000000..a0eca9c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddXXXsh-1b.c @@ -0,0 +1,90 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS 8 + +void NOINLINE +emulate_fmadd_sh(V512 * dest, V512 op1, V512 op2, + __mmask8 k, int zero_mask, int mask3) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + if ((k&1) || !k) + v5.f32[0] = v1.f32[0] * v3.f32[0] + v7.f32[0]; + else if (zero_mask) + v5.f32[0] = 0; + else + v5.f32[0] = v7.f32[0]; + + for (i = 1; i < 8; i++){ + if (mask3) + v5.f32[i] = v7.f32[i]; + else + v5.f32[i] = v1.f32[i]; + } + *dest = pack_twops_2ph(v5, v6); +} + +void +test_512 (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fmadd_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_fmadd_sh"); + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fmadd_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + 0x1); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fmadd_sh"); + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fmadd_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fmadd_sh"); + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fmadd_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fmadd_sh"); + + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fmadd_round_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_fmadd_sh"); + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fmadd_round_sh(src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], 0x1, _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fmadd_sh"); + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fmadd_round_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fmadd_sh"); + init_dest(&res, &exp); + emulate_fmadd_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fmadd_round_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fmadd_sh"); + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddsubXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddsubXXXph-1a.c new file mode 100644 index 0000000..7063646 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddsubXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub231ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub231ph\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m512h x1, x2, x3; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x1 = _mm512_fmaddsub_ph (x1, x2, x3); + x1 = _mm512_mask_fmaddsub_ph (x1, m, x2, x3); + x3 = _mm512_mask3_fmaddsub_ph (x1, x2, x3, m); + x1 = _mm512_maskz_fmaddsub_ph (m, x1, x2, x3); + x1 = _mm512_fmaddsub_round_ph (x1, x2, x3, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + x1 = _mm512_mask_fmaddsub_round_ph (x1, m, x2, x3, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + x3 = _mm512_mask3_fmaddsub_round_ph (x1, x2, x3, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + x1 = _mm512_maskz_fmaddsub_round_ph (m, x1, x2, x3, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddsubXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddsubXXXph-1b.c new file mode 100644 index 0000000..16cf0af1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmaddsubXXXph-1b.c @@ -0,0 +1,171 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS (AVX512F_LEN / 16) + +void NOINLINE +EMULATE(fmaddsub_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + if (i % 2 == 1) { + v5.f32[i] = v1.f32[i] * v3.f32[i] + v7.f32[i]; + } + else { + v5.f32[i] = v1.f32[i] * v3.f32[i] - v7.f32[i]; + } + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + if (i % 2 == 1) { + v6.f32[i] = v2.f32[i] * v4.f32[i] + v8.f32[i]; + } + else { + v6.f32[i] = v2.f32[i] * v4.f32[i] - v8.f32[i]; + } + } + } + *dest = pack_twops_2ph(v5, v6); +} + +void NOINLINE +EMULATE(m_fmaddsub_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + if (i % 2 == 1) { + v5.f32[i] = v1.f32[i] * v7.f32[i] + v3.f32[i]; + } + else { + v5.f32[i] = v1.f32[i] * v7.f32[i] - v3.f32[i]; + } + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + if (i % 2 == 1) { + v6.f32[i] = v2.f32[i] * v8.f32[i] + v4.f32[i]; + } + else { + v6.f32[i] = v2.f32[i] * v8.f32[i] - v4.f32[i]; + } + } + } + *dest = pack_twops_2ph(v5, v6); +} + +void +TEST (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + EMULATE(fmaddsub_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmaddsub_ph) (HF(src1), HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmaddsub_ph); + init_dest(&res, &exp); + EMULATE(fmaddsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmaddsub_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmaddsub_ph); + init_dest(&res, &exp); + EMULATE(m_fmaddsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmaddsub_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2)); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmaddsub_ph); + init_dest(&res, &exp); + EMULATE(fmaddsub_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmaddsub_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmaddsub_ph); + + init_dest(&res, &exp); +#if AVX512F_LEN == 512 + EMULATE(fmaddsub_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmaddsub_round_ph) (HF(src1), HF(src2), + HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmaddsub_ph); + init_dest(&res, &exp); + EMULATE(fmaddsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmaddsub_round_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE, _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmaddsub_ph); + init_dest(&res, &exp); + EMULATE(m_fmaddsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmaddsub_round_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmaddsub_ph); + init_dest(&res, &exp); + EMULATE(fmaddsub_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmaddsub_round_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmaddsub_ph); +#endif + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXph-1a.c new file mode 100644 index 0000000..3b1147a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXph-1a.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsub231ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub231ph\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m512h x1, x2, x3; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x1 = _mm512_fmsub_ph (x1, x2, x3); + x1 = _mm512_mask_fmsub_ph (x1, m, x2, x3); + x3 = _mm512_mask3_fmsub_ph (x1, x2, x3, m); + x1 = _mm512_maskz_fmsub_ph (m, x1, x2, x3); + x1 = _mm512_fmsub_round_ph (x1, x2, x3, _MM_FROUND_TO_NEAREST_INT + | _MM_FROUND_NO_EXC); + x1 = _mm512_mask_fmsub_round_ph (x1, m, x2, x3, _MM_FROUND_TO_NEG_INF + | _MM_FROUND_NO_EXC); + x3 = _mm512_mask3_fmsub_round_ph (x1, x2, x3, m, _MM_FROUND_TO_POS_INF + | _MM_FROUND_NO_EXC); + x1 = _mm512_maskz_fmsub_round_ph (m, x1, x2, x3, _MM_FROUND_TO_ZERO + | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXph-1b.c new file mode 100644 index 0000000..abb9a9b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXph-1b.c @@ -0,0 +1,155 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS (AVX512F_LEN / 16) + +void NOINLINE +EMULATE(fmsub_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = v1.f32[i] * v3.f32[i] - v7.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = v2.f32[i] * v4.f32[i] - v8.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void NOINLINE +EMULATE(m_fmsub_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = v7.f32[i] * v1.f32[i] - v3.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = v8.f32[i] * v2.f32[i] - v4.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void +TEST (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + EMULATE(fmsub_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmsub_ph) (HF(src1), HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmsub_ph); + + init_dest(&res, &exp); + EMULATE(m_fmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmsub_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2)); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmsub_ph); + + init_dest(&res, &exp); + EMULATE(fmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmsub_ph) (HF(src1), HF(src2), HF(res), MASK_VALUE); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmsub_ph); + + init_dest(&res, &exp); + EMULATE(fmsub_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmsub_ph) (ZMASK_VALUE, HF(src1), HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmsub_ph); + +#if AVX512F_LEN == 512 + init_dest(&res, &exp); + EMULATE(fmsub_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmsub_round_ph) (HF(src1), HF(src2), HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmsub_ph); + + init_dest(&res, &exp); + EMULATE(m_fmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmsub_round_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmsub_ph); + + EMULATE(fmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmsub_round_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE, _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmsub_ph); + + init_dest(&res, &exp); + EMULATE(fmsub_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmsub_round_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmsub_ph); +#endif + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXsh-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXsh-1a.c new file mode 100644 index 0000000..335b9e2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXsh-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmsub...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsub231sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...sh\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...sh\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub231sh\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...sh\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m128h a, b, c; +volatile __mmask8 m; + +void extern +avx512f_test (void) +{ + a = _mm_fmsub_sh (a, b, c); + a = _mm_mask_fmsub_sh (a, m, b, c); + c = _mm_mask3_fmsub_sh (a, b, c, m); + a = _mm_maskz_fmsub_sh (m, a, b, c); + a = _mm_fmsub_round_sh (a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + a = _mm_mask_fmsub_round_sh (a, m, b, c, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + c = _mm_mask3_fmsub_round_sh (a, b, c, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + a = _mm_maskz_fmsub_round_sh (m, a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXsh-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXsh-1b.c new file mode 100644 index 0000000..a2563fa --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubXXXsh-1b.c @@ -0,0 +1,89 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS 8 + +void NOINLINE +emulate_fmsub_sh(V512 * dest, V512 op1, V512 op2, + __mmask8 k, int zero_mask, int mask3) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + if ((k&1) || !k) + v5.f32[0] = v1.f32[0] * v3.f32[0] - v7.f32[0]; + else if (zero_mask) + v5.f32[0] = 0; + else + v5.f32[0] = v7.f32[0]; + for (i = 1; i < 8; i++){ + if (mask3) + v5.f32[i] = v7.f32[i]; + else + v5.f32[i] = v1.f32[i]; + } + *dest = pack_twops_2ph(v5, v6); +} + +void +test_512 (void) +{ + V512 res; + V512 exp; + + init_src(); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fmsub_sh(src1.xmmh[0], + src2.xmmh[0], res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_fmsub_sh"); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fmsub_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + 0x1); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fmsub_sh"); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fmsub_sh(src1.xmmh[0], 0x1, src2.xmmh[0], res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fmsub_sh"); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fmsub_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fmsub_sh"); + + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fmsub_round_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_fmsub_sh"); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fmsub_round_sh(src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], 0x1, _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fmsub_sh"); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fmsub_round_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fmsub_sh"); + init_dest(&res, &exp); + emulate_fmsub_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fmsub_round_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fmsub_sh"); + + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubaddXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubaddXXXph-1a.c new file mode 100644 index 0000000..87087c9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubaddXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd231ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd231ph\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m512h x1, x2, x3; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x1 = _mm512_fmsubadd_ph (x1, x2, x3); + x1 = _mm512_mask_fmsubadd_ph (x1, m, x2, x3); + x3 = _mm512_mask3_fmsubadd_ph (x1, x2, x3, m); + x1 = _mm512_maskz_fmsubadd_ph (m, x1, x2, x3); + x1 = _mm512_fmsubadd_round_ph (x1, x2, x3, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + x1 = _mm512_mask_fmsubadd_round_ph (x1, m, x2, x3, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + x3 = _mm512_mask3_fmsubadd_round_ph (x1, x2, x3, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + x1 = _mm512_maskz_fmsubadd_round_ph (m, x1, x2, x3, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubaddXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubaddXXXph-1b.c new file mode 100644 index 0000000..159cae4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfmsubaddXXXph-1b.c @@ -0,0 +1,175 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS (AVX512F_LEN / 16) + +void NOINLINE +EMULATE(fmsubadd_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + if (i % 2 == 1) { + v5.f32[i] = v1.f32[i] * v3.f32[i] - v7.f32[i]; + } + else { + v5.f32[i] = v1.f32[i] * v3.f32[i] + v7.f32[i]; + } + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + if (i % 2 == 1) { + v6.f32[i] = v2.f32[i] * v4.f32[i] - v8.f32[i]; + } + else { + v6.f32[i] = v2.f32[i] * v4.f32[i] + v8.f32[i]; + } + } + } + *dest = pack_twops_2ph(v5, v6); +} + +void NOINLINE +EMULATE(m_fmsubadd_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + if (i % 2 == 1) { + v5.f32[i] = v1.f32[i] * v7.f32[i] - v3.f32[i]; + } + else { + v5.f32[i] = v1.f32[i] * v7.f32[i] + v3.f32[i]; + } + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + if (i % 2 == 1) { + v6.f32[i] = v2.f32[i] * v8.f32[i] - v4.f32[i]; + } + else { + v6.f32[i] = v2.f32[i] * v8.f32[i] + v4.f32[i]; + } + } + } + *dest = pack_twops_2ph(v5, v6); +} + +void +TEST (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + EMULATE(fmsubadd_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmsubadd_ph) (HF(src1), HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmsubadd_ph); + init_dest(&res, &exp); + EMULATE(fmsubadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmsubadd_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmsubadd_ph); + init_dest(&res, &exp); + EMULATE(m_fmsubadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmsubadd_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2)); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmsubadd_ph); + init_dest(&res, &exp); + EMULATE(fmsubadd_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmsubadd_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmsubadd_ph); + + init_dest(&res, &exp); +#if AVX512F_LEN == 512 + EMULATE(fmsubadd_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fmsubadd_round_ph) (HF(src1), HF(src2), + HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _fmsubadd_ph); + init_dest(&res, &exp); + EMULATE(fmsubadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fmsubadd_round_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE, + _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fmsubadd_ph); + init_dest(&res, &exp); + EMULATE(m_fmsubadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fmsubadd_round_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2), + _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fmsubadd_ph); + init_dest(&res, &exp); + EMULATE(fmsubadd_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fmsubadd_round_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res), + _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fmsubadd_ph); +#endif + + if (n_errs != 0) { + abort (); + } +} + + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXph-1a.c new file mode 100644 index 0000000..20e77ce --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmadd231ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd231ph\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m512h x1, x2, x3; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x1 = _mm512_fnmadd_ph (x1, x2, x3); + x1 = _mm512_mask_fnmadd_ph (x1, m, x2, x3); + x3 = _mm512_mask3_fnmadd_ph (x1, x2, x3, m); + x1 = _mm512_maskz_fnmadd_ph (m, x1, x2, x3); + x1 = _mm512_fnmadd_round_ph (x1, x2, x3, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + x1 = _mm512_mask_fnmadd_round_ph (x1, m, x2, x3, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + x3 = _mm512_mask3_fnmadd_round_ph (x1, x2, x3, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + x1 = _mm512_maskz_fnmadd_round_ph (m, x1, x2, x3, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXph-1b.c new file mode 100644 index 0000000..b15b1bd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXph-1b.c @@ -0,0 +1,159 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS (AVX512F_LEN / 16) + +void NOINLINE +EMULATE(fnmadd_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = -(v1.f32[i] * v3.f32[i]) + v7.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = -(v2.f32[i] * v4.f32[i]) + v8.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void NOINLINE +EMULATE(m_fnmadd_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = -(v1.f32[i] * v7.f32[i]) + v3.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = -(v2.f32[i] * v8.f32[i]) + v4.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void +TEST (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + EMULATE(fnmadd_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fnmadd_ph) (HF(src1), HF(src2), + HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _fnmadd_ph); + + init_dest(&res, &exp); + EMULATE(m_fnmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fnmadd_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2)); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fnmadd_ph); + + init_dest(&res, &exp); + EMULATE(fnmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fnmadd_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fnmadd_ph); + + init_dest(&res, &exp); + EMULATE(fnmadd_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fnmadd_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fnmadd_ph); + +#if AVX512F_LEN == 512 + init_dest(&res, &exp); + EMULATE(fnmadd_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fnmadd_round_ph) (HF(src1), HF(src2), + HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _fnmadd_ph); + + init_dest(&res, &exp); + EMULATE(m_fnmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fnmadd_round_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fnmadd_ph); + + EMULATE(fnmadd_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fnmadd_round_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE, _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fnmadd_ph); + + init_dest(&res, &exp); + EMULATE(fnmadd_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fnmadd_round_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fnmadd_ph); +#endif + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXsh-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXsh-1a.c new file mode 100644 index 0000000..77106aa --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXsh-1a.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfnmadd...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmadd231sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...sh\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...sh\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd231sh\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...sh\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m128h a, b, c; +volatile __mmask8 m; + +void extern +avx512f_test (void) +{ + a = _mm_fnmadd_sh (a, b, c); + a = _mm_mask_fnmadd_sh (a, m, b, c); + c = _mm_mask3_fnmadd_sh (a, b, c, m); + a = _mm_maskz_fnmadd_sh (m, a, b, c); + a = _mm_fnmadd_round_sh (a, b, c, _MM_FROUND_TO_NEAREST_INT + | _MM_FROUND_NO_EXC); + a = _mm_mask_fnmadd_round_sh (a, m, b, c, _MM_FROUND_TO_NEG_INF + | _MM_FROUND_NO_EXC); + c = _mm_mask3_fnmadd_round_sh (a, b, c, m, _MM_FROUND_TO_POS_INF + | _MM_FROUND_NO_EXC); + a = _mm_maskz_fnmadd_round_sh (m, a, b, c, _MM_FROUND_TO_ZERO + | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXsh-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXsh-1b.c new file mode 100644 index 0000000..9200150 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmaddXXXsh-1b.c @@ -0,0 +1,90 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS 8 + +void NOINLINE +emulate_fnmadd_sh(V512 * dest, V512 op1, V512 op2, + __mmask8 k, int zero_mask, int mask3) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + if ((k&1) || !k) + v5.f32[0] = -(v1.f32[0] * v3.f32[0]) + v7.f32[0]; + else if (zero_mask) + v5.f32[0] = 0; + else + v5.f32[0] = v7.f32[0]; + + for (i = 1; i < 8; i++){ + if (mask3) + v5.f32[i] = v7.f32[i]; + else + v5.f32[i] = v1.f32[i]; + } + *dest = pack_twops_2ph(v5, v6); +} + +void +test_512 (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fnmadd_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_fnmadd_sh"); + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fnmadd_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + 0x1); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fnmadd_sh"); + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fnmadd_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fnmadd_sh"); + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fnmadd_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fnmadd_sh"); + + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fnmadd_round_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_fnmadd_sh"); + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fnmadd_round_sh(src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], 0x1, _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fnmadd_sh"); + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fnmadd_round_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fnmadd_sh"); + init_dest(&res, &exp); + emulate_fnmadd_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fnmadd_round_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fnmadd_sh"); + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXph-1a.c new file mode 100644 index 0000000..eb05de4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXph-1a.c @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmsub231ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub231ph\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m512h x1, x2, x3; +volatile __mmask32 m; + +void extern +avx512f_test (void) +{ + x1 = _mm512_fnmsub_ph (x1, x2, x3); + x1 = _mm512_mask_fnmsub_ph (x1, m, x2, x3); + x3 = _mm512_mask3_fnmsub_ph (x1, x2, x3, m); + x1 = _mm512_maskz_fnmsub_ph (m, x1, x2, x3); + x1 = _mm512_fnmsub_round_ph (x1, x2, x3, _MM_FROUND_TO_NEAREST_INT + | _MM_FROUND_NO_EXC); + x1 = _mm512_mask_fnmsub_round_ph (x1, m, x2, x3, _MM_FROUND_TO_NEG_INF + | _MM_FROUND_NO_EXC); + x3 = _mm512_mask3_fnmsub_round_ph (x1, x2, x3, m, _MM_FROUND_TO_POS_INF + | _MM_FROUND_NO_EXC); + x1 = _mm512_maskz_fnmsub_round_ph (m, x1, x2, x3, _MM_FROUND_TO_ZERO + | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXph-1b.c new file mode 100644 index 0000000..73f0172 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXph-1b.c @@ -0,0 +1,157 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS (AVX512F_LEN / 16) + +void NOINLINE +EMULATE(fnmsub_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = -(v1.f32[i] * v3.f32[i]) - v7.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = -(v2.f32[i] * v4.f32[i]) - v8.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void NOINLINE +EMULATE(m_fnmsub_ph) (V512 * dest, V512 op1, V512 op2, + __mmask32 k, int zero_mask) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + __mmask16 m1, m2; + + m1 = k & 0xffff; + m2 = (k >> 16) & 0xffff; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + for (i = 0; i < 16; i++) { + if (((1 << i) & m1) == 0) { + if (zero_mask) { + v5.f32[i] = 0; + } + else { + v5.u32[i] = v7.u32[i]; + } + } + else { + v5.f32[i] = -(v1.f32[i] * v7.f32[i]) - v3.f32[i]; + } + + if (((1 << i) & m2) == 0) { + if (zero_mask) { + v6.f32[i] = 0; + } + else { + v6.u32[i] = v8.u32[i]; + } + } + else { + v6.f32[i] = -(v2.f32[i] * v8.f32[i]) - v4.f32[i]; + } + + } + *dest = pack_twops_2ph(v5, v6); +} + +void +TEST (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + EMULATE(fnmsub_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fnmsub_ph) (HF(src1), HF(src2), + HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _fnmsub_ph); + + init_dest(&res, &exp); + EMULATE(m_fnmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fnmsub_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2)); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fnmsub_ph); + + init_dest(&res, &exp); + EMULATE(fnmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fnmsub_ph) (HF(src1), HF(src2), HF(res), MASK_VALUE); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fnmsub_ph); + + init_dest(&res, &exp); + EMULATE(fnmsub_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fnmsub_ph) (ZMASK_VALUE, HF(src1), HF(src2), HF(res)); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fnmsub_ph); + +#if AVX512F_LEN == 512 + init_dest(&res, &exp); + EMULATE(fnmsub_ph)(&exp, src1, src2, NET_MASK, 0); + HF(res) = INTRINSIC (_fnmsub_round_ph) (HF(src1), HF(src2), + HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _fnmsub_ph); + + init_dest(&res, &exp); + EMULATE(m_fnmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask_fnmsub_round_ph) (HF(res), MASK_VALUE, + HF(src1), HF(src2), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask_fnmsub_ph); + + EMULATE(fnmsub_ph)(&exp, src1, src2, MASK_VALUE, 0); + HF(res) = INTRINSIC (_mask3_fnmsub_round_ph) (HF(src1), HF(src2), + HF(res), MASK_VALUE, _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _mask3_fnmsub_ph); + + init_dest(&res, &exp); + EMULATE(fnmsub_ph)(&exp, src1, src2, ZMASK_VALUE, 1); + HF(res) = INTRINSIC (_maskz_fnmsub_round_ph) (ZMASK_VALUE, HF(src1), + HF(src2), HF(res), _ROUND_NINT); + CHECK_RESULT (&res, &exp, N_ELEMS, _maskz_fnmsub_ph); +#endif + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXsh-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXsh-1a.c new file mode 100644 index 0000000..5d14608 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXsh-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfnmsub...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmsub231sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...sh\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...sh\[ \\t\]+\[^\n\]*\{rn-sae\}\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...sh\[ \\t\]+\[^\n\]*\{rd-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub231sh\[ \\t\]+\[^\n\]*\{ru-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...sh\[ \\t\]+\[^\n\]*\{rz-sae\}\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m128h a, b, c; +volatile __mmask8 m; + +void extern +avx512f_test (void) +{ + a = _mm_fnmsub_sh (a, b, c); + a = _mm_mask_fnmsub_sh (a, m, b, c); + c = _mm_mask3_fnmsub_sh (a, b, c, m); + a = _mm_maskz_fnmsub_sh (m, a, b, c); + a = _mm_fnmsub_round_sh (a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + a = _mm_mask_fnmsub_round_sh (a, m, b, c, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + c = _mm_mask3_fnmsub_round_sh (a, b, c, m, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + a = _mm_maskz_fnmsub_round_sh (m, a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXsh-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXsh-1b.c new file mode 100644 index 0000000..7bdb861 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-vfnmsubXXXsh-1b.c @@ -0,0 +1,90 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512dq" } */ + + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +#define N_ELEMS 8 + +void NOINLINE +emulate_fnmsub_sh(V512 * dest, V512 op1, V512 op2, + __mmask8 k, int zero_mask, int mask3) +{ + V512 v1, v2, v3, v4, v5, v6, v7, v8; + int i; + + unpack_ph_2twops(op1, &v1, &v2); + unpack_ph_2twops(op2, &v3, &v4); + unpack_ph_2twops(*dest, &v7, &v8); + + if ((k&1) || !k) + v5.f32[0] = -(v1.f32[0] * v3.f32[0]) - v7.f32[0]; + else if (zero_mask) + v5.f32[0] = 0; + else + v5.f32[0] = v7.f32[0]; + + for (i = 1; i < 8; i++){ + if (mask3) + v5.f32[i] = v7.f32[i]; + else + v5.f32[i] = v1.f32[i]; + } + *dest = pack_twops_2ph(v5, v6); +} + +void +test_512 (void) +{ + V512 res; + V512 exp; + + init_src(); + + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fnmsub_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_fnmsub_sh"); + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fnmsub_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + 0x1); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fnmsub_sh"); + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fnmsub_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fnmsub_sh"); + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fnmsub_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0]); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fnmsub_sh"); + + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_fnmsub_round_sh(src1.xmmh[0], src2.xmmh[0], res.xmmh[0], + _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_fnmsub_sh"); + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x1, 0, 1); + res.xmmh[0] = _mm_mask3_fnmsub_round_sh(src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], 0x1, _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask3_fnmsub_sh"); + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x1, 0, 0); + res.xmmh[0] = _mm_mask_fnmsub_round_sh(src1.xmmh[0], 0x1, src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_mask_fnmsub_sh"); + init_dest(&res, &exp); + emulate_fnmsub_sh(&exp, src1, src2, 0x3, 1, 0); + res.xmmh[0] = _mm_maskz_fnmsub_round_sh(0x3, src1.xmmh[0], src2.xmmh[0], + res.xmmh[0], _ROUND_NINT); + check_results(&res, &exp, N_ELEMS, "_mm_maskz_fnmsub_sh"); + + if (n_errs != 0) { + abort (); + } +} + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16-xorsign-1.c b/gcc/testsuite/gcc.target/i386/avx512fp16-xorsign-1.c new file mode 100644 index 0000000..a22a6ce --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16-xorsign-1.c @@ -0,0 +1,41 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -ftree-vectorize -fdump-tree-vect-details -save-temps" } */ + +extern void abort (); + +static void do_test (void); + +#define DO_TEST do_test +#define AVX512FP16 +#include "avx512-check.h" + +#define N 16 +_Float16 a[N] = {-0.1f, -3.2f, -6.3f, -9.4f, + -12.5f, -15.6f, -18.7f, -21.8f, + 24.9f, 27.1f, 30.2f, 33.3f, + 36.4f, 39.5f, 42.6f, 45.7f}; +_Float16 b[N] = {-1.2f, 3.4f, -5.6f, 7.8f, + -9.0f, 1.0f, -2.0f, 3.0f, + -4.0f, -5.0f, 6.0f, 7.0f, + -8.0f, -9.0f, 10.0f, 11.0f}; +_Float16 r[N]; + +static void +__attribute__ ((noinline, noclone)) +do_test (void) +{ + int i; + + for (i = 0; i < N; i++) + r[i] = a[i] * __builtin_copysignf16 (1.0f, b[i]); + + /* check results: */ + for (i = 0; i < N; i++) + if (r[i] != a[i] * __builtin_copysignf16 (1.0f, b[i])) + abort (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ +/* { dg-final { scan-assembler "\[ \t\]xor" } } */ +/* { dg-final { scan-assembler "\[ \t\]and" } } */ +/* { dg-final { scan-assembler-not "copysign" } } */ diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-neg-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-neg-1a.c new file mode 100644 index 0000000..a40a0d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-neg-1a.c @@ -0,0 +1,18 @@ +/* { dg-do compile} */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl" } */ + +/* { dg-final { scan-assembler-times "vxorps\[ \\t\]+\[^\n\r\]*%xmm0" 1 } } */ +/* { dg-final { scan-assembler-times "vxorps\[ \\t\]+\[^\n\r\]*%ymm0" 1 } } */ +#include<immintrin.h> + +__m128h +neghf128 (__m128h a) +{ + return -a; +} + +__m256h +neghf256 (__m256h a) +{ + return -a; +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-neg-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-neg-1b.c new file mode 100644 index 0000000..d8f65fb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-neg-1b.c @@ -0,0 +1,33 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512FP16 +#include "avx512fp16-helper.h" + +static void +test_512 (void) +{ + V512 v1, v2, v3, v4, exp, res; + int i; + init_src(); + + unpack_ph_2twops(src1, &v1, &v2); + v1.f32[0] = -v1.f32[0]; + exp = pack_twops_2ph(v1, v2); + res.zmmh = src1.zmmh; + res.f16[0] = -res.f16[0]; + check_results(&res, &exp, 32, "neg"); + + unpack_ph_2twops(src1, &v1, &v2); + for (i=0; i<16; i++) + { + v1.f32[i] = -v1.f32[i]; + v2.f32[i] = -v2.f32[i]; + } + exp = pack_twops_2ph(v1, v2); + res.zmmh = -src1.zmmh; + check_results(&res, &exp, 32, "neg"); + if (n_errs != 0) { + abort (); + } +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddXXXph-1a.c new file mode 100644 index 0000000..eea38b8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmadd231ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd231ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmadd...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m256h yy, y2, y3; +volatile __m128h xx, x2, x3; +volatile __mmask8 m; +volatile __mmask16 m16; + +void extern +avx512vl_test (void) +{ + yy = _mm256_mask_fmadd_ph (yy, m16, y2, y3); + xx = _mm_mask_fmadd_ph (xx, m, x2, x3); + + y3 = _mm256_mask3_fmadd_ph (yy, y2, y3, m16); + x3 = _mm_mask3_fmadd_ph (xx, x2, x3, m); + + yy = _mm256_maskz_fmadd_ph (m16, yy, y2, y3); + xx = _mm_maskz_fmadd_ph (m, xx, x2, x3); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddXXXph-1b.c new file mode 100644 index 0000000..f6e4a9a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddXXXph-1b.c @@ -0,0 +1,15 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512VL +#define AVX512F_LEN 256 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmaddXXXph-1b.c" + +#undef AVX512F_LEN +#undef AVX512F_LEN_HALF + +#define AVX512F_LEN 128 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmaddXXXph-1b.c" + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1a.c new file mode 100644 index 0000000..963fbb6a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub231ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub231ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmaddsub...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m256h yy, y2, y3; +volatile __m128h xx, x2, x3; +volatile __mmask8 m; +volatile __mmask16 m16; + +void extern +avx512vl_test (void) +{ + yy = _mm256_mask_fmaddsub_ph (yy, m16, y2, y3); + xx = _mm_mask_fmaddsub_ph (xx, m, x2, x3); + + y3 = _mm256_mask3_fmaddsub_ph (yy, y2, y3, m16); + x3 = _mm_mask3_fmaddsub_ph (xx, x2, x3, m); + + yy = _mm256_maskz_fmaddsub_ph (m16, yy, y2, y3); + xx = _mm_maskz_fmaddsub_ph (m, xx, x2, x3); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1b.c new file mode 100644 index 0000000..7f9748b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmaddsubXXXph-1b.c @@ -0,0 +1,15 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512VL +#define AVX512F_LEN 256 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmaddsubXXXph-1b.c" + +#undef AVX512F_LEN +#undef AVX512F_LEN_HALF + +#define AVX512F_LEN 128 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmaddsubXXXph-1b.c" + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubXXXph-1a.c new file mode 100644 index 0000000..add1abc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsub231ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub231ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsub...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m256h yy, y2, y3; +volatile __m128h xx, x2, x3; +volatile __mmask8 m; +volatile __mmask16 m16; + +void extern +avx512vl_test (void) +{ + yy = _mm256_mask_fmsub_ph (yy, m16, y2, y3); + xx = _mm_mask_fmsub_ph (xx, m, x2, x3); + + y3 = _mm256_mask3_fmsub_ph (yy, y2, y3, m16); + x3 = _mm_mask3_fmsub_ph (xx, x2, x3, m); + + yy = _mm256_maskz_fmsub_ph (m16, yy, y2, y3); + xx = _mm_maskz_fmsub_ph (m, xx, x2, x3); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubXXXph-1b.c new file mode 100644 index 0000000..b9c2085 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubXXXph-1b.c @@ -0,0 +1,15 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512VL +#define AVX512F_LEN 256 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmsubXXXph-1b.c" + +#undef AVX512F_LEN +#undef AVX512F_LEN_HALF + +#define AVX512F_LEN 128 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmsubXXXph-1b.c" + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1a.c new file mode 100644 index 0000000..0316b8e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd231ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd231ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfmsubadd...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m256h yy, y2, y3; +volatile __m128h xx, x2, x3; +volatile __mmask8 m; +volatile __mmask16 m16; + +void extern +avx512vl_test (void) +{ + yy = _mm256_mask_fmsubadd_ph (yy, m16, y2, y3); + xx = _mm_mask_fmsubadd_ph (xx, m, x2, x3); + + y3 = _mm256_mask3_fmsubadd_ph (yy, y2, y3, m16); + x3 = _mm_mask3_fmsubadd_ph (xx, x2, x3, m); + + yy = _mm256_maskz_fmsubadd_ph (m16, yy, y2, y3); + xx = _mm_maskz_fmsubadd_ph (m, xx, x2, x3); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1b.c new file mode 100644 index 0000000..c8caca1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfmsubaddXXXph-1b.c @@ -0,0 +1,15 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512VL +#define AVX512F_LEN 256 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmsubaddXXXph-1b.c" + +#undef AVX512F_LEN +#undef AVX512F_LEN_HALF + +#define AVX512F_LEN 128 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfmsubaddXXXph-1b.c" + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1a.c new file mode 100644 index 0000000..6dad901 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmadd231ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd231ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmadd...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m256h yy, y2, y3; +volatile __m128h xx, x2, x3; +volatile __mmask8 m; +volatile __mmask16 m16; + +void extern +avx512vl_test (void) +{ + yy = _mm256_mask_fnmadd_ph (yy, m16, y2, y3); + xx = _mm_mask_fnmadd_ph (xx, m, x2, x3); + + y3 = _mm256_mask3_fnmadd_ph (yy, y2, y3, m16); + x3 = _mm_mask3_fnmadd_ph (xx, x2, x3, m); + + yy = _mm256_maskz_fnmadd_ph (m16, yy, y2, y3); + xx = _mm_maskz_fnmadd_ph (m, xx, x2, x3); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1b.c new file mode 100644 index 0000000..6c615d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmaddXXXph-1b.c @@ -0,0 +1,15 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512VL +#define AVX512F_LEN 256 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfnmaddXXXph-1b.c" + +#undef AVX512F_LEN +#undef AVX512F_LEN_HALF + +#define AVX512F_LEN 128 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfnmaddXXXph-1b.c" + diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1a.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1a.c new file mode 100644 index 0000000..1a7fd09 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1a.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512fp16 -O2" } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 2 } } */ +/* { dg-final { scan-assembler-times "vfnmsub231ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub231ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ +/* { dg-final { scan-assembler-times "vfnmsub...ph\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */ + +#include <immintrin.h> + +volatile __m256h yy, y2, y3; +volatile __m128h xx, x2, x3; +volatile __mmask8 m; +volatile __mmask16 m16; + +void extern +avx512vl_test (void) +{ + yy = _mm256_mask_fnmsub_ph (yy, m16, y2, y3); + xx = _mm_mask_fnmsub_ph (xx, m, x2, x3); + + y3 = _mm256_mask3_fnmsub_ph (yy, y2, y3, m16); + x3 = _mm_mask3_fnmsub_ph (xx, x2, x3, m); + + yy = _mm256_maskz_fnmsub_ph (m16, yy, y2, y3); + xx = _mm_maskz_fnmsub_ph (m, xx, x2, x3); +} diff --git a/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1b.c b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1b.c new file mode 100644 index 0000000..6d72b3d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512fp16vl-vfnmsubXXXph-1b.c @@ -0,0 +1,15 @@ +/* { dg-do run { target avx512fp16 } } */ +/* { dg-options "-O2 -mavx512fp16 -mavx512vl -mavx512dq" } */ + +#define AVX512VL +#define AVX512F_LEN 256 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfnmsubXXXph-1b.c" + +#undef AVX512F_LEN +#undef AVX512F_LEN_HALF + +#define AVX512F_LEN 128 +#define AVX512F_LEN_HALF 128 +#include "avx512fp16-vfnmsubXXXph-1b.c" + diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c index dd33993..e9a838e 100644 --- a/gcc/testsuite/gcc.target/i386/sse-13.c +++ b/gcc/testsuite/gcc.target/i386/sse-13.c @@ -774,6 +774,36 @@ #define __builtin_ia32_vcvtsh2sd_mask_round(A, B, C, D, E) __builtin_ia32_vcvtsh2sd_mask_round(A, B, C, D, 8) #define __builtin_ia32_vcvtss2sh_mask_round(A, B, C, D, E) __builtin_ia32_vcvtss2sh_mask_round(A, B, C, D, 8) #define __builtin_ia32_vcvtsd2sh_mask_round(A, B, C, D, E) __builtin_ia32_vcvtsd2sh_mask_round(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_mask(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_mask(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_mask(A, B, C, D, E) __builtin_ia32_vfmaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfmaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfmaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_mask(A, B, C, D, E) __builtin_ia32_vfnmaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfnmaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfnmaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_mask(A, B, C, D, E) __builtin_ia32_vfmsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfmsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfmsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_mask(A, B, C, D, E) __builtin_ia32_vfnmsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfnmsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfnmsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_mask(A, B, C, D, E) __builtin_ia32_vfmaddsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_mask3(A, B, C, D, E) __builtin_ia32_vfmaddsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_maskz(A, B, C, D, E) __builtin_ia32_vfmaddsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_mask(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_mask3(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_maskz(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_mask(A, B, C, D, E) __builtin_ia32_vfmsubsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_mask3(A, B, C, D, E) __builtin_ia32_vfmsubsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_maskz(A, B, C, D, E) __builtin_ia32_vfmsubsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_mask(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_mask3(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_maskz(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_maskz(A, B, C, D, 8) /* avx512fp16vlintrin.h */ #define __builtin_ia32_cmpph128_mask(A, B, C, D) __builtin_ia32_cmpph128_mask(A, B, 1, D) diff --git a/gcc/testsuite/gcc.target/i386/sse-14.c b/gcc/testsuite/gcc.target/i386/sse-14.c index e64321d..01ac4e0 100644 --- a/gcc/testsuite/gcc.target/i386/sse-14.c +++ b/gcc/testsuite/gcc.target/i386/sse-14.c @@ -836,6 +836,16 @@ test_3 (_mm_maskz_cvt_roundsh_ss, __m128, __mmask8, __m128, __m128h, 8) test_3 (_mm_maskz_cvt_roundsh_sd, __m128d, __mmask8, __m128d, __m128h, 8) test_3 (_mm_maskz_cvt_roundss_sh, __m128h, __mmask8, __m128h, __m128, 8) test_3 (_mm_maskz_cvt_roundsd_sh, __m128h, __mmask8, __m128h, __m128d, 8) +test_3 (_mm512_fmaddsub_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fmsubadd_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fmadd_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fnmadd_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fmsub_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fnmsub_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm_fmadd_round_sh, __m128h, __m128h, __m128h, __m128h, 9) +test_3 (_mm_fnmadd_round_sh, __m128h, __m128h, __m128h, __m128h, 9) +test_3 (_mm_fmsub_round_sh, __m128h, __m128h, __m128h, __m128h, 9) +test_3 (_mm_fnmsub_round_sh, __m128h, __m128h, __m128h, __m128h, 9) test_3x (_mm512_mask_cmp_round_ph_mask, __mmask32, __mmask32, __m512h, __m512h, 1, 8) test_3x (_mm_mask_cmp_round_sh_mask, __mmask8, __mmask8, __m128h, __m128h, 1, 8) test_3x (_mm512_mask_reduce_round_ph, __m512h, __m512h, __mmask32, __m512h, 123, 8) @@ -868,6 +878,36 @@ test_4 (_mm_mask_cvt_roundsh_ss, __m128, __m128, __mmask8, __m128, __m128h, 8) test_4 (_mm_mask_cvt_roundsh_sd, __m128d, __m128d, __mmask8, __m128d, __m128h, 8) test_4 (_mm_mask_cvt_roundss_sh, __m128h, __m128h, __mmask8, __m128h, __m128, 8) test_4 (_mm_mask_cvt_roundsd_sh, __m128h, __m128h, __mmask8, __m128h, __m128d, 8) +test_4 (_mm512_mask_fmaddsub_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmaddsub_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fmaddsub_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmsubadd_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_mask_fmsubadd_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_maskz_fmsubadd_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fmadd_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmadd_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fmadd_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fnmadd_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fnmadd_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fnmadd_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fmsub_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmsub_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fmsub_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fnmsub_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fnmsub_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fnmsub_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm_mask_fmadd_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fmadd_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fmadd_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) +test_4 (_mm_mask_fnmadd_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fnmadd_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fnmadd_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) +test_4 (_mm_mask_fmsub_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fmsub_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fmsub_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) +test_4 (_mm_mask_fnmsub_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fnmsub_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fnmsub_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) test_4x (_mm_mask_reduce_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 123, 8) test_4x (_mm_mask_roundscale_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 123, 8) test_4x (_mm_mask_getmant_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 1, 1) diff --git a/gcc/testsuite/gcc.target/i386/sse-22.c b/gcc/testsuite/gcc.target/i386/sse-22.c index d92898f..79e3f35 100644 --- a/gcc/testsuite/gcc.target/i386/sse-22.c +++ b/gcc/testsuite/gcc.target/i386/sse-22.c @@ -939,6 +939,16 @@ test_3 (_mm_maskz_cvt_roundsh_ss, __m128, __mmask8, __m128, __m128h, 8) test_3 (_mm_maskz_cvt_roundsh_sd, __m128d, __mmask8, __m128d, __m128h, 8) test_3 (_mm_maskz_cvt_roundss_sh, __m128h, __mmask8, __m128h, __m128, 8) test_3 (_mm_maskz_cvt_roundsd_sh, __m128h, __mmask8, __m128h, __m128d, 8) +test_3 (_mm512_fmaddsub_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fmsubadd_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fmadd_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fnmadd_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fmsub_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm512_fnmsub_round_ph, __m512h, __m512h, __m512h, __m512h, 9) +test_3 (_mm_fmadd_round_sh, __m128h, __m128h, __m128h, __m128h, 9) +test_3 (_mm_fnmadd_round_sh, __m128h, __m128h, __m128h, __m128h, 9) +test_3 (_mm_fmsub_round_sh, __m128h, __m128h, __m128h, __m128h, 9) +test_3 (_mm_fnmsub_round_sh, __m128h, __m128h, __m128h, __m128h, 9) test_3x (_mm512_mask_cmp_round_ph_mask, __mmask32, __mmask32, __m512h, __m512h, 1, 8) test_3x (_mm_mask_cmp_round_sh_mask, __mmask8, __mmask8, __m128h, __m128h, 1, 8) test_3x (_mm512_mask_reduce_round_ph, __m512h, __m512h, __mmask32, __m512h, 123, 8) @@ -970,6 +980,36 @@ test_4 (_mm_mask_cvt_roundsh_ss, __m128, __m128, __mmask8, __m128, __m128h, 8) test_4 (_mm_mask_cvt_roundsh_sd, __m128d, __m128d, __mmask8, __m128d, __m128h, 8) test_4 (_mm_mask_cvt_roundss_sh, __m128h, __m128h, __mmask8, __m128h, __m128, 8) test_4 (_mm_mask_cvt_roundsd_sh, __m128h, __m128h, __mmask8, __m128h, __m128d, 8) +test_4 (_mm512_mask_fmaddsub_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmaddsub_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fmaddsub_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmsubadd_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_mask_fmsubadd_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_maskz_fmsubadd_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fmadd_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmadd_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fmadd_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fnmadd_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fnmadd_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fnmadd_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fmsub_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fmsub_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fmsub_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm512_mask_fnmsub_round_ph, __m512h, __m512h, __mmask32, __m512h, __m512h, 9) +test_4 (_mm512_mask3_fnmsub_round_ph, __m512h, __m512h, __m512h, __m512h, __mmask32, 9) +test_4 (_mm512_maskz_fnmsub_round_ph, __m512h, __mmask32, __m512h, __m512h, __m512h, 9) +test_4 (_mm_mask_fmadd_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fmadd_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fmadd_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) +test_4 (_mm_mask_fnmadd_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fnmadd_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fnmadd_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) +test_4 (_mm_mask_fmsub_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fmsub_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fmsub_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) +test_4 (_mm_mask_fnmsub_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 9) +test_4 (_mm_mask3_fnmsub_round_sh, __m128h, __m128h, __m128h, __m128h, __mmask8, 9) +test_4 (_mm_maskz_fnmsub_round_sh, __m128h, __mmask8, __m128h, __m128h, __m128h, 9) test_4x (_mm_mask_reduce_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 123, 8) test_4x (_mm_mask_roundscale_round_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 123, 8) test_4x (_mm_mask_getmant_sh, __m128h, __m128h, __mmask8, __m128h, __m128h, 1, 1) diff --git a/gcc/testsuite/gcc.target/i386/sse-23.c b/gcc/testsuite/gcc.target/i386/sse-23.c index 9c32b7b..4be2c1e 100644 --- a/gcc/testsuite/gcc.target/i386/sse-23.c +++ b/gcc/testsuite/gcc.target/i386/sse-23.c @@ -775,6 +775,36 @@ #define __builtin_ia32_vcvtsh2sd_mask_round(A, B, C, D, E) __builtin_ia32_vcvtsh2sd_mask_round(A, B, C, D, 8) #define __builtin_ia32_vcvtss2sh_mask_round(A, B, C, D, E) __builtin_ia32_vcvtss2sh_mask_round(A, B, C, D, 8) #define __builtin_ia32_vcvtsd2sh_mask_round(A, B, C, D, E) __builtin_ia32_vcvtsd2sh_mask_round(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_mask(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfmaddsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_mask(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfmsubaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_mask(A, B, C, D, E) __builtin_ia32_vfmaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfmaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfmaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_mask(A, B, C, D, E) __builtin_ia32_vfnmaddph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_mask3(A, B, C, D, E) __builtin_ia32_vfnmaddph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddph512_maskz(A, B, C, D, E) __builtin_ia32_vfnmaddph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_mask(A, B, C, D, E) __builtin_ia32_vfmsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfmsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfmsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_mask(A, B, C, D, E) __builtin_ia32_vfnmsubph512_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_mask3(A, B, C, D, E) __builtin_ia32_vfnmsubph512_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubph512_maskz(A, B, C, D, E) __builtin_ia32_vfnmsubph512_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_mask(A, B, C, D, E) __builtin_ia32_vfmaddsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_mask3(A, B, C, D, E) __builtin_ia32_vfmaddsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmaddsh3_maskz(A, B, C, D, E) __builtin_ia32_vfmaddsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_mask(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_mask3(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmaddsh3_maskz(A, B, C, D, E) __builtin_ia32_vfnmaddsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_mask(A, B, C, D, E) __builtin_ia32_vfmsubsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_mask3(A, B, C, D, E) __builtin_ia32_vfmsubsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfmsubsh3_maskz(A, B, C, D, E) __builtin_ia32_vfmsubsh3_maskz(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_mask(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_mask(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_mask3(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_mask3(A, B, C, D, 8) +#define __builtin_ia32_vfnmsubsh3_maskz(A, B, C, D, E) __builtin_ia32_vfnmsubsh3_maskz(A, B, C, D, 8) /* avx512fp16vlintrin.h */ #define __builtin_ia32_cmpph128_mask(A, B, C, D) __builtin_ia32_cmpph128_mask(A, B, 1, D) diff --git a/gcc/testsuite/gfortran.dg/goacc/privatization-1-compute.f90 b/gcc/testsuite/gfortran.dg/goacc/privatization-1-compute.f90 index ed7e9ec..31f998d 100644 --- a/gcc/testsuite/gfortran.dg/goacc/privatization-1-compute.f90 +++ b/gcc/testsuite/gfortran.dg/goacc/privatization-1-compute.f90 @@ -39,9 +39,9 @@ contains !$acc atomic write ! ... to force 'TREE_ADDRESSABLE'. y = a !$acc end parallel - ! { dg-note {variable 'i' in 'private' clause potentially has improper OpenACC privatization level: 'parm_decl'} "TODO" { xfail *-*-* } l_compute$c_compute } - ! { dg-note {variable 'j' in 'private' clause potentially has improper OpenACC privatization level: 'parm_decl'} "TODO" { xfail *-*-* } l_compute$c_compute } - ! { dg-note {variable 'a' in 'private' clause potentially has improper OpenACC privatization level: 'parm_decl'} "TODO" { xfail *-*-* } l_compute$c_compute } + ! { dg-note {variable 'i' in 'private' clause potentially has improper OpenACC privatization level: 'parm_decl'} "TODO2" { xfail *-*-* } l_compute$c_compute } + ! { dg-note {variable 'j' in 'private' clause potentially has improper OpenACC privatization level: 'parm_decl'} "TODO3" { xfail *-*-* } l_compute$c_compute } + ! { dg-note {variable 'a' in 'private' clause potentially has improper OpenACC privatization level: 'parm_decl'} "TODO4" { xfail *-*-* } l_compute$c_compute } ! { dg-note {variable 'C\.[0-9]+' declared in block potentially has improper OpenACC privatization level: 'const_decl'} "TODO" { target *-*-* } l_compute$c_compute } ! { dg-note {variable 'D\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} "" { target *-*-* } l_compute$c_compute } end subroutine f diff --git a/gcc/testsuite/gfortran.dg/goacc/routine-external-level-of-parallelism-2.f b/gcc/testsuite/gfortran.dg/goacc/routine-external-level-of-parallelism-2.f index 04d507f..949d571 100644 --- a/gcc/testsuite/gfortran.dg/goacc/routine-external-level-of-parallelism-2.f +++ b/gcc/testsuite/gfortran.dg/goacc/routine-external-level-of-parallelism-2.f @@ -22,8 +22,8 @@ ! { dg-warning "insufficient partitioning available to parallelize loop" "" { target *-*-* } .-1 } do j = 1, n call workerr (a, n) ! { dg-message "optimized: assigned OpenACC worker vector loop parallelism" } -! { dg-bogus "note: routine 'workerr' declared here" "TODO" { xfail { ! offloading_enabled } } .-1 } -! { dg-bogus "note: routine 'workerr_' declared here" "TODO" { xfail offloading_enabled } .-2 } +! { dg-bogus "note: routine 'workerr' declared here" "TODO1" { xfail { ! offloading_enabled } } .-1 } +! { dg-bogus "note: routine 'workerr_' declared here" "TODO2" { xfail offloading_enabled } .-2 } end do end do !$acc end parallel loop @@ -36,8 +36,8 @@ do j = 1, n call gangr (a, n) ! { dg-message "optimized: assigned OpenACC worker vector loop parallelism" } ! { dg-error "routine call uses same OpenACC parallelism as containing loop" "" { target *-*-* } .-1 } -! { dg-bogus "note: routine 'gangr' declared here" "TODO" { xfail { ! offloading_enabled } } .-2 } -! { dg-bogus "note: routine 'gangr_' declared here" "TODO" { xfail offloading_enabled } .-3 } +! { dg-bogus "note: routine 'gangr' declared here" "TODO1" { xfail { ! offloading_enabled } } .-2 } +! { dg-bogus "note: routine 'gangr_' declared here" "TODO2" { xfail offloading_enabled } .-3 } end do end do !$acc end parallel loop @@ -162,8 +162,8 @@ !$acc parallel loop ! { dg-message "optimized: assigned OpenACC gang worker loop parallelism" } do i = 1, n call vectorr (a, n) ! { dg-message "optimized: assigned OpenACC vector loop parallelism" } -! { dg-bogus "note: routine 'vectorr' declared here" "TODO" { xfail { ! offloading_enabled } } .-1 } -! { dg-bogus "note: routine 'vectorr_' declared here" "TODO" { xfail offloading_enabled } .-2 } +! { dg-bogus "note: routine 'vectorr' declared here" "TODO1" { xfail { ! offloading_enabled } } .-1 } +! { dg-bogus "note: routine 'vectorr_' declared here" "TODO2" { xfail offloading_enabled } .-2 } end do !$acc end parallel loop @@ -214,8 +214,8 @@ ! { dg-warning "insufficient partitioning available to parallelize loop" "" { target *-*-* } .-1 } do j = 1, n a(i) = workerf (a, n) ! { dg-message "optimized: assigned OpenACC worker vector loop parallelism" } -! { dg-bogus "note: routine 'workerf' declared here" "TODO" { xfail { ! offloading_enabled } } .-1 } -! { dg-bogus "note: routine 'workerf_' declared here" "TODO" { xfail offloading_enabled } .-2 } +! { dg-bogus "note: routine 'workerf' declared here" "TODO1" { xfail { ! offloading_enabled } } .-1 } +! { dg-bogus "note: routine 'workerf_' declared here" "TODO2" { xfail offloading_enabled } .-2 } end do end do !$acc end parallel loop @@ -228,8 +228,8 @@ do j = 1, n a(i) = gangf (a, n) ! { dg-message "optimized: assigned OpenACC worker vector loop parallelism" } ! { dg-error "routine call uses same OpenACC parallelism as containing loop" "" { target *-*-* } .-1 } -! { dg-bogus "note: routine 'gangf' declared here" "TODO" { xfail { ! offloading_enabled } } .-2 } -! { dg-bogus "note: routine 'gangf_' declared here" "TODO" { xfail offloading_enabled } .-3 } +! { dg-bogus "note: routine 'gangf' declared here" "TODO1" { xfail { ! offloading_enabled } } .-2 } +! { dg-bogus "note: routine 'gangf_' declared here" "TODO2" { xfail offloading_enabled } .-3 } end do end do !$acc end parallel loop @@ -354,8 +354,8 @@ !$acc parallel loop ! { dg-message "optimized: assigned OpenACC gang worker loop parallelism" } do i = 1, n a(i) = vectorf (a, n) ! { dg-message "optimized: assigned OpenACC vector loop parallelism" } -! { dg-bogus "note: routine 'vectorf' declared here" "TODO" { xfail { ! offloading_enabled } } .-1 } -! { dg-bogus "note: routine 'vectorf_' declared here" "TODO" { xfail offloading_enabled } .-2 } +! { dg-bogus "note: routine 'vectorf' declared here" "TODO1" { xfail { ! offloading_enabled } } .-1 } +! { dg-bogus "note: routine 'vectorf_' declared here" "TODO2" { xfail offloading_enabled } .-2 } end do !$acc end parallel loop diff --git a/gcc/testsuite/gfortran.dg/gomp/order-5.f90 b/gcc/testsuite/gfortran.dg/gomp/order-5.f90 new file mode 100644 index 0000000..4d9e336 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/order-5.f90 @@ -0,0 +1,129 @@ +! { dg-additional-options "-fdump-tree-original" } + +subroutine f1 (a) + integer :: a(*), i + !$omp do order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp simd order ( reproducible : concurrent ) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do simd order(reproducible :concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do +end + +subroutine f2 (a) + integer :: a(*), i + !$omp parallel do order(reproducible: concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp parallel do simd order (reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute parallel do order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute parallel do simd order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams + !$omp distribute parallel do order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp distribute parallel do simd order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp distribute order(reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp end teams + !$omp taskloop simd order (reproducible:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do +end + +subroutine f3 (a) + integer :: a(*), i + !$omp do order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp simd order ( unconstrained : concurrent ) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do simd order(unconstrained :concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do +end + +subroutine f4 (a) + integer :: a(*), i + !$omp parallel do order(unconstrained: concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp parallel do simd order (unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute parallel do order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute parallel do simd order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams + !$omp distribute parallel do order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp distribute parallel do simd order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp distribute order(unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp end teams + !$omp taskloop simd order (unconstrained:concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do +end + +! { dg-final { scan-tree-dump-times "#pragma omp distribute order\\(concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp distribute order\\(unconstrained:concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp for nowait order\\(concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp for nowait order\\(unconstrained:concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp for order\\(concurrent\\)" 2 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp for order\\(unconstrained:concurrent\\)" 2 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp parallel" 12 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) order\\(concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) order\\(unconstrained:concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp taskloop" 2 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp teams" 8 "original"} } diff --git a/gcc/testsuite/gfortran.dg/gomp/order-6.f90 b/gcc/testsuite/gfortran.dg/gomp/order-6.f90 new file mode 100644 index 0000000..c8aeecb --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/order-6.f90 @@ -0,0 +1,436 @@ +module m + use iso_c_binding + implicit none (type, external) + interface + subroutine foo() + end subroutine foo + integer function omp_get_thread_num () + end + integer function omp_get_num_threads () + end + integer function omp_target_is_present (x, i) + import :: c_ptr + type(c_ptr) :: x + integer, value :: i + end + integer function omp_get_cancellation () + end + end interface + integer :: v +contains +subroutine f1 (a) + integer, target :: a(*) + integer :: i + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + !$omp parallel ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end parallel + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + block + integer j + !$omp simd + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + !$omp critical ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end critical + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end ordered + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = v + 1 + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = v + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = a(i) + end do + !$omp simd order(reproducible:concurrent) + do i = 1, 64 + 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 simd order(reproducible:concurrent) + do i = 1, 64 + 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 simd order(reproducible:concurrent) + do i = 1, 64 + 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 simd order(reproducible:concurrent) + do i = 1, 64 + 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 f2 (a) + integer, target :: a(*) + integer :: i + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + !$omp parallel ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end parallel + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + block + integer j + !$omp simd + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + !$omp critical ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end critical + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end ordered + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = v + 1 + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = v + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = a(i) + end do + !$omp do simd order(reproducible:concurrent) + do i = 1, 64 + 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 do simd order(reproducible:concurrent) + do i = 1, 64 + 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 do simd order(reproducible:concurrent) + do i = 1, 64 + 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 do simd order(reproducible:concurrent) + do i = 1, 64 + 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 f3 (a) + integer, target :: a(*) + integer :: i + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + block + integer j + !$omp simd + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end critical + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end ordered + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = v + 1 + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = v + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = a(i) + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + !$omp task ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = a(i) + 1 + !$omp end task + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + block + integer j + !$omp taskloop ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp do order(reproducible:concurrent) + do i = 1, 64 + 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 do order(reproducible:concurrent) + do i = 1, 64 + 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 do order(reproducible:concurrent) + do i = 1, 64 + 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 do order(reproducible:concurrent) + do i = 1, 64 + 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 f4 (a) + integer, target :: a(*) + integer :: i + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp parallel ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end parallel + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + block + integer j + !$omp simd + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp critical ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end critical + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end ordered + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = v + 1 + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = v + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = a(i) + end do + !$omp simd order(unconstrained:concurrent) + do i = 1, 64 + 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 simd order(unconstrained:concurrent) + do i = 1, 64 + 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 simd order(unconstrained:concurrent) + do i = 1, 64 + 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 simd order(unconstrained:concurrent) + do i = 1, 64 + 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(*) + integer :: i + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp parallel ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end parallel + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + block + integer j + !$omp simd + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp critical ! { dg-error "OpenMP constructs other than 'ordered simd', 'simd', 'loop' or 'atomic' may not be nested inside 'simd' region" } + call foo () + !$omp end critical + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end ordered + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = v + 1 + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = v + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = a(i) + end do + !$omp do simd order(unconstrained:concurrent) + do i = 1, 64 + 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 do simd order(unconstrained:concurrent) + do i = 1, 64 + 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 do simd order(unconstrained:concurrent) + do i = 1, 64 + 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 do simd order(unconstrained:concurrent) + do i = 1, 64 + 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 f6 (a) + integer, target :: a(*) + integer :: i + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + block + integer j + !$omp simd + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end critical + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + call foo () + !$omp end ordered + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = v + 1 + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = v + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + v = a(i) + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + !$omp task ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + a(i) = a(i) + 1 + !$omp end task + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + block + integer j + !$omp taskloop ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a region with the 'order\\(concurrent\\)' clause" } + do j = 1, 64 + a(64 * i + j) = i + j + end do + end block + end do + !$omp do order(unconstrained:concurrent) + do i = 1, 64 + 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 do order(unconstrained:concurrent) + do i = 1, 64 + 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 do order(unconstrained:concurrent) + do i = 1, 64 + 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 do order(unconstrained:concurrent) + do i = 1, 64 + 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 +end module m diff --git a/gcc/testsuite/gfortran.dg/gomp/order-7.f90 b/gcc/testsuite/gfortran.dg/gomp/order-7.f90 new file mode 100644 index 0000000..4be8ab3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/order-7.f90 @@ -0,0 +1,59 @@ +subroutine f1 (a) + integer :: a(*) + integer i + !$omp do order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp simd order ( concurrent ) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do simd order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do +end + +subroutine f2 (a) + integer :: a(*) + integer i + !$omp parallel do order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp parallel do simd order (concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute parallel do order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute parallel do simd order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams distribute order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp teams + !$omp distribute parallel do order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp distribute parallel do simd order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp distribute order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp end teams + !$omp taskloop simd order (concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do +end diff --git a/gcc/testsuite/gfortran.dg/gomp/order-8.f90 b/gcc/testsuite/gfortran.dg/gomp/order-8.f90 new file mode 100644 index 0000000..c753886 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/order-8.f90 @@ -0,0 +1,61 @@ +subroutine f1 (a) + integer :: a(*) + integer i + !$omp do order ! { dg-error "Failed to match clause" } + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do simd order : ! { dg-error "Failed to match clause" } + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp simd order ( foobar ) ! { dg-error "Expected ORDER\\(CONCURRENT\\) at .1. with optional 'reproducible' or 'unconstrained' modifier" } + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do simd order( concurrent ! { dg-error "Expected ORDER\\(CONCURRENT\\) at .1. with optional 'reproducible' or 'unconstrained' modifier" } + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do simd order( concurrent : foo )! { dg-error "Expected ORDER\\(CONCURRENT\\) at .1. with optional 'reproducible' or 'unconstrained' modifier" } + do i = 1, 128 + a(i) = a(i) + 1 + end do +end + +subroutine f2 (a) + integer :: a(*) + integer i + !$omp teams + !$omp distribute order(concurrent) + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp end teams + !$omp taskloop order (concurrent) ! { dg-error "Failed to match clause" } + do i = 1, 128 + a(i) = a(i) + 1 + end do + !$omp do order(concurrent) ordered ! { dg-error "ORDER clause must not be used together ORDERED" } + do i = 1, 128 + !$omp ordered + a(i) = a(i) + 1 + !$omp end ordered + end do + !$omp do ordered order(concurrent) ! { dg-error "ORDER clause must not be used together ORDERED" } + do i = 1, 128 + !$omp ordered + a(i) = a(i) + 1 + !$omp end ordered + end do + !$omp do ordered (1) order(concurrent) ! { dg-error "ORDER clause must not be used together ORDERED" } + do i = 1, 128 + !$omp ordered depend (sink: i - 1) + !$omp ordered depend (source) + end do + !$omp do order(concurrent)ordered (1) ! { dg-error "ORDER clause must not be used together ORDERED" } + do i = 1, 128 + !$omp ordered depend (sink: i - 1) + !$omp ordered depend (source) + end do +end diff --git a/gcc/testsuite/gfortran.dg/gomp/order-9.f90 b/gcc/testsuite/gfortran.dg/gomp/order-9.f90 new file mode 100644 index 0000000..c769511 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/order-9.f90 @@ -0,0 +1,35 @@ +subroutine foo + !$omp do schedule(static) order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + !$omp do schedule(static) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + + !$omp loop bind(thread) order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + !$omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + !$omp simd order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + !$omp simd order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + !$omp distribute dist_schedule(static) order(concurrent) order(concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do + !$omp loop bind(thread) order(reproducible:concurrent) order(unconstrained:concurrent) ! { dg-error "Duplicated 'order \\(' clause" } + do i = 1, 8 + call f0 () + end do +end diff --git a/gcc/testsuite/gfortran.dg/include_14.f90 b/gcc/testsuite/gfortran.dg/include_14.f90 new file mode 100644 index 0000000..b306b2c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_14.f90 @@ -0,0 +1,5 @@ +! { dg-additional-options "-cpp -idirafter /fdaf/ -I bar" } +end + +! { dg-warning "/fdaf/: No such file or directory" "" { target *-*-* } 0 } +! { dg-warning "bar: No such file or directory" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/gfortran.dg/include_15.f90 b/gcc/testsuite/gfortran.dg/include_15.f90 new file mode 100644 index 0000000..4944282 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_15.f90 @@ -0,0 +1,5 @@ +! { dg-additional-options "-cpp -idirafter /fdaf/ -I bar -Wmissing-include-dirs" } +end + +! { dg-warning "/fdaf/: No such file or directory" "" { target *-*-* } 0 } +! { dg-warning "bar: No such file or directory" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/gfortran.dg/include_16.f90 b/gcc/testsuite/gfortran.dg/include_16.f90 new file mode 100644 index 0000000..45794f2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_16.f90 @@ -0,0 +1,2 @@ +! { dg-additional-options "-cpp -idirafter /fdaf/ -I bar -Wno-missing-include-dirs" } +end diff --git a/gcc/testsuite/gfortran.dg/include_17.f90 b/gcc/testsuite/gfortran.dg/include_17.f90 new file mode 100644 index 0000000..0ed5c86d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_17.f90 @@ -0,0 +1,4 @@ +! { dg-do compile } +! { dg-options "-I foo-bar -Wno-missing-include-dirs" } +end + diff --git a/gcc/testsuite/gfortran.dg/include_18.f90 b/gcc/testsuite/gfortran.dg/include_18.f90 new file mode 100644 index 0000000..ca69df3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_18.f90 @@ -0,0 +1,3 @@ +! { dg-do compile } +! { dg-options "-I nothere -Wno-missing-include-dirs" } +end diff --git a/gcc/testsuite/gfortran.dg/include_19.f90 b/gcc/testsuite/gfortran.dg/include_19.f90 new file mode 100644 index 0000000..2a06817 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_19.f90 @@ -0,0 +1,4 @@ +! { dg-do compile } +! { dg-options "-J foobar/foo -Wno-missing-include-dirs" } +program main +end program main diff --git a/gcc/testsuite/gfortran.dg/include_20.f90 b/gcc/testsuite/gfortran.dg/include_20.f90 new file mode 100644 index 0000000..4f8fdc6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_20.f90 @@ -0,0 +1,5 @@ +! { dg-do compile } +! { dg-options "-J foobar/foo" } +program main +end program main +! { dg-warning "Nonexistent include directory" "" { target *-*-* } 0 } diff --git a/gcc/testsuite/gfortran.dg/include_21.f90 b/gcc/testsuite/gfortran.dg/include_21.f90 new file mode 100644 index 0000000..40bc598 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/include_21.f90 @@ -0,0 +1,26 @@ +# 1 "../../../trunk/libgfortran/generated/_abs_c4.F90" +# 1 "C:\\msys\\1.0.10\\home\\FX\\ibin\\i586-pc-mingw32\\libgfortran//" +# 1 "<built-in>" +# 1 "<command-line>" +# 1 "../../../trunk/libgfortran/generated/_abs_c4.F90" +! Comment here + +# 1 "./config.h" 1 + +# 37 "../../../trunk/libgfortran/generated/_abs_c4.F90" 2 + +# 1 "./kinds.inc" 1 +# 38 "../../../trunk/libgfortran/generated/_abs_c4.F90" 2 + +# 1 "./c99_protos.inc" 1 +# 39 "../../../trunk/libgfortran/generated/_abs_c4.F90" 2 + +elemental function abs_c4 (parm) + complex (kind=4), intent (in) :: parm + real (kind=4) :: abs_c4 + + abs_c4 = abs (parm) +end function + +! { dg-do compile } +! { dg-options "-fpreprocessed -g3 -Wno-missing-include-dirs" } diff --git a/gcc/testsuite/gfortran.dg/include_6.f90 b/gcc/testsuite/gfortran.dg/include_6.f90 index f5bb085..3e3be1b 100644 --- a/gcc/testsuite/gfortran.dg/include_6.f90 +++ b/gcc/testsuite/gfortran.dg/include_6.f90 @@ -1,6 +1,6 @@ ! { dg-do compile } ! { dg-options "-I gfortran.log" } -! { dg-error "is not a directory" "" { target *-*-* } 0 } +! { dg-warning "Include directory 'gfortran.log/': Not a directory" "" { target *-*-* } 0 } ! { dg-prune-output "compilation terminated." } end diff --git a/gcc/testsuite/gfortran.dg/pr102366.f90 b/gcc/testsuite/gfortran.dg/pr102366.f90 new file mode 100644 index 0000000..d002f64 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr102366.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } +! { dg-options "-fdump-tree-original -Wall" } +! { dg-final { scan-tree-dump-times "static real" 1 "original" } } +! PR fortran/102366 - large arrays no longer become static + +program p + real(kind=4) :: a(16776325) + a=1.0 +end diff --git a/gcc/testsuite/gnat.dg/asan1.adb b/gcc/testsuite/gnat.dg/asan1.adb index a4bc59a..26bc1a4 100644 --- a/gcc/testsuite/gnat.dg/asan1.adb +++ b/gcc/testsuite/gnat.dg/asan1.adb @@ -1,7 +1,7 @@ -- { dg-do compile } -- { dg-additional-sources asan1_pkg.ads } -- { dg-options "-fsanitize=address" } --- { dg-skip-if "" no_fsanitize_address } +-- { dg-skip-if "no address sanitizer" { no_fsanitize_address } } with Asan1_Pkg; diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp index 4459dbc..10b98bd 100644 --- a/gcc/testsuite/jit.dg/jit.exp +++ b/gcc/testsuite/jit.dg/jit.exp @@ -167,6 +167,9 @@ proc fixed_host_execute {args} { if {![file exists ${executable}]} { perror "The executable, \"$executable\" is missing" 0 return "No source file found" + } elseif {![file executable ${executable}]} { + perror "The executable, \"$executable\" is not usable" 0 + return "Bad executable found" } verbose "params: $params" 2 @@ -194,84 +197,125 @@ proc fixed_host_execute {args} { set args [concat $args ${params}] verbose "args: $args" 2 - eval spawn -noecho $args - - expect_after full_buffer { error "got full_buffer" } + # We checked that the executable exists above, and can be executed, but + #Â that does not cover other reasons that the launch could fail (e.g. + #Â missing or malformed params); catch such cases here and report them. + set err [catch "spawn -noecho $args" pid] + set sub_proc_id $spawn_id + if { $pid <= 0 || $err != 0 || $sub_proc_id < 0 } { + warning "failed to spawn : $args : err = $err" + } + + # Increase the buffer size, if needed to avoid spurious buffer-full + # events; GCC uses 10000; chose a power of two here. + set current_max_match [match_max -i $sub_proc_id] + if { $current_max_match < 8192 } { + match_max -i $sub_proc_id 8192 + set used [match_max -i $sub_proc_id] + } + + # If we get a buffer-full error, that seems to be unrecoverable so try to + #Â exit in a reasonable manner to avoid wedged processes. + expect_after full_buffer { + verbose -log "fixed_host_execute: $args FULL BUFFER" + # FIXME: this all assumes that closing the connection will cause the + # sub-process to terminate (but that is not going to be the case if, + # for example, there is something started with -nohup somewhere). + # We should explicitly kill it here. + #Â Set the process to be a nowait exit. + wait -nowait -i $sub_proc_id + catch close + perror "${executable} got full_buffer" + return "${executable} got full_buffer" + } set prefix "\[^\r\n\]*" + # Work around a Darwin tcl or termios bug that sometimes inserts extra + # CR characters into the cooked tty stream + set endline "\r\n" + if { [istarget *-*-darwin*] } { + set endline "\r(\r)*\n" + } + + # Note that the logic here assumes that we cannot (validly) get single + # carriage return or line feed characters in the stream. If those occur, + #Â it will stop any further matching. We arange for the matching to be + # at the start of the buffer - so that if there is any spurious output + # to be discarded, it must be done explicitly - not by matching part-way + # through the buffer. expect { - -re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" { + -re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*$endline" { regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output verbose "$output" 3 set timetol 0 exp_continue } - -re "^$prefix\tNOTE:\[^\r\n\]+\r\n" { - regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output - set output [string range $output 6 end-2] - verbose "$output" 2 + -re "^\tNOTE: (\[^\r\n\]+)$endline" { + # discard notes. + verbose "Ignored note: $expect_out(1,string)" 2 set timetol 0 exp_continue } - -re "^$prefix\tPASSED:\[^\r\n\]+\r\n" { - regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output - set output [string range $output 8 end-2] - pass "$output" + -re "^\tPASSED: (\[^\r\n\]+)$endline" { + pass "$expect_out(1,string)" set timetol 0 exp_continue } - -re "^$prefix\tFAILED:\[^\r\n\]+\r\n" { - regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output - set output [string range $output 8 end-2] - fail "$output" + -re "^\tFAILED: (\[^\r\n\]+)$endline" { + fail "$expect_out(1,string)" set timetol 0 exp_continue } - -re "^$prefix\tUNTESTED:\[^\r\n\]+\r\n" { - regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output - set output [string range $output 8 end-2] - untested "$output" + -re "^\tUNTESTED: (\[^\r\n\]+)$endline" { + untested "$expect_out(1,string)" set timetol 0 exp_continue } - -re "^$prefix\tUNRESOLVED:\[^\r\n\]+\r\n" { - regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output - set output [string range $output 8 end-2] - unresolved "$output" + -re "^\tUNRESOLVED: (\[^\r\n\]+)$endline" { + unresolved "$expect_out(1,string)" set timetol 0 exp_continue } - -re "^Totals" { - verbose "All done" 2 + -re "^$prefix$endline" { + #Â This matches and discards any other lines (including blank ones). + if { [string length $expect_out(buffer)] <= 2 } { + set output "blank line" + } else { + set output [string range $expect_out(buffer) 0 end-2] + } + verbose -log "DISCARDED $expect_out(spawn_id) : $output" + exp_continue } eof { - # unresolved "${executable} died prematurely" - # catch close - # return "${executable} died prematurely" + # This seems to be the only way that we can reliably know that the + # output is finished since there are cases where further output + # follows the dejagnu test harness totals. + verbose "saw eof" 2 } timeout { - warning "Timed out executing test case" if { $timetol <= 2 } { + verbose -log "Timed out with retry (timeout = $timeout)" incr timetol exp_continue } else { + warning "Timed out executing testcase (timeout = $timeout)" catch close return "Timed out executing test case" } } - -re "^$prefix\r\n" { - exp_continue - } } - # Use "wait" before "close": valgrind might not have finished - # writing the log out before we parse it, so we need to wait for - # the spawnee to finish. - - catch wait wres - verbose "wres: $wres" 2 - verify_exit_status $executable $wres - + # Use "wait" to pick up the sub-process exit state. If the sub-process is + # writing to a file (perhaps under valgrind) then that also needs to be + # complete; only attempt this on a valid spawn. + if { $sub_proc_id > 0 } { + verbose "waiting for $sub_proc_id" 1 + #Â Be explicit about what we are waiting for. + catch "wait -i $sub_proc_id" wres + verbose "wres: $wres" 2 + verify_exit_status $executable $wres + } + if $run_under_valgrind { upvar 2 name name parse_valgrind_logfile $name $valgrind_logfile diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp index 91f165b..fac212e 100644 --- a/gcc/testsuite/lib/prune.exp +++ b/gcc/testsuite/lib/prune.exp @@ -37,6 +37,9 @@ proc prune_gcc_output { text } { # Handle any freeform regexps. set text [handle-dg-regexps $text] + # Remove Windows .exe suffix + regsub -all "(as|cc1|cc1plus|collect2|f951|ld|lto-wrapper)\.exe?:" $text {\1:} text + regsub -all "(^|\n)(\[^\n\]*: \[iI\]|I)n ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|substitution|program|subroutine|block-data)\[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text regsub -all "(^|\n)\[^\n\]*: (recursively )?required \[^\n\]*" $text "" text diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index f11c4e6..9ebca7a 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -11251,14 +11251,15 @@ proc check_effective_target_movdir { } { } "-mmovdiri -mmovdir64b" ] } -# Return 1 if target is not support address sanitize, 1 otherwise. +# Return 1 if the target does not support address sanitizer, 0 otherwise proc check_effective_target_no_fsanitize_address {} { if ![check_no_compiler_messages fsanitize_address executable { int main (void) { return 0; } - }] { + } "-fsanitize=address" ] { return 1; } + return 0; } diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index e061baa..18307a5 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -99,6 +99,7 @@ along with GCC; see the file COPYING3. If not see #include "internal-fn.h" #include "vr-values.h" #include "range-op.h" +#include "tree-ssa-loop-ivopts.h" static struct datadep_stats { @@ -1300,22 +1301,18 @@ base_supports_access_fn_components_p (tree base) DR, analyzed in LOOP and instantiated before NEST. */ static void -dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop) +dr_analyze_indices (struct indices *dri, tree ref, edge nest, loop_p loop) { - vec<tree> access_fns = vNULL; - tree ref, op; - tree base, off, access_fn; - /* If analyzing a basic-block there are no indices to analyze and thus no access functions. */ if (!nest) { - DR_BASE_OBJECT (dr) = DR_REF (dr); - DR_ACCESS_FNS (dr).create (0); + dri->base_object = ref; + dri->access_fns.create (0); return; } - ref = DR_REF (dr); + vec<tree> access_fns = vNULL; /* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses into a two element array with a constant index. The base is @@ -1338,8 +1335,8 @@ dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop) { if (TREE_CODE (ref) == ARRAY_REF) { - op = TREE_OPERAND (ref, 1); - access_fn = analyze_scalar_evolution (loop, op); + tree op = TREE_OPERAND (ref, 1); + tree access_fn = analyze_scalar_evolution (loop, op); access_fn = instantiate_scev (nest, loop, access_fn); access_fns.safe_push (access_fn); } @@ -1370,16 +1367,16 @@ dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop) analyzed nest, add it as an additional independent access-function. */ if (TREE_CODE (ref) == MEM_REF) { - op = TREE_OPERAND (ref, 0); - access_fn = analyze_scalar_evolution (loop, op); + tree op = TREE_OPERAND (ref, 0); + tree access_fn = analyze_scalar_evolution (loop, op); access_fn = instantiate_scev (nest, loop, access_fn); if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC) { - tree orig_type; tree memoff = TREE_OPERAND (ref, 1); - base = initial_condition (access_fn); - orig_type = TREE_TYPE (base); + tree base = initial_condition (access_fn); + tree orig_type = TREE_TYPE (base); STRIP_USELESS_TYPE_CONVERSION (base); + tree off; split_constant_offset (base, &base, &off); STRIP_USELESS_TYPE_CONVERSION (base); /* Fold the MEM_REF offset into the evolutions initial @@ -1424,7 +1421,7 @@ dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop) base, memoff); MR_DEPENDENCE_CLIQUE (ref) = MR_DEPENDENCE_CLIQUE (old); MR_DEPENDENCE_BASE (ref) = MR_DEPENDENCE_BASE (old); - DR_UNCONSTRAINED_BASE (dr) = true; + dri->unconstrained_base = true; access_fns.safe_push (access_fn); } } @@ -1436,8 +1433,8 @@ dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop) build_int_cst (reference_alias_ptr_type (ref), 0)); } - DR_BASE_OBJECT (dr) = ref; - DR_ACCESS_FNS (dr) = access_fns; + dri->base_object = ref; + dri->access_fns = access_fns; } /* Extracts the alias analysis information from the memory reference DR. */ @@ -1463,6 +1460,8 @@ void free_data_ref (data_reference_p dr) { DR_ACCESS_FNS (dr).release (); + if (dr->alt_indices.base_object) + dr->alt_indices.access_fns.release (); free (dr); } @@ -1497,7 +1496,7 @@ create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt, dr_analyze_innermost (&DR_INNERMOST (dr), memref, nest != NULL ? loop : NULL, stmt); - dr_analyze_indices (dr, nest, loop); + dr_analyze_indices (&dr->indices, DR_REF (dr), nest, loop); dr_analyze_alias (dr); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -3066,41 +3065,30 @@ access_fn_components_comparable_p (tree ref_a, tree ref_b) TREE_TYPE (TREE_OPERAND (ref_b, 0))); } -/* Initialize a data dependence relation between data accesses A and - B. NB_LOOPS is the number of loops surrounding the references: the - size of the classic distance/direction vectors. */ +/* Initialize a data dependence relation RES in LOOP_NEST. USE_ALT_INDICES + is true when the main indices of A and B were not comparable so we try again + with alternate indices computed on an indirect reference. */ struct data_dependence_relation * -initialize_data_dependence_relation (struct data_reference *a, - struct data_reference *b, - vec<loop_p> loop_nest) +initialize_data_dependence_relation (struct data_dependence_relation *res, + vec<loop_p> loop_nest, + bool use_alt_indices) { - struct data_dependence_relation *res; + struct data_reference *a = DDR_A (res); + struct data_reference *b = DDR_B (res); unsigned int i; - res = XCNEW (struct data_dependence_relation); - DDR_A (res) = a; - DDR_B (res) = b; - DDR_LOOP_NEST (res).create (0); - DDR_SUBSCRIPTS (res).create (0); - DDR_DIR_VECTS (res).create (0); - DDR_DIST_VECTS (res).create (0); - - if (a == NULL || b == NULL) + struct indices *indices_a = &a->indices; + struct indices *indices_b = &b->indices; + if (use_alt_indices) { - DDR_ARE_DEPENDENT (res) = chrec_dont_know; - return res; + if (TREE_CODE (DR_REF (a)) != MEM_REF) + indices_a = &a->alt_indices; + if (TREE_CODE (DR_REF (b)) != MEM_REF) + indices_b = &b->alt_indices; } - - /* If the data references do not alias, then they are independent. */ - if (!dr_may_alias_p (a, b, loop_nest.exists () ? loop_nest[0] : NULL)) - { - DDR_ARE_DEPENDENT (res) = chrec_known; - return res; - } - - unsigned int num_dimensions_a = DR_NUM_DIMENSIONS (a); - unsigned int num_dimensions_b = DR_NUM_DIMENSIONS (b); + unsigned int num_dimensions_a = indices_a->access_fns.length (); + unsigned int num_dimensions_b = indices_b->access_fns.length (); if (num_dimensions_a == 0 || num_dimensions_b == 0) { DDR_ARE_DEPENDENT (res) = chrec_dont_know; @@ -3125,9 +3113,9 @@ initialize_data_dependence_relation (struct data_reference *a, the a and b accesses have a single ARRAY_REF component reference [0] but have two subscripts. */ - if (DR_UNCONSTRAINED_BASE (a)) + if (indices_a->unconstrained_base) num_dimensions_a -= 1; - if (DR_UNCONSTRAINED_BASE (b)) + if (indices_b->unconstrained_base) num_dimensions_b -= 1; /* These structures describe sequences of component references in @@ -3210,6 +3198,10 @@ initialize_data_dependence_relation (struct data_reference *a, B: [3, 4] (i.e. s.e) */ while (index_a < num_dimensions_a && index_b < num_dimensions_b) { + /* The alternate indices form always has a single dimension + with unconstrained base. */ + gcc_assert (!use_alt_indices); + /* REF_A and REF_B must be one of the component access types allowed by dr_analyze_indices. */ gcc_checking_assert (access_fn_component_p (ref_a)); @@ -3280,11 +3272,12 @@ initialize_data_dependence_relation (struct data_reference *a, /* See whether FULL_SEQ ends at the base and whether the two bases are equal. We do not care about TBAA or alignment info so we can use OEP_ADDRESS_OF to avoid false negatives. */ - tree base_a = DR_BASE_OBJECT (a); - tree base_b = DR_BASE_OBJECT (b); + tree base_a = indices_a->base_object; + tree base_b = indices_b->base_object; bool same_base_p = (full_seq.start_a + full_seq.length == num_dimensions_a && full_seq.start_b + full_seq.length == num_dimensions_b - && DR_UNCONSTRAINED_BASE (a) == DR_UNCONSTRAINED_BASE (b) + && (indices_a->unconstrained_base + == indices_b->unconstrained_base) && operand_equal_p (base_a, base_b, OEP_ADDRESS_OF) && (types_compatible_p (TREE_TYPE (base_a), TREE_TYPE (base_b)) @@ -3323,7 +3316,7 @@ initialize_data_dependence_relation (struct data_reference *a, both lvalues are distinct from the object's declared type. */ if (same_base_p) { - if (DR_UNCONSTRAINED_BASE (a)) + if (indices_a->unconstrained_base) full_seq.length += 1; } else @@ -3332,8 +3325,41 @@ initialize_data_dependence_relation (struct data_reference *a, /* Punt if we didn't find a suitable sequence. */ if (full_seq.length == 0) { - DDR_ARE_DEPENDENT (res) = chrec_dont_know; - return res; + if (use_alt_indices + || (TREE_CODE (DR_REF (a)) == MEM_REF + && TREE_CODE (DR_REF (b)) == MEM_REF) + || may_be_nonaddressable_p (DR_REF (a)) + || may_be_nonaddressable_p (DR_REF (b))) + { + /* Fully exhausted possibilities. */ + DDR_ARE_DEPENDENT (res) = chrec_dont_know; + return res; + } + + /* Try evaluating both DRs as dereferences of pointers. */ + if (!a->alt_indices.base_object + && TREE_CODE (DR_REF (a)) != MEM_REF) + { + tree alt_ref = build2 (MEM_REF, TREE_TYPE (DR_REF (a)), + build1 (ADDR_EXPR, ptr_type_node, DR_REF (a)), + build_int_cst + (reference_alias_ptr_type (DR_REF (a)), 0)); + dr_analyze_indices (&a->alt_indices, alt_ref, + loop_preheader_edge (loop_nest[0]), + loop_containing_stmt (DR_STMT (a))); + } + if (!b->alt_indices.base_object + && TREE_CODE (DR_REF (b)) != MEM_REF) + { + tree alt_ref = build2 (MEM_REF, TREE_TYPE (DR_REF (b)), + build1 (ADDR_EXPR, ptr_type_node, DR_REF (b)), + build_int_cst + (reference_alias_ptr_type (DR_REF (b)), 0)); + dr_analyze_indices (&b->alt_indices, alt_ref, + loop_preheader_edge (loop_nest[0]), + loop_containing_stmt (DR_STMT (b))); + } + return initialize_data_dependence_relation (res, loop_nest, true); } if (!same_base_p) @@ -3381,8 +3407,8 @@ initialize_data_dependence_relation (struct data_reference *a, struct subscript *subscript; subscript = XNEW (struct subscript); - SUB_ACCESS_FN (subscript, 0) = DR_ACCESS_FN (a, full_seq.start_a + i); - SUB_ACCESS_FN (subscript, 1) = DR_ACCESS_FN (b, full_seq.start_b + i); + SUB_ACCESS_FN (subscript, 0) = indices_a->access_fns[full_seq.start_a + i]; + SUB_ACCESS_FN (subscript, 1) = indices_b->access_fns[full_seq.start_b + i]; SUB_CONFLICTS_IN_A (subscript) = conflict_fn_not_known (); SUB_CONFLICTS_IN_B (subscript) = conflict_fn_not_known (); SUB_LAST_CONFLICT (subscript) = chrec_dont_know; @@ -3393,6 +3419,40 @@ initialize_data_dependence_relation (struct data_reference *a, return res; } +/* Initialize a data dependence relation between data accesses A and + B. NB_LOOPS is the number of loops surrounding the references: the + size of the classic distance/direction vectors. */ + +struct data_dependence_relation * +initialize_data_dependence_relation (struct data_reference *a, + struct data_reference *b, + vec<loop_p> loop_nest) +{ + data_dependence_relation *res = XCNEW (struct data_dependence_relation); + DDR_A (res) = a; + DDR_B (res) = b; + DDR_LOOP_NEST (res).create (0); + DDR_SUBSCRIPTS (res).create (0); + DDR_DIR_VECTS (res).create (0); + DDR_DIST_VECTS (res).create (0); + + if (a == NULL || b == NULL) + { + DDR_ARE_DEPENDENT (res) = chrec_dont_know; + return res; + } + + /* If the data references do not alias, then they are independent. */ + if (!dr_may_alias_p (a, b, loop_nest.exists () ? loop_nest[0] : NULL)) + { + DDR_ARE_DEPENDENT (res) = chrec_known; + return res; + } + + return initialize_data_dependence_relation (res, loop_nest, false); +} + + /* Frees memory used by the conflict function F. */ static void diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h index 685f33d..74f579c 100644 --- a/gcc/tree-data-ref.h +++ b/gcc/tree-data-ref.h @@ -166,14 +166,19 @@ struct data_reference and runs to completion. */ bool is_conditional_in_stmt; + /* Alias information for the data reference. */ + struct dr_alias alias; + /* Behavior of the memory reference in the innermost loop. */ struct innermost_loop_behavior innermost; /* Subscripts of this data reference. */ struct indices indices; - /* Alias information for the data reference. */ - struct dr_alias alias; + /* Alternate subscripts initialized lazily and used by data-dependence + analysis only when the main indices of two DRs are not comparable. + Keep last to keep vec_info_shared::check_datarefs happy. */ + struct indices alt_indices; }; #define DR_STMT(DR) (DR)->stmt diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 32225b8..7de12f3 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1149,7 +1149,10 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) break; case OMP_CLAUSE_ORDER: - pp_string (pp, "order(concurrent)"); + pp_string (pp, "order("); + if (OMP_CLAUSE_ORDER_UNCONSTRAINED (clause)) + pp_string (pp, "unconstrained:"); + pp_string (pp, "concurrent)"); break; case OMP_CLAUSE_BIND: diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index 7c93958..7c568a4 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -199,16 +199,22 @@ static bool handle_assign (gimple_stmt_iterator *, tree, bool *, /* Sets MINMAX to either the constant value or the range VAL is in and returns either the constant value or VAL on success or null - when the range couldn't be determined. Uses RVALS when nonnull - to determine the range, otherwise uses CFUN or global range info, - whichever is nonnull. */ + when the range couldn't be determined. Uses RVALS or CFUN for + range info, whichever is nonnull. */ tree get_range (tree val, gimple *stmt, wide_int minmax[2], range_query *rvals /* = NULL */) { if (!rvals) - rvals = get_range_query (cfun); + { + if (!cfun) + /* When called from front ends for global initializers CFUN + may be null. */ + return NULL_TREE; + + rvals = get_range_query (cfun); + } value_range vr; if (!rvals->range_of_expr (vr, val, stmt)) diff --git a/gcc/tree-ssa-threadbackward.c b/gcc/tree-ssa-threadbackward.c index 805b7ac..9554207 100644 --- a/gcc/tree-ssa-threadbackward.c +++ b/gcc/tree-ssa-threadbackward.c @@ -122,7 +122,7 @@ const edge back_threader::UNREACHABLE_EDGE = (edge) -1; back_threader::back_threader (bool speed_p) : m_registry (param_max_fsm_thread_paths), m_profit (speed_p), - m_solver (m_ranger) + m_solver (m_ranger, /*resolve=*/false) { m_last_stmt = NULL; m_imports = BITMAP_ALLOC (NULL); @@ -902,15 +902,11 @@ back_threader_registry::register_path (const vec<basic_block> &m_path, edge e = find_edge (bb1, bb2); gcc_assert (e); - jump_thread_edge *x - = m_lowlevel_registry.allocate_thread_edge (e, EDGE_COPY_SRC_BLOCK); - jump_thread_path->safe_push (x); + m_lowlevel_registry.push_edge (jump_thread_path, e, EDGE_COPY_SRC_BLOCK); } - jump_thread_edge *x - = m_lowlevel_registry.allocate_thread_edge (taken_edge, - EDGE_NO_COPY_SRC_BLOCK); - jump_thread_path->safe_push (x); + m_lowlevel_registry.push_edge (jump_thread_path, + taken_edge, EDGE_NO_COPY_SRC_BLOCK); if (m_lowlevel_registry.register_jump_thread (jump_thread_path)) ++m_threaded_paths; diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 2b9a4c3..04138cb 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -898,10 +898,7 @@ jump_threader::thread_around_empty_blocks (vec<jump_thread_edge *> *path, if (!bitmap_bit_p (visited, taken_edge->dest->index)) { - jump_thread_edge *x - = m_registry->allocate_thread_edge (taken_edge, - EDGE_NO_COPY_SRC_BLOCK); - path->safe_push (x); + m_registry->push_edge (path, taken_edge, EDGE_NO_COPY_SRC_BLOCK); bitmap_set_bit (visited, taken_edge->dest->index); return thread_around_empty_blocks (path, taken_edge, visited); } @@ -942,10 +939,7 @@ jump_threader::thread_around_empty_blocks (vec<jump_thread_edge *> *path, return false; bitmap_set_bit (visited, taken_edge->dest->index); - jump_thread_edge *x - = m_registry->allocate_thread_edge (taken_edge, - EDGE_NO_COPY_SRC_BLOCK); - path->safe_push (x); + m_registry->push_edge (path, taken_edge, EDGE_NO_COPY_SRC_BLOCK); thread_around_empty_blocks (path, taken_edge, visited); return true; @@ -1051,16 +1045,9 @@ jump_threader::thread_through_normal_block (vec<jump_thread_edge *> *path, /* Only push the EDGE_START_JUMP_THREAD marker if this is first edge on the path. */ if (path->length () == 0) - { - jump_thread_edge *x - = m_registry->allocate_thread_edge (e, EDGE_START_JUMP_THREAD); - path->safe_push (x); - } + m_registry->push_edge (path, e, EDGE_START_JUMP_THREAD); - jump_thread_edge *x - = m_registry->allocate_thread_edge (taken_edge, - EDGE_COPY_SRC_BLOCK); - path->safe_push (x); + m_registry->push_edge (path, taken_edge, EDGE_COPY_SRC_BLOCK); /* See if we can thread through DEST as well, this helps capture secondary effects of threading without having to re-run DOM or @@ -1146,53 +1133,43 @@ edge_forwards_cmp_to_conditional_jump_through_empty_bb_p (edge e) void jump_threader::thread_across_edge (edge e) { - bitmap visited = BITMAP_ALLOC (NULL); + auto_bitmap visited; m_state->push (e); stmt_count = 0; vec<jump_thread_edge *> *path = m_registry->allocate_thread_path (); - bitmap_clear (visited); bitmap_set_bit (visited, e->src->index); bitmap_set_bit (visited, e->dest->index); - int threaded; + int threaded = 0; if ((e->flags & EDGE_DFS_BACK) == 0) threaded = thread_through_normal_block (path, e, visited); - else - threaded = 0; if (threaded > 0) { propagate_threaded_block_debug_into (path->last ()->e->dest, e->dest); - BITMAP_FREE (visited); m_registry->register_jump_thread (path); m_state->pop (); return; } - else - { - /* Negative and zero return values indicate no threading was possible, - thus there should be no edges on the thread path and no need to walk - through the vector entries. */ - gcc_assert (path->length () == 0); - path->release (); - /* A negative status indicates the target block was deemed too big to - duplicate. Just quit now rather than trying to use the block as - a joiner in a jump threading path. + gcc_checking_assert (path->length () == 0); + path->release (); + + if (threaded < 0) + { + /* The target block was deemed too big to duplicate. Just quit + now rather than trying to use the block as a joiner in a jump + threading path. This prevents unnecessary code growth, but more importantly if we do not look at all the statements in the block, then we may have missed some invalidations if we had traversed a backedge! */ - if (threaded < 0) - { - BITMAP_FREE (visited); - m_state->pop (); - return; - } + m_state->pop (); + return; } /* We were unable to determine what out edge from E->dest is taken. However, @@ -1217,7 +1194,6 @@ jump_threader::thread_across_edge (edge e) if (taken_edge->flags & EDGE_COMPLEX) { m_state->pop (); - BITMAP_FREE (visited); return; } @@ -1235,17 +1211,11 @@ jump_threader::thread_across_edge (edge e) bitmap_set_bit (visited, e->src->index); bitmap_set_bit (visited, e->dest->index); bitmap_set_bit (visited, taken_edge->dest->index); - vec<jump_thread_edge *> *path = m_registry->allocate_thread_path (); - /* Record whether or not we were able to thread through a successor - of E->dest. */ - jump_thread_edge *x - = m_registry->allocate_thread_edge (e, EDGE_START_JUMP_THREAD); - path->safe_push (x); + vec<jump_thread_edge *> *path = m_registry->allocate_thread_path (); + m_registry->push_edge (path, e, EDGE_START_JUMP_THREAD); + m_registry->push_edge (path, taken_edge, EDGE_COPY_SRC_JOINER_BLOCK); - x = m_registry->allocate_thread_edge (taken_edge, - EDGE_COPY_SRC_JOINER_BLOCK); - path->safe_push (x); found = thread_around_empty_blocks (path, taken_edge, visited); if (!found) @@ -1267,7 +1237,6 @@ jump_threader::thread_across_edge (edge e) m_state->pop (); } - BITMAP_FREE (visited); } m_state->pop (); diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index c5a7423..baac112 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -196,10 +196,12 @@ back_jt_path_registry::back_jt_path_registry () { } -jump_thread_edge * -jt_path_registry::allocate_thread_edge (edge e, jump_thread_edge_type t) +void +jt_path_registry::push_edge (vec<jump_thread_edge *> *path, + edge e, jump_thread_edge_type type) { - return m_allocator.allocate_thread_edge (e, t); + jump_thread_edge *x = m_allocator.allocate_thread_edge (e, type); + path->safe_push (x); } vec<jump_thread_edge *> * @@ -211,9 +213,9 @@ jt_path_registry::allocate_thread_path () /* Dump a jump threading path, including annotations about each edge in the path. */ -void +static void dump_jump_thread_path (FILE *dump_file, - const vec<jump_thread_edge *> path, + const vec<jump_thread_edge *> &path, bool registering) { fprintf (dump_file, diff --git a/gcc/tree-ssa-threadupdate.h b/gcc/tree-ssa-threadupdate.h index 94c9bc8..8b48a67 100644 --- a/gcc/tree-ssa-threadupdate.h +++ b/gcc/tree-ssa-threadupdate.h @@ -66,7 +66,7 @@ public: virtual ~jt_path_registry (); bool register_jump_thread (vec<jump_thread_edge *> *); bool thread_through_all_blocks (bool peel_loop_headers); - jump_thread_edge *allocate_thread_edge (edge e, jump_thread_edge_type t); + void push_edge (vec<jump_thread_edge *> *path, edge, jump_thread_edge_type); vec<jump_thread_edge *> *allocate_thread_path (); void debug (); protected: diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 84eadd1..d67534f 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -39,6 +39,8 @@ along with GCC; see the file COPYING3. If not see #include "calls.h" #include "gimple-range.h" +#include "gimple-predicate-analysis.h" + /* This implements the pass that does predicate aware warning on uses of possibly uninitialized variables. The pass first collects the set of possibly uninitialized SSA names. For each such name, it walks through @@ -49,19 +51,11 @@ along with GCC; see the file COPYING3. If not see default definitions or by checking if the predicate set that guards the defining paths is a superset of the use predicate. */ -/* Max PHI args we can handle in pass. */ -const unsigned max_phi_args = 32; - /* Pointer set of potentially undefined ssa names, i.e., ssa names that are defined by phi with operands that are not defined or potentially undefined. */ static hash_set<tree> *possibly_undefined_names = 0; -/* Bit mask handling macros. */ -#define MASK_SET_BIT(mask, pos) mask |= (1 << pos) -#define MASK_TEST_BIT(mask, pos) (mask & (1 << pos)) -#define MASK_EMPTY(mask) (mask == 0) - /* Returns the first bit position (starting from LSB) in mask that is non zero. Returns -1 if the mask is empty. */ static int @@ -389,23 +383,24 @@ check_defs (ao_ref *ref, tree vdef, void *data_) /* The ASAN_MARK intrinsic doesn't modify the variable. */ if (is_gimple_call (def_stmt)) { + /* The ASAN_MARK intrinsic doesn't modify the variable. */ if (gimple_call_internal_p (def_stmt) && gimple_call_internal_fn (def_stmt) == IFN_ASAN_MARK) - return false; + return false; if (tree fndecl = gimple_call_fndecl (def_stmt)) - { - /* Some sanitizer calls pass integer arguments to built-ins - that expect pointers. Avoid using gimple_call_builtin_p() - which fails for such calls. */ - if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) - { - built_in_function fncode = DECL_FUNCTION_CODE (fndecl); - if (fncode > BEGIN_SANITIZER_BUILTINS - && fncode < END_SANITIZER_BUILTINS) - return false; - } - } + { + /* Some sanitizer calls pass integer arguments to built-ins + that expect pointets. Avoid using gimple_call_builtin_p() + which fails for such calls. */ + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + { + built_in_function fncode = DECL_FUNCTION_CODE (fndecl); + if (fncode > BEGIN_SANITIZER_BUILTINS + && fncode < END_SANITIZER_BUILTINS) + return false; + } + } } /* End of VLA scope is not a kill. */ @@ -998,8 +993,8 @@ can_skip_redundant_opnd (tree opnd, gimple *phi) return true; } -/* Returns a bit mask holding the positions of arguments in PHI - that have empty (or possibly empty) definitions. */ +/* Return a bitset holding the positions of arguments in PHI with empty + (or possibly empty) definitions. */ static unsigned compute_uninit_opnds_pos (gphi *phi) @@ -1008,7 +1003,7 @@ compute_uninit_opnds_pos (gphi *phi) unsigned n = gimple_phi_num_args (phi); /* Bail out for phi with too many args. */ - if (n > max_phi_args) + if (n > predicate::func_t::max_phi_args) return 0; for (unsigned i = 0; i < n; ++i) @@ -1031,2111 +1026,32 @@ compute_uninit_opnds_pos (gphi *phi) return uninit_opnds; } -/* Find the immediate postdominator of the specified basic block BLOCK. */ - -static inline basic_block -find_pdom (basic_block block) -{ - if (block == EXIT_BLOCK_PTR_FOR_FN (cfun)) - return EXIT_BLOCK_PTR_FOR_FN (cfun); - else - { - basic_block bb = get_immediate_dominator (CDI_POST_DOMINATORS, block); - if (!bb) - return EXIT_BLOCK_PTR_FOR_FN (cfun); - return bb; - } -} - -/* Find the immediate dominator of the specified basic block BLOCK. */ - -static inline basic_block -find_dom (basic_block block) -{ - if (block == ENTRY_BLOCK_PTR_FOR_FN (cfun)) - return ENTRY_BLOCK_PTR_FOR_FN (cfun); - else - { - basic_block bb = get_immediate_dominator (CDI_DOMINATORS, block); - if (!bb) - return ENTRY_BLOCK_PTR_FOR_FN (cfun); - return bb; - } -} - -/* Returns true if BB1 is postdominating BB2 and BB1 is - not a loop exit bb. The loop exit bb check is simple and does - not cover all cases. */ - -static bool -is_non_loop_exit_postdominating (basic_block bb1, basic_block bb2) -{ - if (!dominated_by_p (CDI_POST_DOMINATORS, bb2, bb1)) - return false; - - if (single_pred_p (bb1) && !single_succ_p (bb2)) - return false; - - return true; -} - -/* Find the closest postdominator of a specified BB, which is control - equivalent to BB. */ - -static inline basic_block -find_control_equiv_block (basic_block bb) -{ - basic_block pdom = find_pdom (bb); - - /* Skip the postdominating bb that is also loop exit. */ - if (!is_non_loop_exit_postdominating (pdom, bb)) - return NULL; - - if (dominated_by_p (CDI_DOMINATORS, pdom, bb)) - return pdom; - - return NULL; -} - -#define MAX_NUM_CHAINS 8 -#define MAX_CHAIN_LEN 5 -#define MAX_POSTDOM_CHECK 8 -#define MAX_SWITCH_CASES 40 +/* Function object type used to determine whether an expression + is of interest to the predicate analyzer. */ -/* Computes the control dependence chains (paths of edges) - for DEP_BB up to the dominating basic block BB (the head node of a - chain should be dominated by it). CD_CHAINS is pointer to an - array holding the result chains. CUR_CD_CHAIN is the current - chain being computed. *NUM_CHAINS is total number of chains. The - function returns true if the information is successfully computed, - return false if there is no control dependence or not computed. */ - -static bool -compute_control_dep_chain (basic_block bb, basic_block dep_bb, - vec<edge> *cd_chains, - size_t *num_chains, - vec<edge> *cur_cd_chain, - int *num_calls) +struct uninit_undef_val_t: public predicate::func_t { - edge_iterator ei; - edge e; - size_t i; - bool found_cd_chain = false; - size_t cur_chain_len = 0; - - if (*num_calls > param_uninit_control_dep_attempts) - return false; - ++*num_calls; - - /* Could use a set instead. */ - cur_chain_len = cur_cd_chain->length (); - if (cur_chain_len > MAX_CHAIN_LEN) - return false; - - for (i = 0; i < cur_chain_len; i++) - { - edge e = (*cur_cd_chain)[i]; - /* Cycle detected. */ - if (e->src == bb) - return false; - } - - FOR_EACH_EDGE (e, ei, bb->succs) - { - basic_block cd_bb; - int post_dom_check = 0; - if (e->flags & (EDGE_FAKE | EDGE_ABNORMAL)) - continue; - - cd_bb = e->dest; - cur_cd_chain->safe_push (e); - while (!is_non_loop_exit_postdominating (cd_bb, bb)) - { - if (cd_bb == dep_bb) - { - /* Found a direct control dependence. */ - if (*num_chains < MAX_NUM_CHAINS) - { - cd_chains[*num_chains] = cur_cd_chain->copy (); - (*num_chains)++; - } - found_cd_chain = true; - /* Check path from next edge. */ - break; - } - - /* Now check if DEP_BB is indirectly control dependent on BB. */ - if (compute_control_dep_chain (cd_bb, dep_bb, cd_chains, num_chains, - cur_cd_chain, num_calls)) - { - found_cd_chain = true; - break; - } - - cd_bb = find_pdom (cd_bb); - post_dom_check++; - if (cd_bb == EXIT_BLOCK_PTR_FOR_FN (cfun) - || post_dom_check > MAX_POSTDOM_CHECK) - break; - } - cur_cd_chain->pop (); - gcc_assert (cur_cd_chain->length () == cur_chain_len); - } - gcc_assert (cur_cd_chain->length () == cur_chain_len); - - return found_cd_chain; -} - -/* The type to represent a simple predicate. */ - -struct pred_info -{ - tree pred_lhs; - tree pred_rhs; - enum tree_code cond_code; - bool invert; + virtual bool operator()(tree) override; + virtual unsigned phi_arg_set (gphi *) override; }; -/* The type to represent a sequence of predicates grouped - with .AND. operation. */ - -typedef vec<pred_info, va_heap, vl_ptr> pred_chain; - -/* The type to represent a sequence of pred_chains grouped - with .OR. operation. */ - -typedef vec<pred_chain, va_heap, vl_ptr> pred_chain_union; - -/* Converts the chains of control dependence edges into a set of - predicates. A control dependence chain is represented by a vector - edges. DEP_CHAINS points to an array of dependence chains. - NUM_CHAINS is the size of the chain array. One edge in a dependence - chain is mapped to predicate expression represented by pred_info - type. One dependence chain is converted to a composite predicate that - is the result of AND operation of pred_info mapped to each edge. - A composite predicate is presented by a vector of pred_info. On - return, *PREDS points to the resulting array of composite predicates. - *NUM_PREDS is the number of composite predictes. */ - -static bool -convert_control_dep_chain_into_preds (vec<edge> *dep_chains, - size_t num_chains, - pred_chain_union *preds) -{ - bool has_valid_pred = false; - size_t i, j; - if (num_chains == 0 || num_chains >= MAX_NUM_CHAINS) - return false; - - /* Now convert the control dep chain into a set - of predicates. */ - preds->reserve (num_chains); - - for (i = 0; i < num_chains; i++) - { - vec<edge> one_cd_chain = dep_chains[i]; - - has_valid_pred = false; - pred_chain t_chain = vNULL; - for (j = 0; j < one_cd_chain.length (); j++) - { - gimple *cond_stmt; - gimple_stmt_iterator gsi; - basic_block guard_bb; - pred_info one_pred; - edge e; - - e = one_cd_chain[j]; - guard_bb = e->src; - gsi = gsi_last_bb (guard_bb); - /* Ignore empty forwarder blocks. */ - if (empty_block_p (guard_bb) && single_succ_p (guard_bb)) - continue; - /* An empty basic block here is likely a PHI, and is not one - of the cases we handle below. */ - if (gsi_end_p (gsi)) - { - has_valid_pred = false; - break; - } - cond_stmt = gsi_stmt (gsi); - if (is_gimple_call (cond_stmt) && EDGE_COUNT (e->src->succs) >= 2) - /* Ignore EH edge. Can add assertion on the other edge's flag. */ - continue; - /* Skip if there is essentially one succesor. */ - if (EDGE_COUNT (e->src->succs) == 2) - { - edge e1; - edge_iterator ei1; - bool skip = false; - - FOR_EACH_EDGE (e1, ei1, e->src->succs) - { - if (EDGE_COUNT (e1->dest->succs) == 0) - { - skip = true; - break; - } - } - if (skip) - continue; - } - if (gimple_code (cond_stmt) == GIMPLE_COND) - { - one_pred.pred_lhs = gimple_cond_lhs (cond_stmt); - one_pred.pred_rhs = gimple_cond_rhs (cond_stmt); - one_pred.cond_code = gimple_cond_code (cond_stmt); - one_pred.invert = !!(e->flags & EDGE_FALSE_VALUE); - t_chain.safe_push (one_pred); - has_valid_pred = true; - } - else if (gswitch *gs = dyn_cast<gswitch *> (cond_stmt)) - { - /* Avoid quadratic behavior. */ - if (gimple_switch_num_labels (gs) > MAX_SWITCH_CASES) - { - has_valid_pred = false; - break; - } - /* Find the case label. */ - tree l = NULL_TREE; - unsigned idx; - for (idx = 0; idx < gimple_switch_num_labels (gs); ++idx) - { - tree tl = gimple_switch_label (gs, idx); - if (e->dest == label_to_block (cfun, CASE_LABEL (tl))) - { - if (!l) - l = tl; - else - { - l = NULL_TREE; - break; - } - } - } - /* If more than one label reaches this block or the case - label doesn't have a single value (like the default one) - fail. */ - if (!l - || !CASE_LOW (l) - || (CASE_HIGH (l) - && !operand_equal_p (CASE_LOW (l), CASE_HIGH (l), 0))) - { - has_valid_pred = false; - break; - } - one_pred.pred_lhs = gimple_switch_index (gs); - one_pred.pred_rhs = CASE_LOW (l); - one_pred.cond_code = EQ_EXPR; - one_pred.invert = false; - t_chain.safe_push (one_pred); - has_valid_pred = true; - } - else - { - has_valid_pred = false; - break; - } - } - - if (!has_valid_pred) - break; - else - preds->safe_push (t_chain); - } - return has_valid_pred; -} - -/* Computes all control dependence chains for USE_BB. The control - dependence chains are then converted to an array of composite - predicates pointed to by PREDS. PHI_BB is the basic block of - the phi whose result is used in USE_BB. */ - -static bool -find_predicates (pred_chain_union *preds, - basic_block phi_bb, - basic_block use_bb) -{ - size_t num_chains = 0, i; - int num_calls = 0; - vec<edge> dep_chains[MAX_NUM_CHAINS]; - auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain; - bool has_valid_pred = false; - basic_block cd_root = 0; - - /* First find the closest bb that is control equivalent to PHI_BB - that also dominates USE_BB. */ - cd_root = phi_bb; - while (dominated_by_p (CDI_DOMINATORS, use_bb, cd_root)) - { - basic_block ctrl_eq_bb = find_control_equiv_block (cd_root); - if (ctrl_eq_bb && dominated_by_p (CDI_DOMINATORS, use_bb, ctrl_eq_bb)) - cd_root = ctrl_eq_bb; - else - break; - } - - compute_control_dep_chain (cd_root, use_bb, dep_chains, &num_chains, - &cur_chain, &num_calls); - - has_valid_pred - = convert_control_dep_chain_into_preds (dep_chains, num_chains, preds); - for (i = 0; i < num_chains; i++) - dep_chains[i].release (); - return has_valid_pred; -} - -/* Computes the set of incoming edges of PHI that have non empty - definitions of a phi chain. The collection will be done - recursively on operands that are defined by phis. CD_ROOT - is the control dependence root. *EDGES holds the result, and - VISITED_PHIS is a pointer set for detecting cycles. */ - -static void -collect_phi_def_edges (gphi *phi, basic_block cd_root, - auto_vec<edge> *edges, - hash_set<gimple *> *visited_phis) -{ - size_t i, n; - edge opnd_edge; - tree opnd; - - if (visited_phis->add (phi)) - return; - - n = gimple_phi_num_args (phi); - for (i = 0; i < n; i++) - { - opnd_edge = gimple_phi_arg_edge (phi, i); - opnd = gimple_phi_arg_def (phi, i); - - if (TREE_CODE (opnd) != SSA_NAME) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "\n[CHECK] Found def edge %d in ", (int) i); - print_gimple_stmt (dump_file, phi, 0); - } - edges->safe_push (opnd_edge); - } - else - { - gimple *def = SSA_NAME_DEF_STMT (opnd); - - if (gimple_code (def) == GIMPLE_PHI - && dominated_by_p (CDI_DOMINATORS, gimple_bb (def), cd_root)) - collect_phi_def_edges (as_a<gphi *> (def), cd_root, edges, - visited_phis); - else if (!uninit_undefined_value_p (opnd)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "\n[CHECK] Found def edge %d in ", - (int) i); - print_gimple_stmt (dump_file, phi, 0); - } - edges->safe_push (opnd_edge); - } - } - } -} - -/* For each use edge of PHI, computes all control dependence chains. - The control dependence chains are then converted to an array of - composite predicates pointed to by PREDS. */ - -static bool -find_def_preds (pred_chain_union *preds, gphi *phi) -{ - size_t num_chains = 0, i, n; - vec<edge> dep_chains[MAX_NUM_CHAINS]; - auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain; - auto_vec<edge> def_edges; - bool has_valid_pred = false; - basic_block phi_bb, cd_root = 0; - - phi_bb = gimple_bb (phi); - /* First find the closest dominating bb to be - the control dependence root. */ - cd_root = find_dom (phi_bb); - if (!cd_root) - return false; - - hash_set<gimple *> visited_phis; - collect_phi_def_edges (phi, cd_root, &def_edges, &visited_phis); - - n = def_edges.length (); - if (n == 0) - return false; - - for (i = 0; i < n; i++) - { - size_t prev_nc, j; - int num_calls = 0; - edge opnd_edge; - - opnd_edge = def_edges[i]; - prev_nc = num_chains; - compute_control_dep_chain (cd_root, opnd_edge->src, dep_chains, - &num_chains, &cur_chain, &num_calls); - - /* Now update the newly added chains with - the phi operand edge: */ - if (EDGE_COUNT (opnd_edge->src->succs) > 1) - { - if (prev_nc == num_chains && num_chains < MAX_NUM_CHAINS) - dep_chains[num_chains++] = vNULL; - for (j = prev_nc; j < num_chains; j++) - dep_chains[j].safe_push (opnd_edge); - } - } - - has_valid_pred - = convert_control_dep_chain_into_preds (dep_chains, num_chains, preds); - for (i = 0; i < num_chains; i++) - dep_chains[i].release (); - return has_valid_pred; -} - -/* Dump a pred_info. */ - -static void -dump_pred_info (pred_info one_pred) -{ - if (one_pred.invert) - fprintf (dump_file, " (.NOT.) "); - print_generic_expr (dump_file, one_pred.pred_lhs); - fprintf (dump_file, " %s ", op_symbol_code (one_pred.cond_code)); - print_generic_expr (dump_file, one_pred.pred_rhs); -} - -/* Dump a pred_chain. */ - -static void -dump_pred_chain (pred_chain one_pred_chain) -{ - size_t np = one_pred_chain.length (); - for (size_t j = 0; j < np; j++) - { - dump_pred_info (one_pred_chain[j]); - if (j < np - 1) - fprintf (dump_file, " (.AND.) "); - else - fprintf (dump_file, "\n"); - } -} - -/* Dumps the predicates (PREDS) for USESTMT. */ - -static void -dump_predicates (gimple *usestmt, pred_chain_union preds, const char *msg) -{ - fprintf (dump_file, "%s", msg); - if (usestmt) - { - print_gimple_stmt (dump_file, usestmt, 0); - fprintf (dump_file, "is guarded by :\n\n"); - } - size_t num_preds = preds.length (); - for (size_t i = 0; i < num_preds; i++) - { - dump_pred_chain (preds[i]); - if (i < num_preds - 1) - fprintf (dump_file, "(.OR.)\n"); - else - fprintf (dump_file, "\n\n"); - } -} - -/* Destroys the predicate set *PREDS. */ - -static void -destroy_predicate_vecs (pred_chain_union *preds) -{ - size_t i; - - size_t n = preds->length (); - for (i = 0; i < n; i++) - (*preds)[i].release (); - preds->release (); -} - -/* Computes the 'normalized' conditional code with operand - swapping and condition inversion. */ - -static enum tree_code -get_cmp_code (enum tree_code orig_cmp_code, bool swap_cond, bool invert) -{ - enum tree_code tc = orig_cmp_code; - - if (swap_cond) - tc = swap_tree_comparison (orig_cmp_code); - if (invert) - tc = invert_tree_comparison (tc, false); - - switch (tc) - { - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - break; - default: - return ERROR_MARK; - } - return tc; -} - -/* Returns whether VAL CMPC BOUNDARY is true. */ - -static bool -is_value_included_in (tree val, tree boundary, enum tree_code cmpc) -{ - bool inverted = false; - bool result; - - /* Only handle integer constant here. */ - if (TREE_CODE (val) != INTEGER_CST || TREE_CODE (boundary) != INTEGER_CST) - return true; - - if (cmpc == GE_EXPR || cmpc == GT_EXPR || cmpc == NE_EXPR) - { - cmpc = invert_tree_comparison (cmpc, false); - inverted = true; - } - - if (cmpc == EQ_EXPR) - result = tree_int_cst_equal (val, boundary); - else if (cmpc == LT_EXPR) - result = tree_int_cst_lt (val, boundary); - else - { - gcc_assert (cmpc == LE_EXPR); - result = tree_int_cst_le (val, boundary); - } - - if (inverted) - result ^= 1; - - return result; -} - -/* Returns whether VAL satisfies (x CMPC BOUNDARY) predicate. CMPC can be - either one of the range comparison codes ({GE,LT,EQ,NE}_EXPR and the like), - or BIT_AND_EXPR. EXACT_P is only meaningful for the latter. It modifies the - question from whether VAL & BOUNDARY != 0 to whether VAL & BOUNDARY == VAL. - For other values of CMPC, EXACT_P is ignored. */ - -static bool -value_sat_pred_p (tree val, tree boundary, enum tree_code cmpc, - bool exact_p = false) -{ - if (cmpc != BIT_AND_EXPR) - return is_value_included_in (val, boundary, cmpc); - - wide_int andw = wi::to_wide (val) & wi::to_wide (boundary); - if (exact_p) - return andw == wi::to_wide (val); - else - return andw.to_uhwi (); -} - -/* Returns true if PRED is common among all the predicate - chains (PREDS) (and therefore can be factored out). */ +/* Return true if the argument is an expression of interest. */ -static bool -find_matching_predicate_in_rest_chains (pred_info pred, pred_chain_union preds) -{ - size_t i, j, n; - - /* Trival case. */ - if (preds.length () == 1) - return true; - - for (i = 1; i < preds.length (); i++) - { - bool found = false; - pred_chain one_chain = preds[i]; - n = one_chain.length (); - for (j = 0; j < n; j++) - { - pred_info pred2 = one_chain[j]; - /* Can relax the condition comparison to not - use address comparison. However, the most common - case is that multiple control dependent paths share - a common path prefix, so address comparison should - be ok. */ - - if (operand_equal_p (pred2.pred_lhs, pred.pred_lhs, 0) - && operand_equal_p (pred2.pred_rhs, pred.pred_rhs, 0) - && pred2.invert == pred.invert) - { - found = true; - break; - } - } - if (!found) - return false; - } - return true; -} - -/* Forward declaration. */ -static bool is_use_properly_guarded (gimple *use_stmt, - basic_block use_bb, - gphi *phi, - unsigned uninit_opnds, - pred_chain_union *def_preds, - hash_set<gphi *> *visited_phis); - -/* Returns true if all uninitialized opnds are pruned. Returns false - otherwise. PHI is the phi node with uninitialized operands, - UNINIT_OPNDS is the bitmap of the uninitialize operand positions, - FLAG_DEF is the statement defining the flag guarding the use of the - PHI output, BOUNDARY_CST is the const value used in the predicate - associated with the flag, CMP_CODE is the comparison code used in - the predicate, VISITED_PHIS is the pointer set of phis visited, and - VISITED_FLAG_PHIS is the pointer to the pointer set of flag definitions - that are also phis. - - Example scenario: - - BB1: - flag_1 = phi <0, 1> // (1) - var_1 = phi <undef, some_val> - - - BB2: - flag_2 = phi <0, flag_1, flag_1> // (2) - var_2 = phi <undef, var_1, var_1> - if (flag_2 == 1) - goto BB3; - - BB3: - use of var_2 // (3) - - Because some flag arg in (1) is not constant, if we do not look into the - flag phis recursively, it is conservatively treated as unknown and var_1 - is thought to be flowed into use at (3). Since var_1 is potentially - uninitialized a false warning will be emitted. - Checking recursively into (1), the compiler can find out that only some_val - (which is defined) can flow into (3) which is OK. */ - -static bool -prune_uninit_phi_opnds (gphi *phi, unsigned uninit_opnds, gphi *flag_def, - tree boundary_cst, enum tree_code cmp_code, - hash_set<gphi *> *visited_phis, - bitmap *visited_flag_phis) +bool +uninit_undef_val_t::operator()(tree val) { - unsigned i; - - for (i = 0; i < MIN (max_phi_args, gimple_phi_num_args (flag_def)); i++) - { - tree flag_arg; - - if (!MASK_TEST_BIT (uninit_opnds, i)) - continue; - - flag_arg = gimple_phi_arg_def (flag_def, i); - if (!is_gimple_constant (flag_arg)) - { - gphi *flag_arg_def, *phi_arg_def; - tree phi_arg; - unsigned uninit_opnds_arg_phi; - - if (TREE_CODE (flag_arg) != SSA_NAME) - return false; - flag_arg_def = dyn_cast<gphi *> (SSA_NAME_DEF_STMT (flag_arg)); - if (!flag_arg_def) - return false; - - phi_arg = gimple_phi_arg_def (phi, i); - if (TREE_CODE (phi_arg) != SSA_NAME) - return false; - - phi_arg_def = dyn_cast<gphi *> (SSA_NAME_DEF_STMT (phi_arg)); - if (!phi_arg_def) - return false; - - if (gimple_bb (phi_arg_def) != gimple_bb (flag_arg_def)) - return false; - - if (!*visited_flag_phis) - *visited_flag_phis = BITMAP_ALLOC (NULL); - - tree phi_result = gimple_phi_result (flag_arg_def); - if (bitmap_bit_p (*visited_flag_phis, SSA_NAME_VERSION (phi_result))) - return false; - - bitmap_set_bit (*visited_flag_phis, - SSA_NAME_VERSION (gimple_phi_result (flag_arg_def))); - - /* Now recursively prune the uninitialized phi args. */ - uninit_opnds_arg_phi = compute_uninit_opnds_pos (phi_arg_def); - if (!prune_uninit_phi_opnds - (phi_arg_def, uninit_opnds_arg_phi, flag_arg_def, boundary_cst, - cmp_code, visited_phis, visited_flag_phis)) - return false; - - phi_result = gimple_phi_result (flag_arg_def); - bitmap_clear_bit (*visited_flag_phis, SSA_NAME_VERSION (phi_result)); - continue; - } - - /* Now check if the constant is in the guarded range. */ - if (is_value_included_in (flag_arg, boundary_cst, cmp_code)) - { - tree opnd; - gimple *opnd_def; - - /* Now that we know that this undefined edge is not - pruned. If the operand is defined by another phi, - we can further prune the incoming edges of that - phi by checking the predicates of this operands. */ - - opnd = gimple_phi_arg_def (phi, i); - opnd_def = SSA_NAME_DEF_STMT (opnd); - if (gphi *opnd_def_phi = dyn_cast <gphi *> (opnd_def)) - { - edge opnd_edge; - unsigned uninit_opnds2 = compute_uninit_opnds_pos (opnd_def_phi); - if (!MASK_EMPTY (uninit_opnds2)) - { - pred_chain_union def_preds = vNULL; - bool ok; - opnd_edge = gimple_phi_arg_edge (phi, i); - ok = is_use_properly_guarded (phi, - opnd_edge->src, - opnd_def_phi, - uninit_opnds2, - &def_preds, - visited_phis); - destroy_predicate_vecs (&def_preds); - if (!ok) - return false; - } - } - else - return false; - } - } - - return true; -} - -/* A helper function finds predicate which will be examined against uninit - paths. If there is no "flag_var cmp const" form predicate, the function - tries to find predicate of form like "flag_var cmp flag_var" with value - range info. PHI is the phi node whose incoming (undefined) paths need to - be examined. On success, the function returns the comparsion code, sets - defintion gimple of the flag_var to FLAG_DEF, sets boundary_cst to - BOUNDARY_CST. On fail, the function returns ERROR_MARK. */ - -static enum tree_code -find_var_cmp_const (pred_chain_union preds, gphi *phi, gimple **flag_def, - tree *boundary_cst) -{ - enum tree_code vrinfo_code = ERROR_MARK, code; - gimple *vrinfo_def = NULL; - tree vrinfo_cst = NULL, cond_lhs, cond_rhs; - - gcc_assert (preds.length () > 0); - pred_chain the_pred_chain = preds[0]; - for (unsigned i = 0; i < the_pred_chain.length (); i++) - { - bool use_vrinfo_p = false; - pred_info the_pred = the_pred_chain[i]; - cond_lhs = the_pred.pred_lhs; - cond_rhs = the_pred.pred_rhs; - if (cond_lhs == NULL_TREE || cond_rhs == NULL_TREE) - continue; - - code = get_cmp_code (the_pred.cond_code, false, the_pred.invert); - if (code == ERROR_MARK) - continue; - - if (TREE_CODE (cond_lhs) == SSA_NAME && is_gimple_constant (cond_rhs)) - ; - else if (TREE_CODE (cond_rhs) == SSA_NAME - && is_gimple_constant (cond_lhs)) - { - std::swap (cond_lhs, cond_rhs); - if ((code = get_cmp_code (code, true, false)) == ERROR_MARK) - continue; - } - /* Check if we can take advantage of "flag_var comp flag_var" predicate - with value range info. Note only first of such case is handled. */ - else if (vrinfo_code == ERROR_MARK - && TREE_CODE (cond_lhs) == SSA_NAME - && TREE_CODE (cond_rhs) == SSA_NAME) - { - gimple* lhs_def = SSA_NAME_DEF_STMT (cond_lhs); - if (!lhs_def || gimple_code (lhs_def) != GIMPLE_PHI - || gimple_bb (lhs_def) != gimple_bb (phi)) - { - std::swap (cond_lhs, cond_rhs); - if ((code = get_cmp_code (code, true, false)) == ERROR_MARK) - continue; - } - - /* Check value range info of rhs, do following transforms: - flag_var < [min, max] -> flag_var < max - flag_var > [min, max] -> flag_var > min - - We can also transform LE_EXPR/GE_EXPR to LT_EXPR/GT_EXPR: - flag_var <= [min, max] -> flag_var < [min, max+1] - flag_var >= [min, max] -> flag_var > [min-1, max] - if no overflow/wrap. */ - tree type = TREE_TYPE (cond_lhs); - value_range r; - if (!INTEGRAL_TYPE_P (type) - || !get_range_query (cfun)->range_of_expr (r, cond_rhs) - || r.kind () != VR_RANGE) - continue; - wide_int min = r.lower_bound (); - wide_int max = r.upper_bound (); - if (code == LE_EXPR - && max != wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type))) - { - code = LT_EXPR; - max = max + 1; - } - if (code == GE_EXPR - && min != wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type))) - { - code = GT_EXPR; - min = min - 1; - } - if (code == LT_EXPR) - cond_rhs = wide_int_to_tree (type, max); - else if (code == GT_EXPR) - cond_rhs = wide_int_to_tree (type, min); - else - continue; - - use_vrinfo_p = true; - } - else - continue; - - if ((*flag_def = SSA_NAME_DEF_STMT (cond_lhs)) == NULL) - continue; - - if (gimple_code (*flag_def) != GIMPLE_PHI - || gimple_bb (*flag_def) != gimple_bb (phi) - || !find_matching_predicate_in_rest_chains (the_pred, preds)) - continue; - - /* Return if any "flag_var comp const" predicate is found. */ - if (!use_vrinfo_p) - { - *boundary_cst = cond_rhs; - return code; - } - /* Record if any "flag_var comp flag_var[vinfo]" predicate is found. */ - else if (vrinfo_code == ERROR_MARK) - { - vrinfo_code = code; - vrinfo_def = *flag_def; - vrinfo_cst = cond_rhs; - } - } - /* Return the "flag_var cmp flag_var[vinfo]" predicate we found. */ - if (vrinfo_code != ERROR_MARK) - { - *flag_def = vrinfo_def; - *boundary_cst = vrinfo_cst; - } - return vrinfo_code; -} - -/* A helper function that determines if the predicate set - of the use is not overlapping with that of the uninit paths. - The most common senario of guarded use is in Example 1: - Example 1: - if (some_cond) - { - x = ...; - flag = true; - } - - ... some code ... - - if (flag) - use (x); - - The real world examples are usually more complicated, but similar - and usually result from inlining: - - bool init_func (int * x) - { - if (some_cond) - return false; - *x = .. - return true; - } - - void foo (..) - { - int x; - - if (!init_func (&x)) - return; - - .. some_code ... - use (x); - } - - Another possible use scenario is in the following trivial example: - - Example 2: - if (n > 0) - x = 1; - ... - if (n > 0) - { - if (m < 2) - .. = x; - } - - Predicate analysis needs to compute the composite predicate: - - 1) 'x' use predicate: (n > 0) .AND. (m < 2) - 2) 'x' default value (non-def) predicate: .NOT. (n > 0) - (the predicate chain for phi operand defs can be computed - starting from a bb that is control equivalent to the phi's - bb and is dominating the operand def.) - - and check overlapping: - (n > 0) .AND. (m < 2) .AND. (.NOT. (n > 0)) - <==> false - - This implementation provides framework that can handle - scenarios. (Note that many simple cases are handled properly - without the predicate analysis -- this is due to jump threading - transformation which eliminates the merge point thus makes - path sensitive analysis unnecessary.) - - PHI is the phi node whose incoming (undefined) paths need to be - pruned, and UNINIT_OPNDS is the bitmap holding uninit operand - positions. VISITED_PHIS is the pointer set of phi stmts being - checked. */ - -static bool -use_pred_not_overlap_with_undef_path_pred (pred_chain_union preds, - gphi *phi, unsigned uninit_opnds, - hash_set<gphi *> *visited_phis) -{ - gimple *flag_def = 0; - tree boundary_cst = 0; - enum tree_code cmp_code; - bitmap visited_flag_phis = NULL; - bool all_pruned = false; - - /* Find within the common prefix of multiple predicate chains - a predicate that is a comparison of a flag variable against - a constant. */ - cmp_code = find_var_cmp_const (preds, phi, &flag_def, &boundary_cst); - if (cmp_code == ERROR_MARK) - return false; - - /* Now check all the uninit incoming edge has a constant flag value - that is in conflict with the use guard/predicate. */ - all_pruned = prune_uninit_phi_opnds - (phi, uninit_opnds, as_a<gphi *> (flag_def), boundary_cst, cmp_code, - visited_phis, &visited_flag_phis); - - if (visited_flag_phis) - BITMAP_FREE (visited_flag_phis); - - return all_pruned; -} - -/* The helper function returns true if two predicates X1 and X2 - are equivalent. It assumes the expressions have already - properly re-associated. */ - -static inline bool -pred_equal_p (pred_info x1, pred_info x2) -{ - enum tree_code c1, c2; - if (!operand_equal_p (x1.pred_lhs, x2.pred_lhs, 0) - || !operand_equal_p (x1.pred_rhs, x2.pred_rhs, 0)) - return false; - - c1 = x1.cond_code; - if (x1.invert != x2.invert - && TREE_CODE_CLASS (x2.cond_code) == tcc_comparison) - c2 = invert_tree_comparison (x2.cond_code, false); - else - c2 = x2.cond_code; - - return c1 == c2; -} - -/* Returns true if the predication is testing !=. */ - -static inline bool -is_neq_relop_p (pred_info pred) -{ - - return ((pred.cond_code == NE_EXPR && !pred.invert) - || (pred.cond_code == EQ_EXPR && pred.invert)); -} - -/* Returns true if pred is of the form X != 0. */ - -static inline bool -is_neq_zero_form_p (pred_info pred) -{ - if (!is_neq_relop_p (pred) || !integer_zerop (pred.pred_rhs) - || TREE_CODE (pred.pred_lhs) != SSA_NAME) - return false; - return true; -} - -/* The helper function returns true if two predicates X1 - is equivalent to X2 != 0. */ - -static inline bool -pred_expr_equal_p (pred_info x1, tree x2) -{ - if (!is_neq_zero_form_p (x1)) - return false; - - return operand_equal_p (x1.pred_lhs, x2, 0); -} - -/* Returns true of the domain of single predicate expression - EXPR1 is a subset of that of EXPR2. Returns false if it - cannot be proved. */ - -static bool -is_pred_expr_subset_of (pred_info expr1, pred_info expr2) -{ - enum tree_code code1, code2; - - if (pred_equal_p (expr1, expr2)) - return true; - - if ((TREE_CODE (expr1.pred_rhs) != INTEGER_CST) - || (TREE_CODE (expr2.pred_rhs) != INTEGER_CST)) - return false; - - if (!operand_equal_p (expr1.pred_lhs, expr2.pred_lhs, 0)) - return false; - - code1 = expr1.cond_code; - if (expr1.invert) - code1 = invert_tree_comparison (code1, false); - code2 = expr2.cond_code; - if (expr2.invert) - code2 = invert_tree_comparison (code2, false); - - if (code2 == NE_EXPR && code1 == NE_EXPR) - return false; - - if (code2 == NE_EXPR) - return !value_sat_pred_p (expr2.pred_rhs, expr1.pred_rhs, code1); - - if (code1 == EQ_EXPR) - return value_sat_pred_p (expr1.pred_rhs, expr2.pred_rhs, code2); - - if (code1 == code2) - return value_sat_pred_p (expr1.pred_rhs, expr2.pred_rhs, code2, - code1 == BIT_AND_EXPR); + if (TREE_CODE (val) == SSA_NAME) + return uninit_undefined_value_p (val); return false; } -/* Returns true if the domain of PRED1 is a subset - of that of PRED2. Returns false if it cannot be proved so. */ +/* Return a bitset of PHI arguments of interest. */ -static bool -is_pred_chain_subset_of (pred_chain pred1, pred_chain pred2) +unsigned +uninit_undef_val_t::phi_arg_set (gphi *phi) { - size_t np1, np2, i1, i2; - - np1 = pred1.length (); - np2 = pred2.length (); - - for (i2 = 0; i2 < np2; i2++) - { - bool found = false; - pred_info info2 = pred2[i2]; - for (i1 = 0; i1 < np1; i1++) - { - pred_info info1 = pred1[i1]; - if (is_pred_expr_subset_of (info1, info2)) - { - found = true; - break; - } - } - if (!found) - return false; - } - return true; -} - -/* Returns true if the domain defined by - one pred chain ONE_PRED is a subset of the domain - of *PREDS. It returns false if ONE_PRED's domain is - not a subset of any of the sub-domains of PREDS - (corresponding to each individual chains in it), even - though it may be still be a subset of whole domain - of PREDS which is the union (ORed) of all its subdomains. - In other words, the result is conservative. */ - -static bool -is_included_in (pred_chain one_pred, pred_chain_union preds) -{ - size_t i; - size_t n = preds.length (); - - for (i = 0; i < n; i++) - { - if (is_pred_chain_subset_of (one_pred, preds[i])) - return true; - } - - return false; -} - -/* Compares two predicate sets PREDS1 and PREDS2 and returns - true if the domain defined by PREDS1 is a superset - of PREDS2's domain. N1 and N2 are array sizes of PREDS1 and - PREDS2 respectively. The implementation chooses not to build - generic trees (and relying on the folding capability of the - compiler), but instead performs brute force comparison of - individual predicate chains (won't be a compile time problem - as the chains are pretty short). When the function returns - false, it does not necessarily mean *PREDS1 is not a superset - of *PREDS2, but mean it may not be so since the analysis cannot - prove it. In such cases, false warnings may still be - emitted. */ - -static bool -is_superset_of (pred_chain_union preds1, pred_chain_union preds2) -{ - size_t i, n2; - pred_chain one_pred_chain = vNULL; - - n2 = preds2.length (); - - for (i = 0; i < n2; i++) - { - one_pred_chain = preds2[i]; - if (!is_included_in (one_pred_chain, preds1)) - return false; - } - - return true; -} - -/* Returns true if X1 is the negate of X2. */ - -static inline bool -pred_neg_p (pred_info x1, pred_info x2) -{ - enum tree_code c1, c2; - if (!operand_equal_p (x1.pred_lhs, x2.pred_lhs, 0) - || !operand_equal_p (x1.pred_rhs, x2.pred_rhs, 0)) - return false; - - c1 = x1.cond_code; - if (x1.invert == x2.invert) - c2 = invert_tree_comparison (x2.cond_code, false); - else - c2 = x2.cond_code; - - return c1 == c2; -} - -/* 1) ((x IOR y) != 0) AND (x != 0) is equivalent to (x != 0); - 2) (X AND Y) OR (!X AND Y) is equivalent to Y; - 3) X OR (!X AND Y) is equivalent to (X OR Y); - 4) ((x IAND y) != 0) || (x != 0 AND y != 0)) is equivalent to - (x != 0 AND y != 0) - 5) (X AND Y) OR (!X AND Z) OR (!Y AND Z) is equivalent to - (X AND Y) OR Z - - PREDS is the predicate chains, and N is the number of chains. */ - -/* Helper function to implement rule 1 above. ONE_CHAIN is - the AND predication to be simplified. */ - -static void -simplify_pred (pred_chain *one_chain) -{ - size_t i, j, n; - bool simplified = false; - pred_chain s_chain = vNULL; - - n = one_chain->length (); - - for (i = 0; i < n; i++) - { - pred_info *a_pred = &(*one_chain)[i]; - - if (!a_pred->pred_lhs) - continue; - if (!is_neq_zero_form_p (*a_pred)) - continue; - - gimple *def_stmt = SSA_NAME_DEF_STMT (a_pred->pred_lhs); - if (gimple_code (def_stmt) != GIMPLE_ASSIGN) - continue; - if (gimple_assign_rhs_code (def_stmt) == BIT_IOR_EXPR) - { - for (j = 0; j < n; j++) - { - pred_info *b_pred = &(*one_chain)[j]; - - if (!b_pred->pred_lhs) - continue; - if (!is_neq_zero_form_p (*b_pred)) - continue; - - if (pred_expr_equal_p (*b_pred, gimple_assign_rhs1 (def_stmt)) - || pred_expr_equal_p (*b_pred, gimple_assign_rhs2 (def_stmt))) - { - /* Mark a_pred for removal. */ - a_pred->pred_lhs = NULL; - a_pred->pred_rhs = NULL; - simplified = true; - break; - } - } - } - } - - if (!simplified) - return; - - for (i = 0; i < n; i++) - { - pred_info *a_pred = &(*one_chain)[i]; - if (!a_pred->pred_lhs) - continue; - s_chain.safe_push (*a_pred); - } - - one_chain->release (); - *one_chain = s_chain; -} - -/* The helper function implements the rule 2 for the - OR predicate PREDS. - - 2) (X AND Y) OR (!X AND Y) is equivalent to Y. */ - -static bool -simplify_preds_2 (pred_chain_union *preds) -{ - size_t i, j, n; - bool simplified = false; - pred_chain_union s_preds = vNULL; - - /* (X AND Y) OR (!X AND Y) is equivalent to Y. - (X AND Y) OR (X AND !Y) is equivalent to X. */ - - n = preds->length (); - for (i = 0; i < n; i++) - { - pred_info x, y; - pred_chain *a_chain = &(*preds)[i]; - - if (a_chain->length () != 2) - continue; - - x = (*a_chain)[0]; - y = (*a_chain)[1]; - - for (j = 0; j < n; j++) - { - pred_chain *b_chain; - pred_info x2, y2; - - if (j == i) - continue; - - b_chain = &(*preds)[j]; - if (b_chain->length () != 2) - continue; - - x2 = (*b_chain)[0]; - y2 = (*b_chain)[1]; - - if (pred_equal_p (x, x2) && pred_neg_p (y, y2)) - { - /* Kill a_chain. */ - a_chain->release (); - b_chain->release (); - b_chain->safe_push (x); - simplified = true; - break; - } - if (pred_neg_p (x, x2) && pred_equal_p (y, y2)) - { - /* Kill a_chain. */ - a_chain->release (); - b_chain->release (); - b_chain->safe_push (y); - simplified = true; - break; - } - } - } - /* Now clean up the chain. */ - if (simplified) - { - for (i = 0; i < n; i++) - { - if ((*preds)[i].is_empty ()) - continue; - s_preds.safe_push ((*preds)[i]); - } - preds->release (); - (*preds) = s_preds; - s_preds = vNULL; - } - - return simplified; -} - -/* The helper function implements the rule 2 for the - OR predicate PREDS. - - 3) x OR (!x AND y) is equivalent to x OR y. */ - -static bool -simplify_preds_3 (pred_chain_union *preds) -{ - size_t i, j, n; - bool simplified = false; - - /* Now iteratively simplify X OR (!X AND Z ..) - into X OR (Z ...). */ - - n = preds->length (); - if (n < 2) - return false; - - for (i = 0; i < n; i++) - { - pred_info x; - pred_chain *a_chain = &(*preds)[i]; - - if (a_chain->length () != 1) - continue; - - x = (*a_chain)[0]; - - for (j = 0; j < n; j++) - { - pred_chain *b_chain; - pred_info x2; - size_t k; - - if (j == i) - continue; - - b_chain = &(*preds)[j]; - if (b_chain->length () < 2) - continue; - - for (k = 0; k < b_chain->length (); k++) - { - x2 = (*b_chain)[k]; - if (pred_neg_p (x, x2)) - { - b_chain->unordered_remove (k); - simplified = true; - break; - } - } - } - } - return simplified; -} - -/* The helper function implements the rule 4 for the - OR predicate PREDS. - - 2) ((x AND y) != 0) OR (x != 0 AND y != 0) is equivalent to - (x != 0 ANd y != 0). */ - -static bool -simplify_preds_4 (pred_chain_union *preds) -{ - size_t i, j, n; - bool simplified = false; - pred_chain_union s_preds = vNULL; - gimple *def_stmt; - - n = preds->length (); - for (i = 0; i < n; i++) - { - pred_info z; - pred_chain *a_chain = &(*preds)[i]; - - if (a_chain->length () != 1) - continue; - - z = (*a_chain)[0]; - - if (!is_neq_zero_form_p (z)) - continue; - - def_stmt = SSA_NAME_DEF_STMT (z.pred_lhs); - if (gimple_code (def_stmt) != GIMPLE_ASSIGN) - continue; - - if (gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR) - continue; - - for (j = 0; j < n; j++) - { - pred_chain *b_chain; - pred_info x2, y2; - - if (j == i) - continue; - - b_chain = &(*preds)[j]; - if (b_chain->length () != 2) - continue; - - x2 = (*b_chain)[0]; - y2 = (*b_chain)[1]; - if (!is_neq_zero_form_p (x2) || !is_neq_zero_form_p (y2)) - continue; - - if ((pred_expr_equal_p (x2, gimple_assign_rhs1 (def_stmt)) - && pred_expr_equal_p (y2, gimple_assign_rhs2 (def_stmt))) - || (pred_expr_equal_p (x2, gimple_assign_rhs2 (def_stmt)) - && pred_expr_equal_p (y2, gimple_assign_rhs1 (def_stmt)))) - { - /* Kill a_chain. */ - a_chain->release (); - simplified = true; - break; - } - } - } - /* Now clean up the chain. */ - if (simplified) - { - for (i = 0; i < n; i++) - { - if ((*preds)[i].is_empty ()) - continue; - s_preds.safe_push ((*preds)[i]); - } - - preds->release (); - (*preds) = s_preds; - s_preds = vNULL; - } - - return simplified; -} - -/* This function simplifies predicates in PREDS. */ - -static void -simplify_preds (pred_chain_union *preds, gimple *use_or_def, bool is_use) -{ - size_t i, n; - bool changed = false; - - if (dump_file && dump_flags & TDF_DETAILS) - { - fprintf (dump_file, "[BEFORE SIMPLICATION -- "); - dump_predicates (use_or_def, *preds, is_use ? "[USE]:\n" : "[DEF]:\n"); - } - - for (i = 0; i < preds->length (); i++) - simplify_pred (&(*preds)[i]); - - n = preds->length (); - if (n < 2) - return; - - do - { - changed = false; - if (simplify_preds_2 (preds)) - changed = true; - - /* Now iteratively simplify X OR (!X AND Z ..) - into X OR (Z ...). */ - if (simplify_preds_3 (preds)) - changed = true; - - if (simplify_preds_4 (preds)) - changed = true; - } - while (changed); - - return; -} - -/* This is a helper function which attempts to normalize predicate chains - by following UD chains. It basically builds up a big tree of either IOR - operations or AND operations, and convert the IOR tree into a - pred_chain_union or BIT_AND tree into a pred_chain. - Example: - - _3 = _2 RELOP1 _1; - _6 = _5 RELOP2 _4; - _9 = _8 RELOP3 _7; - _10 = _3 | _6; - _12 = _9 | _0; - _t = _10 | _12; - - then _t != 0 will be normalized into a pred_chain_union - - (_2 RELOP1 _1) OR (_5 RELOP2 _4) OR (_8 RELOP3 _7) OR (_0 != 0) - - Similarly given, - - _3 = _2 RELOP1 _1; - _6 = _5 RELOP2 _4; - _9 = _8 RELOP3 _7; - _10 = _3 & _6; - _12 = _9 & _0; - - then _t != 0 will be normalized into a pred_chain: - (_2 RELOP1 _1) AND (_5 RELOP2 _4) AND (_8 RELOP3 _7) AND (_0 != 0) - - */ - -/* This is a helper function that stores a PRED into NORM_PREDS. */ - -inline static void -push_pred (pred_chain_union *norm_preds, pred_info pred) -{ - pred_chain pred_chain = vNULL; - pred_chain.safe_push (pred); - norm_preds->safe_push (pred_chain); -} - -/* A helper function that creates a predicate of the form - OP != 0 and push it WORK_LIST. */ - -inline static void -push_to_worklist (tree op, vec<pred_info, va_heap, vl_ptr> *work_list, - hash_set<tree> *mark_set) -{ - if (mark_set->contains (op)) - return; - mark_set->add (op); - - pred_info arg_pred; - arg_pred.pred_lhs = op; - arg_pred.pred_rhs = integer_zero_node; - arg_pred.cond_code = NE_EXPR; - arg_pred.invert = false; - work_list->safe_push (arg_pred); -} - -/* A helper that generates a pred_info from a gimple assignment - CMP_ASSIGN with comparison rhs. */ - -static pred_info -get_pred_info_from_cmp (gimple *cmp_assign) -{ - pred_info n_pred; - n_pred.pred_lhs = gimple_assign_rhs1 (cmp_assign); - n_pred.pred_rhs = gimple_assign_rhs2 (cmp_assign); - n_pred.cond_code = gimple_assign_rhs_code (cmp_assign); - n_pred.invert = false; - return n_pred; -} - -/* Returns true if the PHI is a degenerated phi with - all args with the same value (relop). In that case, *PRED - will be updated to that value. */ - -static bool -is_degenerated_phi (gimple *phi, pred_info *pred_p) -{ - int i, n; - tree op0; - gimple *def0; - pred_info pred0; - - n = gimple_phi_num_args (phi); - op0 = gimple_phi_arg_def (phi, 0); - - if (TREE_CODE (op0) != SSA_NAME) - return false; - - def0 = SSA_NAME_DEF_STMT (op0); - if (gimple_code (def0) != GIMPLE_ASSIGN) - return false; - if (TREE_CODE_CLASS (gimple_assign_rhs_code (def0)) != tcc_comparison) - return false; - pred0 = get_pred_info_from_cmp (def0); - - for (i = 1; i < n; ++i) - { - gimple *def; - pred_info pred; - tree op = gimple_phi_arg_def (phi, i); - - if (TREE_CODE (op) != SSA_NAME) - return false; - - def = SSA_NAME_DEF_STMT (op); - if (gimple_code (def) != GIMPLE_ASSIGN) - return false; - if (TREE_CODE_CLASS (gimple_assign_rhs_code (def)) != tcc_comparison) - return false; - pred = get_pred_info_from_cmp (def); - if (!pred_equal_p (pred, pred0)) - return false; - } - - *pred_p = pred0; - return true; -} - -/* Normalize one predicate PRED - 1) if PRED can no longer be normlized, put it into NORM_PREDS. - 2) otherwise if PRED is of the form x != 0, follow x's definition - and put normalized predicates into WORK_LIST. */ - -static void -normalize_one_pred_1 (pred_chain_union *norm_preds, - pred_chain *norm_chain, - pred_info pred, - enum tree_code and_or_code, - vec<pred_info, va_heap, vl_ptr> *work_list, - hash_set<tree> *mark_set) -{ - if (!is_neq_zero_form_p (pred)) - { - if (and_or_code == BIT_IOR_EXPR) - push_pred (norm_preds, pred); - else - norm_chain->safe_push (pred); - return; - } - - gimple *def_stmt = SSA_NAME_DEF_STMT (pred.pred_lhs); - - if (gimple_code (def_stmt) == GIMPLE_PHI - && is_degenerated_phi (def_stmt, &pred)) - work_list->safe_push (pred); - else if (gimple_code (def_stmt) == GIMPLE_PHI && and_or_code == BIT_IOR_EXPR) - { - int i, n; - n = gimple_phi_num_args (def_stmt); - - /* If we see non zero constant, we should punt. The predicate - * should be one guarding the phi edge. */ - for (i = 0; i < n; ++i) - { - tree op = gimple_phi_arg_def (def_stmt, i); - if (TREE_CODE (op) == INTEGER_CST && !integer_zerop (op)) - { - push_pred (norm_preds, pred); - return; - } - } - - for (i = 0; i < n; ++i) - { - tree op = gimple_phi_arg_def (def_stmt, i); - if (integer_zerop (op)) - continue; - - push_to_worklist (op, work_list, mark_set); - } - } - else if (gimple_code (def_stmt) != GIMPLE_ASSIGN) - { - if (and_or_code == BIT_IOR_EXPR) - push_pred (norm_preds, pred); - else - norm_chain->safe_push (pred); - } - else if (gimple_assign_rhs_code (def_stmt) == and_or_code) - { - /* Avoid splitting up bit manipulations like x & 3 or y | 1. */ - if (is_gimple_min_invariant (gimple_assign_rhs2 (def_stmt))) - { - /* But treat x & 3 as condition. */ - if (and_or_code == BIT_AND_EXPR) - { - pred_info n_pred; - n_pred.pred_lhs = gimple_assign_rhs1 (def_stmt); - n_pred.pred_rhs = gimple_assign_rhs2 (def_stmt); - n_pred.cond_code = and_or_code; - n_pred.invert = false; - norm_chain->safe_push (n_pred); - } - } - else - { - push_to_worklist (gimple_assign_rhs1 (def_stmt), work_list, mark_set); - push_to_worklist (gimple_assign_rhs2 (def_stmt), work_list, mark_set); - } - } - else if (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)) - == tcc_comparison) - { - pred_info n_pred = get_pred_info_from_cmp (def_stmt); - if (and_or_code == BIT_IOR_EXPR) - push_pred (norm_preds, n_pred); - else - norm_chain->safe_push (n_pred); - } - else - { - if (and_or_code == BIT_IOR_EXPR) - push_pred (norm_preds, pred); - else - norm_chain->safe_push (pred); - } -} - -/* Normalize PRED and store the normalized predicates into NORM_PREDS. */ - -static void -normalize_one_pred (pred_chain_union *norm_preds, pred_info pred) -{ - vec<pred_info, va_heap, vl_ptr> work_list = vNULL; - enum tree_code and_or_code = ERROR_MARK; - pred_chain norm_chain = vNULL; - - if (!is_neq_zero_form_p (pred)) - { - push_pred (norm_preds, pred); - return; - } - - gimple *def_stmt = SSA_NAME_DEF_STMT (pred.pred_lhs); - if (gimple_code (def_stmt) == GIMPLE_ASSIGN) - and_or_code = gimple_assign_rhs_code (def_stmt); - if (and_or_code != BIT_IOR_EXPR && and_or_code != BIT_AND_EXPR) - { - if (TREE_CODE_CLASS (and_or_code) == tcc_comparison) - { - pred_info n_pred = get_pred_info_from_cmp (def_stmt); - push_pred (norm_preds, n_pred); - } - else - push_pred (norm_preds, pred); - return; - } - - work_list.safe_push (pred); - hash_set<tree> mark_set; - - while (!work_list.is_empty ()) - { - pred_info a_pred = work_list.pop (); - normalize_one_pred_1 (norm_preds, &norm_chain, a_pred, and_or_code, - &work_list, &mark_set); - } - if (and_or_code == BIT_AND_EXPR) - norm_preds->safe_push (norm_chain); - - work_list.release (); -} - -static void -normalize_one_pred_chain (pred_chain_union *norm_preds, pred_chain one_chain) -{ - vec<pred_info, va_heap, vl_ptr> work_list = vNULL; - hash_set<tree> mark_set; - pred_chain norm_chain = vNULL; - size_t i; - - for (i = 0; i < one_chain.length (); i++) - { - work_list.safe_push (one_chain[i]); - mark_set.add (one_chain[i].pred_lhs); - } - - while (!work_list.is_empty ()) - { - pred_info a_pred = work_list.pop (); - normalize_one_pred_1 (0, &norm_chain, a_pred, BIT_AND_EXPR, &work_list, - &mark_set); - } - - norm_preds->safe_push (norm_chain); - work_list.release (); -} - -/* Normalize predicate chains PREDS and returns the normalized one. */ - -static pred_chain_union -normalize_preds (pred_chain_union preds, gimple *use_or_def, bool is_use) -{ - pred_chain_union norm_preds = vNULL; - size_t n = preds.length (); - size_t i; - - if (dump_file && dump_flags & TDF_DETAILS) - { - fprintf (dump_file, "[BEFORE NORMALIZATION --"); - dump_predicates (use_or_def, preds, is_use ? "[USE]:\n" : "[DEF]:\n"); - } - - for (i = 0; i < n; i++) - { - if (preds[i].length () != 1) - normalize_one_pred_chain (&norm_preds, preds[i]); - else - { - normalize_one_pred (&norm_preds, preds[i][0]); - preds[i].release (); - } - } - - if (dump_file) - { - fprintf (dump_file, "[AFTER NORMALIZATION -- "); - dump_predicates (use_or_def, norm_preds, - is_use ? "[USE]:\n" : "[DEF]:\n"); - } - - destroy_predicate_vecs (&preds); - return norm_preds; -} - -/* Return TRUE if PREDICATE can be invalidated by any individual - predicate in USE_GUARD. */ - -static bool -can_one_predicate_be_invalidated_p (pred_info predicate, - pred_chain use_guard) -{ - if (dump_file && dump_flags & TDF_DETAILS) - { - fprintf (dump_file, "Testing if this predicate: "); - dump_pred_info (predicate); - fprintf (dump_file, "\n...can be invalidated by a USE guard of: "); - dump_pred_chain (use_guard); - } - for (size_t i = 0; i < use_guard.length (); ++i) - { - /* NOTE: This is a very simple check, and only understands an - exact opposite. So, [i == 0] is currently only invalidated - by [.NOT. i == 0] or [i != 0]. Ideally we should also - invalidate with say [i > 5] or [i == 8]. There is certainly - room for improvement here. */ - if (pred_neg_p (predicate, use_guard[i])) - { - if (dump_file && dump_flags & TDF_DETAILS) - { - fprintf (dump_file, " Predicate was invalidated by: "); - dump_pred_info (use_guard[i]); - fputc ('\n', dump_file); - } - return true; - } - } - return false; -} - -/* Return TRUE if all predicates in UNINIT_PRED are invalidated by - USE_GUARD being true. */ - -static bool -can_chain_union_be_invalidated_p (pred_chain_union uninit_pred, - pred_chain use_guard) -{ - if (uninit_pred.is_empty ()) - return false; - if (dump_file && dump_flags & TDF_DETAILS) - dump_predicates (NULL, uninit_pred, - "Testing if anything here can be invalidated: "); - for (size_t i = 0; i < uninit_pred.length (); ++i) - { - pred_chain c = uninit_pred[i]; - size_t j; - for (j = 0; j < c.length (); ++j) - if (can_one_predicate_be_invalidated_p (c[j], use_guard)) - break; - - /* If we were unable to invalidate any predicate in C, then there - is a viable path from entry to the PHI where the PHI takes - an uninitialized value and continues to a use of the PHI. */ - if (j == c.length ()) - return false; - } - return true; -} - -/* Return TRUE if none of the uninitialized operands in UNINT_OPNDS - can actually happen if we arrived at a use for PHI. - - PHI_USE_GUARDS are the guard conditions for the use of the PHI. */ - -static bool -uninit_uses_cannot_happen (gphi *phi, unsigned uninit_opnds, - pred_chain_union phi_use_guards) -{ - unsigned phi_args = gimple_phi_num_args (phi); - if (phi_args > max_phi_args) - return false; - - /* PHI_USE_GUARDS are OR'ed together. If we have more than one - possible guard, there's no way of knowing which guard was true. - Since we need to be absolutely sure that the uninitialized - operands will be invalidated, bail. */ - if (phi_use_guards.length () != 1) - return false; - - /* Look for the control dependencies of all the uninitialized - operands and build guard predicates describing them. */ - pred_chain_union uninit_preds; - bool ret = true; - for (unsigned i = 0; i < phi_args; ++i) - { - if (!MASK_TEST_BIT (uninit_opnds, i)) - continue; - - edge e = gimple_phi_arg_edge (phi, i); - vec<edge> dep_chains[MAX_NUM_CHAINS]; - auto_vec<edge, MAX_CHAIN_LEN + 1> cur_chain; - size_t num_chains = 0; - int num_calls = 0; - - /* Build the control dependency chain for uninit operand `i'... */ - uninit_preds = vNULL; - if (!compute_control_dep_chain (ENTRY_BLOCK_PTR_FOR_FN (cfun), - e->src, dep_chains, &num_chains, - &cur_chain, &num_calls)) - { - ret = false; - break; - } - /* ...and convert it into a set of predicates. */ - bool has_valid_preds - = convert_control_dep_chain_into_preds (dep_chains, num_chains, - &uninit_preds); - for (size_t j = 0; j < num_chains; ++j) - dep_chains[j].release (); - if (!has_valid_preds) - { - ret = false; - break; - } - simplify_preds (&uninit_preds, NULL, false); - uninit_preds = normalize_preds (uninit_preds, NULL, false); - - /* Can the guard for this uninitialized operand be invalidated - by the PHI use? */ - if (!can_chain_union_be_invalidated_p (uninit_preds, phi_use_guards[0])) - { - ret = false; - break; - } - } - destroy_predicate_vecs (&uninit_preds); - return ret; -} - -/* Computes the predicates that guard the use and checks - if the incoming paths that have empty (or possibly - empty) definition can be pruned/filtered. The function returns - true if it can be determined that the use of PHI's def in - USE_STMT is guarded with a predicate set not overlapping with - predicate sets of all runtime paths that do not have a definition. - - Returns false if it is not or it cannot be determined. USE_BB is - the bb of the use (for phi operand use, the bb is not the bb of - the phi stmt, but the src bb of the operand edge). - - UNINIT_OPNDS is a bit vector. If an operand of PHI is uninitialized, the - corresponding bit in the vector is 1. VISITED_PHIS is a pointer - set of phis being visited. - - *DEF_PREDS contains the (memoized) defining predicate chains of PHI. - If *DEF_PREDS is the empty vector, the defining predicate chains of - PHI will be computed and stored into *DEF_PREDS as needed. - - VISITED_PHIS is a pointer set of phis being visited. */ - -static bool -is_use_properly_guarded (gimple *use_stmt, - basic_block use_bb, - gphi *phi, - unsigned uninit_opnds, - pred_chain_union *def_preds, - hash_set<gphi *> *visited_phis) -{ - basic_block phi_bb; - pred_chain_union preds = vNULL; - bool has_valid_preds = false; - bool is_properly_guarded = false; - - if (visited_phis->add (phi)) - return false; - - phi_bb = gimple_bb (phi); - - if (is_non_loop_exit_postdominating (use_bb, phi_bb)) - return false; - - has_valid_preds = find_predicates (&preds, phi_bb, use_bb); - - if (!has_valid_preds) - { - destroy_predicate_vecs (&preds); - return false; - } - - /* Try to prune the dead incoming phi edges. */ - is_properly_guarded - = use_pred_not_overlap_with_undef_path_pred (preds, phi, uninit_opnds, - visited_phis); - - /* We might be able to prove that if the control dependencies - for UNINIT_OPNDS are true, that the control dependencies for - USE_STMT can never be true. */ - if (!is_properly_guarded) - is_properly_guarded |= uninit_uses_cannot_happen (phi, uninit_opnds, - preds); - - if (is_properly_guarded) - { - destroy_predicate_vecs (&preds); - return true; - } - - if (def_preds->is_empty ()) - { - has_valid_preds = find_def_preds (def_preds, phi); - - if (!has_valid_preds) - { - destroy_predicate_vecs (&preds); - return false; - } - - simplify_preds (def_preds, phi, false); - *def_preds = normalize_preds (*def_preds, phi, false); - } - - simplify_preds (&preds, use_stmt, true); - preds = normalize_preds (preds, use_stmt, true); - - is_properly_guarded = is_superset_of (*def_preds, preds); - - destroy_predicate_vecs (&preds); - return is_properly_guarded; + return compute_uninit_opnds_pos (phi); } /* Searches through all uses of a potentially @@ -3149,48 +1065,42 @@ is_use_properly_guarded (gimple *use_stmt, static gimple * find_uninit_use (gphi *phi, unsigned uninit_opnds, - vec<gphi *> *worklist, - hash_set<gphi *> *added_to_worklist) + vec<gphi *> *worklist, hash_set<gphi *> *added_to_worklist) { - tree phi_result; + /* The Boolean predicate guarding the PHI definition. Initialized + lazily from PHI in the first call to is_use_guarded() and cached + for subsequent iterations. */ + uninit_undef_val_t eval; + predicate def_preds (eval); + use_operand_p use_p; - gimple *use_stmt; imm_use_iterator iter; - pred_chain_union def_preds = vNULL; - gimple *ret = NULL; - - phi_result = gimple_phi_result (phi); - + tree phi_result = gimple_phi_result (phi); FOR_EACH_IMM_USE_FAST (use_p, iter, phi_result) { - basic_block use_bb; - - use_stmt = USE_STMT (use_p); + gimple *use_stmt = USE_STMT (use_p); if (is_gimple_debug (use_stmt)) continue; + basic_block use_bb; if (gphi *use_phi = dyn_cast<gphi *> (use_stmt)) use_bb = gimple_phi_arg_edge (use_phi, PHI_ARG_INDEX_FROM_USE (use_p))->src; else use_bb = gimple_bb (use_stmt); - hash_set<gphi *> visited_phis; - if (is_use_properly_guarded (use_stmt, use_bb, phi, uninit_opnds, - &def_preds, &visited_phis)) + if (def_preds.is_use_guarded (use_stmt, use_bb, phi, uninit_opnds)) continue; if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "[CHECK]: Found unguarded use: "); + fprintf (dump_file, "Found unguarded use in bb %u: ", + use_bb->index); print_gimple_stmt (dump_file, use_stmt, 0); } /* Found one real use, return. */ if (gimple_code (use_stmt) != GIMPLE_PHI) - { - ret = use_stmt; - break; - } + return use_stmt; /* Found a phi use that is not guarded, add the phi to the worklist. */ @@ -3207,8 +1117,7 @@ find_uninit_use (gphi *phi, unsigned uninit_opnds, } } - destroy_predicate_vecs (&def_preds); - return ret; + return NULL; } /* Look for inputs to PHI that are SSA_NAMEs that have empty definitions @@ -3233,28 +1142,47 @@ warn_uninitialized_phi (gphi *phi, vec<gphi *> *worklist, if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "[CHECK]: examining phi: "); + fprintf (dump_file, "Examining phi: "); print_gimple_stmt (dump_file, phi, 0); } - /* Now check if we have any use of the value without proper guard. */ gimple *uninit_use_stmt = find_uninit_use (phi, uninit_opnds, worklist, added_to_worklist); - /* All uses are properly guarded. */ + /* All uses are properly guarded but a new PHI may have been added + to WORKLIST. */ if (!uninit_use_stmt) return; - int phiarg_index = MASK_FIRST_SET_BIT (uninit_opnds); + unsigned phiarg_index = MASK_FIRST_SET_BIT (uninit_opnds); tree uninit_op = gimple_phi_arg_def (phi, phiarg_index); if (SSA_NAME_VAR (uninit_op) == NULL_TREE) return; - location_t phi_arg_loc = gimple_phi_arg_location (phi, phiarg_index); + location_t loc = UNKNOWN_LOCATION; + if (gimple_phi_arg_has_location (phi, phiarg_index)) + loc = gimple_phi_arg_location (phi, phiarg_index); + else + { + tree arg_def = gimple_phi_arg_def (phi, phiarg_index); + if (TREE_CODE (arg_def) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (arg_def); + if (gphi *arg_phi = dyn_cast<gphi *> (def_stmt)) + { + unsigned uop = compute_uninit_opnds_pos (arg_phi); + unsigned idx = MASK_FIRST_SET_BIT (uop); + if (idx < gimple_phi_num_args (arg_phi) + && gimple_phi_arg_has_location (arg_phi, idx)) + loc = gimple_phi_arg_location (arg_phi, idx); + } + } + } + warn_uninit (OPT_Wmaybe_uninitialized, uninit_op, SSA_NAME_VAR (uninit_op), "%qD may be used uninitialized in this function", - uninit_use_stmt, phi_arg_loc); + uninit_use_stmt, loc); } static bool @@ -3292,8 +1220,8 @@ public: }; // class pass_late_warn_uninitialized -unsigned int -pass_late_warn_uninitialized::execute (function *fun) +static void +execute_late_warn_uninitialized (function *fun) { basic_block bb; gphi_iterator gsi; @@ -3316,15 +1244,13 @@ pass_late_warn_uninitialized::execute (function *fun) for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gphi *phi = gsi.phi (); - size_t n, i; - - n = gimple_phi_num_args (phi); /* Don't look at virtual operands. */ if (virtual_operand_p (gimple_phi_result (phi))) continue; - for (i = 0; i < n; ++i) + unsigned n = gimple_phi_num_args (phi); + for (unsigned i = 0; i < n; ++i) { tree op = gimple_phi_arg_def (phi, i); if (TREE_CODE (op) == SSA_NAME && uninit_undefined_value_p (op)) @@ -3333,7 +1259,8 @@ pass_late_warn_uninitialized::execute (function *fun) added_to_worklist.add (phi); if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "[WORKLIST]: add to initial list: "); + fprintf (dump_file, "[WORKLIST]: add to initial list " + "for operand %u of: ", i); print_gimple_stmt (dump_file, phi, 0); } break; @@ -3353,6 +1280,12 @@ pass_late_warn_uninitialized::execute (function *fun) possibly_undefined_names = NULL; free_dominance_info (CDI_POST_DOMINATORS); timevar_pop (TV_TREE_UNINIT); +} + +unsigned int +pass_late_warn_uninitialized::execute (function *fun) +{ + execute_late_warn_uninitialized (fun); return 0; } diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index 967d437..a57700f 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -2268,8 +2268,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo) if (npeel) LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) = npeel; else - LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) - = DR_MISALIGNMENT (dr0_info); + LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) = -1; SET_DR_MISALIGNMENT (dr0_info, 0); if (dump_enabled_p ()) { @@ -4636,13 +4635,6 @@ static void vect_duplicate_ssa_name_ptr_info (tree name, dr_vec_info *dr_info) { duplicate_ssa_name_ptr_info (name, DR_PTR_INFO (dr_info->dr)); - int misalign = DR_MISALIGNMENT (dr_info); - if (misalign == DR_MISALIGNMENT_UNKNOWN) - mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (name)); - else - set_ptr_info_alignment (SSA_NAME_PTR_INFO (name), - known_alignment (DR_TARGET_ALIGNMENT (dr_info)), - misalign); } /* Function vect_create_addr_base_for_vector_ref. diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 5a5b8da..e94356d 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -2047,6 +2047,7 @@ vect_dissolve_slp_only_groups (loop_vec_info loop_vinfo) if (STMT_VINFO_GROUPED_ACCESS (stmt_info)) { stmt_vec_info first_element = DR_GROUP_FIRST_ELEMENT (stmt_info); + dr_vec_info *dr_info = STMT_VINFO_DR_INFO (first_element); unsigned int group_size = DR_GROUP_SIZE (first_element); /* Check if SLP-only groups. */ @@ -2067,6 +2068,24 @@ vect_dissolve_slp_only_groups (loop_vec_info loop_vinfo) DR_GROUP_GAP (vinfo) = 0; else DR_GROUP_GAP (vinfo) = group_size - 1; + /* Duplicate and adjust alignment info, it needs to + be present on each group leader, see dr_misalignment. */ + if (vinfo != first_element) + { + dr_vec_info *dr_info2 = STMT_VINFO_DR_INFO (vinfo); + dr_info2->target_alignment = dr_info->target_alignment; + int misalignment = dr_info->misalignment; + if (misalignment != DR_MISALIGNMENT_UNKNOWN) + { + HOST_WIDE_INT diff + = (TREE_INT_CST_LOW (DR_INIT (dr_info2->dr)) + - TREE_INT_CST_LOW (DR_INIT (dr_info->dr))); + unsigned HOST_WIDE_INT align_c + = dr_info->target_alignment.to_constant (); + misalignment = (misalignment + diff) % align_c; + } + dr_info2->misalignment = misalignment; + } vinfo = next; } } diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index ce79d88..17849b5 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -8650,7 +8650,7 @@ vectorizable_load (vec_info *vinfo, FOR_EACH_VEC_ELT (SLP_TREE_LOAD_PERMUTATION (slp_node), j, k) if (k > maxk) maxk = k; - tree vectype = STMT_VINFO_VECTYPE (group_info); + tree vectype = SLP_TREE_VECTYPE (slp_node); if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nunits) || maxk >= (DR_GROUP_SIZE (group_info) & ~(nunits - 1))) { diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c index 3aa3e2a..20daa31 100644 --- a/gcc/tree-vectorizer.c +++ b/gcc/tree-vectorizer.c @@ -507,7 +507,8 @@ vec_info_shared::check_datarefs () return; gcc_assert (datarefs.length () == datarefs_copy.length ()); for (unsigned i = 0; i < datarefs.length (); ++i) - if (memcmp (&datarefs_copy[i], datarefs[i], sizeof (data_reference)) != 0) + if (memcmp (&datarefs_copy[i], datarefs[i], + offsetof (data_reference, alt_indices)) != 0) gcc_unreachable (); } @@ -1715,6 +1715,10 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_ORDERED_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED), 0) +/* True for unconstrained modifier on order(concurrent) clause. */ +#define OMP_CLAUSE_ORDER_UNCONSTRAINED(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDER)->base.public_flag) + #define OMP_CLAUSE_REDUCTION_CODE(NODE) \ (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_REDUCTION, \ OMP_CLAUSE_IN_REDUCTION)->omp_clause.subcode.reduction_code) diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index ba01d29..ac5f3f9 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -190,26 +190,31 @@ relation_transitive (relation_kind r1, relation_kind r2) // ------------------------------------------------------------------------- -// This class represents an equivalency set, and contains a link to the next -// one in the list to be searched. - // The very first element in the m_equiv chain is actually just a summary // element in which the m_names bitmap is used to indicate that an ssa_name // has an equivalence set in this block. // This allows for much faster traversal of the DOM chain, as a search for // SSA_NAME simply requires walking the DOM chain until a block is found // which has the bit for SSA_NAME set. Then scan for the equivalency set in -// that block. No previous blcoks need be searched. +// that block. No previous lists need be searched. -class equiv_chain -{ -public: - bitmap m_names; // ssa-names in equiv set. - basic_block m_bb; // Block this belongs to - equiv_chain *m_next; // Next in block list. - void dump (FILE *f) const; // Show names in this list. -}; +// If SSA has an equivalence in this list, find and return it. +// Otherwise return NULL. +equiv_chain * +equiv_chain::find (unsigned ssa) +{ + equiv_chain *ptr = NULL; + // If there are equiv sets and SSA is in one in this list, find it. + // Otherwise return NULL. + if (bitmap_bit_p (m_names, ssa)) + { + for (ptr = m_next; ptr; ptr = ptr->m_next) + if (bitmap_bit_p (ptr->m_names, ssa)) + break; + } + return ptr; +} // Dump the names in this equivalence set. @@ -244,12 +249,15 @@ equiv_oracle::equiv_oracle () m_equiv.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); m_equiv_set = BITMAP_ALLOC (&m_bitmaps); obstack_init (&m_chain_obstack); + m_self_equiv.create (0); + m_self_equiv.safe_grow_cleared (num_ssa_names + 1); } // Destruct an equivalency oracle. equiv_oracle::~equiv_oracle () { + m_self_equiv.release (); obstack_free (&m_chain_obstack, NULL); m_equiv.release (); bitmap_obstack_release (&m_bitmaps); @@ -259,16 +267,48 @@ equiv_oracle::~equiv_oracle () // This is the external API. const_bitmap -equiv_oracle::equiv_set (tree ssa, basic_block bb) const +equiv_oracle::equiv_set (tree ssa, basic_block bb) { // Search the dominator tree for an equivalency. equiv_chain *equiv = find_equiv_dom (ssa, bb); if (equiv) return equiv->m_names; - return NULL; + // Otherwise return a cached equiv set containing just this SSA. + unsigned v = SSA_NAME_VERSION (ssa); + if (v >= m_self_equiv.length ()) + m_self_equiv.safe_grow_cleared (num_ssa_names + 1); + + if (!m_self_equiv[v]) + { + m_self_equiv[v] = BITMAP_ALLOC (&m_bitmaps); + bitmap_set_bit (m_self_equiv[v], v); + } + return m_self_equiv[v]; +} + +// Query if thre is a relation (equivalence) between 2 SSA_NAMEs. + +relation_kind +equiv_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) +{ + // If the 2 ssa names share the same equiv set, they are equal. + if (equiv_set (ssa1, bb) == equiv_set (ssa2, bb)) + return EQ_EXPR; + return VREL_NONE; } +// Query if thre is a relation (equivalence) between 2 SSA_NAMEs. + +relation_kind +equiv_oracle::query_relation (basic_block bb ATTRIBUTE_UNUSED, const_bitmap e1, + const_bitmap e2) +{ + // If the 2 ssa names share the same equiv set, they are equal. + if (bitmap_equal_p (e1, e2)) + return EQ_EXPR; + return VREL_NONE; +} // If SSA has an equivalence in block BB, find and return it. // Otherwise return NULL. @@ -276,19 +316,10 @@ equiv_oracle::equiv_set (tree ssa, basic_block bb) const equiv_chain * equiv_oracle::find_equiv_block (unsigned ssa, int bb) const { - equiv_chain *ptr = NULL; - if (bb >= (int)m_equiv.length ()) + if (bb >= (int)m_equiv.length () || !m_equiv[bb]) return NULL; - // If there are equiv sets and SSA is in one in this block, find it. - // Otherwise return NULL. - if (m_equiv[bb] && bitmap_bit_p (m_equiv[bb]->m_names, ssa)) - { - for (ptr = m_equiv[bb]->m_next; ptr; ptr = ptr->m_next) - if (bitmap_bit_p (ptr->m_names, ssa)) - break; - } - return ptr; + return m_equiv[bb]->find (ssa); } // Starting at block BB, walk the dominator chain looking for the nearest @@ -376,6 +407,24 @@ equiv_oracle::register_equiv (basic_block bb, equiv_chain *equiv_1, return b; } +// Create an equivalency set containing only SSA in its definition block. +// This is done the first time SSA is registered in an equivalency and blocks +// any DOM searches past the definition. + +void +equiv_oracle::register_initial_def (tree ssa) +{ + if (SSA_NAME_IS_DEFAULT_DEF (ssa)) + return; + basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (ssa)); + gcc_checking_assert (bb && !find_equiv_dom (ssa, bb)); + + unsigned v = SSA_NAME_VERSION (ssa); + bitmap_set_bit (m_equiv_set, v); + bitmap equiv_set = BITMAP_ALLOC (&m_bitmaps); + bitmap_set_bit (equiv_set, v); + add_equiv_to_block (bb, equiv_set); +} // Register an equivalence between SSA1 and SSA2 in block BB. // The equivalence oracle maintains a vector of equivalencies indexed by basic @@ -385,10 +434,23 @@ equiv_oracle::register_equiv (basic_block bb, equiv_chain *equiv_1, // containing all the ssa_names in this basic block. void -equiv_oracle::register_equiv (basic_block bb, tree ssa1, tree ssa2) +equiv_oracle::register_relation (basic_block bb, relation_kind k, tree ssa1, + tree ssa2) { + // Only handle equality relations. + if (k != EQ_EXPR) + return; + unsigned v1 = SSA_NAME_VERSION (ssa1); unsigned v2 = SSA_NAME_VERSION (ssa2); + + // If this is the first time an ssa_name has an equivalency registered + // create a self-equivalency record in the def block. + if (!bitmap_bit_p (m_equiv_set, v1)) + register_initial_def (ssa1); + if (!bitmap_bit_p (m_equiv_set, v2)) + register_initial_def (ssa2); + equiv_chain *equiv_1 = find_equiv_dom (ssa1, bb); equiv_chain *equiv_2 = find_equiv_dom (ssa2, bb); @@ -420,6 +482,15 @@ equiv_oracle::register_equiv (basic_block bb, tree ssa1, tree ssa2) if (!equiv_set) return; + add_equiv_to_block (bb, equiv_set); +} + +// Add an equivalency record in block BB containing bitmap EQUIV_SET. +// Note the internal caller is responible for allocating EQUIV_SET properly. + +void +equiv_oracle::add_equiv_to_block (basic_block bb, bitmap equiv_set) +{ equiv_chain *ptr; // Check if this is the first time a block has an equivalence added. @@ -681,9 +752,37 @@ public: // ------------------------------------------------------------------------ +// Find the relation between any ssa_name in B1 and any name in B2 in LIST. +// This will allow equivalencies to be applied to any SSA_NAME in a relation. + +relation_kind +relation_chain_head::find_relation (const_bitmap b1, const_bitmap b2) const +{ + if (!m_names) + return VREL_NONE; + + // If both b1 and b2 aren't referenced in thie block, cant be a relation + if (!bitmap_intersect_p (m_names, b1) || !bitmap_intersect_p (m_names, b2)) + return VREL_NONE; + + // Search for the fiorst relation that contains BOTH an element from B1 + // and B2, and return that relation. + for (relation_chain *ptr = m_head; ptr ; ptr = ptr->m_next) + { + unsigned op1 = SSA_NAME_VERSION (ptr->op1 ()); + unsigned op2 = SSA_NAME_VERSION (ptr->op2 ()); + if (bitmap_bit_p (b1, op1) && bitmap_bit_p (b2, op2)) + return ptr->kind (); + if (bitmap_bit_p (b1, op2) && bitmap_bit_p (b2, op1)) + return relation_swap (ptr->kind ()); + } + + return VREL_NONE; +} + // Instantiate a relation oracle. -relation_oracle::relation_oracle () +dom_oracle::dom_oracle () { m_relations.create (0); m_relations.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); @@ -694,7 +793,7 @@ relation_oracle::relation_oracle () // Destruct a relation oracle. -relation_oracle::~relation_oracle () +dom_oracle::~dom_oracle () { m_relations.release (); } @@ -702,8 +801,8 @@ relation_oracle::~relation_oracle () // Register relation K between ssa_name OP1 and OP2 on STMT. void -relation_oracle::register_relation (gimple *stmt, relation_kind k, tree op1, - tree op2) +relation_oracle::register_stmt (gimple *stmt, relation_kind k, tree op1, + tree op2) { gcc_checking_assert (TREE_CODE (op1) == SSA_NAME); gcc_checking_assert (TREE_CODE (op2) == SSA_NAME); @@ -722,19 +821,35 @@ relation_oracle::register_relation (gimple *stmt, relation_kind k, tree op1, print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } - // This relation applies to the entire block, use STMT's block. - // Equivalencies are handled by the equivalence oracle. - if (k == EQ_EXPR) - register_equiv (gimple_bb (stmt), op1, op2); - else - register_relation (gimple_bb (stmt), k, op1, op2); + // If an equivalence is being added between a PHI and one of its arguments + // make sure that that argument is not defined in the same block. + // This can happen along back edges and the equivalence will not be + // applicable as it would require a use before def. + if (k == EQ_EXPR && is_a<gphi *> (stmt)) + { + tree phi_def = gimple_phi_result (stmt); + gcc_checking_assert (phi_def == op1 || phi_def == op2); + tree arg = op2; + if (phi_def == op2) + arg = op1; + if (gimple_bb (stmt) == gimple_bb (SSA_NAME_DEF_STMT (arg))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " Not registered due to "); + print_generic_expr (dump_file, arg, TDF_SLIM); + fprintf (dump_file, " being defined in the same block.\n"); + } + return; + } + } + register_relation (gimple_bb (stmt), k, op1, op2); } // Register relation K between ssa_name OP1 and OP2 on edge E. void -relation_oracle::register_relation (edge e, relation_kind k, tree op1, - tree op2) +relation_oracle::register_edge (edge e, relation_kind k, tree op1, tree op2) { gcc_checking_assert (TREE_CODE (op1) == SSA_NAME); gcc_checking_assert (TREE_CODE (op2) == SSA_NAME); @@ -752,24 +867,35 @@ relation_oracle::register_relation (edge e, relation_kind k, tree op1, fprintf (dump_file, " on (%d->%d)\n", e->src->index, e->dest->index); } - // Equivalencies are handled by the equivalence oracle. + register_relation (e->dest, k, op1, op2); +} + +// Register relation K between OP! and OP2 in block BB. +// This creates the record and searches for existing records in the dominator +// tree to merge with. + +void +dom_oracle::register_relation (basic_block bb, relation_kind k, tree op1, + tree op2) +{ // Equivalencies are handled by the equivalence oracle. if (k == EQ_EXPR) - register_equiv (e->dest, op1, op2); + equiv_oracle::register_relation (bb, k, op1, op2); else - register_relation (e->dest, k, op1, op2); + { + relation_chain *ptr = set_one_relation (bb, k, op1, op2); + register_transitives (bb, *ptr); + } } // Register relation K between OP! and OP2 in block BB. // This creates the record and searches for existing records in the dominator // tree to merge with. -// TRANSITIVE_P is true if this is being registered as a transitive operation, -// and should not try to register further transitives. -void -relation_oracle::register_relation (basic_block bb, relation_kind k, tree op1, - tree op2, bool transitive_p) +relation_chain * +dom_oracle::set_one_relation (basic_block bb, relation_kind k, tree op1, + tree op2) { - gcc_checking_assert (k != VREL_NONE); + gcc_checking_assert (k != VREL_NONE && k != EQ_EXPR); value_relation vr(k, op1, op2); int bbi = bb->index; @@ -824,11 +950,9 @@ relation_oracle::register_relation (basic_block bb, relation_kind k, tree op1, sizeof (relation_chain)); ptr->set_relation (k, op1, op2); ptr->m_next = m_relations[bbi].m_head; - m_relations[bbi].m_head = ptr;; + m_relations[bbi].m_head = ptr; } - - if (!transitive_p) - register_transitives (bb, *ptr); + return ptr; } // Starting at ROOT_BB search the DOM tree looking for relations which @@ -837,12 +961,25 @@ relation_oracle::register_relation (basic_block bb, relation_kind k, tree op1, // considered. void -relation_oracle::register_transitives (basic_block root_bb, - const value_relation &relation, - const_bitmap equiv1, - const_bitmap equiv2) +dom_oracle::register_transitives (basic_block root_bb, + const value_relation &relation) { basic_block bb; + // Only apply transitives to certain kinds of operations. + switch (relation.kind ()) + { + case LE_EXPR: + case LT_EXPR: + case GT_EXPR: + case GE_EXPR: + break; + default: + return; + } + + const_bitmap equiv1 = equiv_set (relation.op1 (), root_bb); + const_bitmap equiv2 = equiv_set (relation.op2 (), root_bb); + for (bb = root_bb; bb; bb = get_immediate_dominator (CDI_DOMINATORS, bb)) { int bbi = bb->index; @@ -897,8 +1034,7 @@ relation_oracle::register_transitives (basic_block root_bb, value_relation nr (relation.kind (), r1, r2); if (nr.apply_transitive (*ptr)) { - register_relation (root_bb, nr.kind (), nr.op1 (), nr.op2 (), - true); + set_one_relation (root_bb, nr.kind (), nr.op1 (), nr.op2 ()); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, " Registering transitive relation "); @@ -911,98 +1047,30 @@ relation_oracle::register_transitives (basic_block root_bb, } } -// Find adn register any transitive relations implied by RELATION occuring -// in block BB. - -void -relation_oracle::register_transitives (basic_block bb, - const value_relation &relation) -{ - // Only apply transitives to certain kinds of operations. - switch (relation.kind ()) - { - case LE_EXPR: - case LT_EXPR: - case GT_EXPR: - case GE_EXPR: - break; - default: - return; - } - - // Set up the bitmaps for op1 and op2, and if there are no equivalencies, - // set just op1 or op2 in their own bitmap. - const_bitmap equiv1 = equiv_set (relation.op1 (), bb); - const_bitmap equiv2 = equiv_set (relation.op2 (), bb); - if (equiv1) - { - if (equiv2) - register_transitives (bb, relation, equiv1, equiv2); - else - { - bitmap_clear (m_tmp); - bitmap_set_bit (m_tmp, SSA_NAME_VERSION (relation.op2 ())); - register_transitives (bb, relation, equiv1, m_tmp); - } - } - else if (equiv2) - { - bitmap_clear (m_tmp); - bitmap_set_bit (m_tmp, SSA_NAME_VERSION (relation.op1 ())); - register_transitives (bb, relation, m_tmp, equiv2); - } - else - { - bitmap_clear (m_tmp); - bitmap_clear (m_tmp2); - bitmap_set_bit (m_tmp, SSA_NAME_VERSION (relation.op1 ())); - bitmap_set_bit (m_tmp2, SSA_NAME_VERSION (relation.op2 ())); - register_transitives (bb, relation, m_tmp, m_tmp2); - } -} - // Find the relation between any ssa_name in B1 and any name in B2 in block BB. // This will allow equivalencies to be applied to any SSA_NAME in a relation. relation_kind -relation_oracle::find_relation_block (unsigned bb, const_bitmap b1, - const_bitmap b2) +dom_oracle::find_relation_block (unsigned bb, const_bitmap b1, + const_bitmap b2) const { - const_bitmap bm; if (bb >= m_relations.length()) return VREL_NONE; - bm = m_relations[bb].m_names; - if (!bm) - return VREL_NONE; - - // If both b1 and b2 aren't referenced in thie block, cant be a relation - if (!bitmap_intersect_p (bm, b1) || !bitmap_intersect_p (bm, b2)) - return VREL_NONE; - - // Search for the fiorst relation that contains BOTH an element from B1 - // and B2, and return that relation. - for (relation_chain *ptr = m_relations[bb].m_head; ptr ; ptr = ptr->m_next) - { - unsigned op1 = SSA_NAME_VERSION (ptr->op1 ()); - unsigned op2 = SSA_NAME_VERSION (ptr->op2 ()); - if (bitmap_bit_p (b1, op1) && bitmap_bit_p (b2, op2)) - return ptr->kind (); - if (bitmap_bit_p (b1, op2) && bitmap_bit_p (b2, op1)) - return relation_swap (ptr->kind ()); - } - - return VREL_NONE; + return m_relations[bb].find_relation (b1, b2); } -// Search the DOM tree for a relation between an element of B1 and B2, starting -// with block BB. +// Search the DOM tree for a relation between an element of equivalency set B1 +// and B2, starting with block BB. relation_kind -relation_oracle::find_relation_dom (basic_block bb, const_bitmap b1, - const_bitmap b2) +dom_oracle::query_relation (basic_block bb, const_bitmap b1, + const_bitmap b2) { relation_kind r; + if (bitmap_equal_p (b1, b2)) + return EQ_EXPR; + // If either name does not occur in a relation anywhere, there isnt one. if (!bitmap_intersect_p (m_relation_set, b1) || !bitmap_intersect_p (m_relation_set, b2)) @@ -1023,8 +1091,8 @@ relation_oracle::find_relation_dom (basic_block bb, const_bitmap b1, // is found, return a pointer to the chain object in OBJ. relation_kind -relation_oracle::find_relation_block (int bb, unsigned v1, unsigned v2, - relation_chain **obj) +dom_oracle::find_relation_block (int bb, unsigned v1, unsigned v2, + relation_chain **obj) const { if (bb >= (int)m_relations.length()) return VREL_NONE; @@ -1063,7 +1131,7 @@ relation_oracle::find_relation_block (int bb, unsigned v1, unsigned v2, // starting with block BB relation_kind -relation_oracle::find_relation_dom (basic_block bb, unsigned v1, unsigned v2) +dom_oracle::find_relation_dom (basic_block bb, unsigned v1, unsigned v2) const { relation_kind r; // IF either name does not occur in a relation anywhere, there isnt one. @@ -1084,7 +1152,7 @@ relation_oracle::find_relation_dom (basic_block bb, unsigned v1, unsigned v2) // dominator of BB relation_kind -relation_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) +dom_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) { relation_kind kind; unsigned v1 = SSA_NAME_VERSION (ssa1); @@ -1092,9 +1160,10 @@ relation_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) if (v1 == v2) return EQ_EXPR; - // Check for equivalence first. + // Check for equivalence first. They must be in each equivalency set. const_bitmap equiv1 = equiv_set (ssa1, bb); - if (equiv1 && bitmap_bit_p (equiv1, v2)) + const_bitmap equiv2 = equiv_set (ssa2, bb); + if (bitmap_bit_p (equiv1, v2) && bitmap_bit_p (equiv2, v1)) return EQ_EXPR; // Initially look for a direct relationship and just return that. @@ -1102,38 +1171,15 @@ relation_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) if (kind != VREL_NONE) return kind; - // If v2 isn't in v1s equiv set, then v1 shouldn't be in v2's set either. - // It is possible for out-of-order dominator processing to have an out of - // sync set of equivalences.. Down the road, when we do full updates, - // change this to an assert to ensure everything is in sync. - const_bitmap equiv2 = equiv_set (ssa2, bb); - if (equiv2 && bitmap_bit_p (equiv2, v1)) - return EQ_EXPR; - - // If not equal, see if there is a relationship between equivalences. - if (!equiv1 && !equiv2) - kind = VREL_NONE; - else if (!equiv1) - { - bitmap_clear (m_tmp); - bitmap_set_bit (m_tmp, v1); - kind = find_relation_dom (bb, m_tmp, equiv2); - } - else if (!equiv2) - { - bitmap_clear (m_tmp); - bitmap_set_bit (m_tmp, v2); - kind = find_relation_dom (bb, equiv1, m_tmp); - } - else - kind = find_relation_dom (bb, equiv1, equiv2); + // Query using the equiovalence sets. + kind = query_relation (bb, equiv1, equiv2); return kind; } // Dump all the relations in block BB to file F. void -relation_oracle::dump (FILE *f, basic_block bb) const +dom_oracle::dump (FILE *f, basic_block bb) const { equiv_oracle::dump (f,bb); @@ -1154,7 +1200,7 @@ relation_oracle::dump (FILE *f, basic_block bb) const // Dump all the relations known to file F. void -relation_oracle::dump (FILE *f) const +dom_oracle::dump (FILE *f) const { fprintf (f, "Relation dump\n"); for (unsigned i = 0; i < m_relations.length (); i++) @@ -1170,3 +1216,178 @@ relation_oracle::debug () const { dump (stderr); } + +path_oracle::path_oracle (relation_oracle *oracle) +{ + m_root = oracle; + bitmap_obstack_initialize (&m_bitmaps); + obstack_init (&m_chain_obstack); + + // Initialize header records. + m_equiv.m_names = BITMAP_ALLOC (&m_bitmaps); + m_equiv.m_bb = NULL; + m_equiv.m_next = NULL; + m_relations.m_names = BITMAP_ALLOC (&m_bitmaps); + m_relations.m_head = NULL; +} + +path_oracle::~path_oracle () +{ + obstack_free (&m_chain_obstack, NULL); + bitmap_obstack_release (&m_bitmaps); +} + +// Return the equiv set for SSA, and if there isn't one, check for equivs +// starting in block BB. + +const_bitmap +path_oracle::equiv_set (tree ssa, basic_block bb) +{ + // Check the list first. + equiv_chain *ptr = m_equiv.find (SSA_NAME_VERSION (ssa)); + if (ptr) + return ptr->m_names; + + // Otherwise defer to the root oracle. + if (m_root) + return m_root->equiv_set (ssa, bb); + + // Allocate a throw away bitmap if there isn't a root oracle. + bitmap tmp = BITMAP_ALLOC (&m_bitmaps); + bitmap_set_bit (tmp, SSA_NAME_VERSION (ssa)); + return tmp; +} + +// Register an equivalence between SSA1 and SSA2 resolving unkowns from +// block BB. + +void +path_oracle::register_equiv (basic_block bb, tree ssa1, tree ssa2) +{ + const_bitmap equiv_1 = equiv_set (ssa1, bb); + const_bitmap equiv_2 = equiv_set (ssa2, bb); + + // Check if they are the same set, if so, we're done. + if (bitmap_equal_p (equiv_1, equiv_2)) + return; + + // Don't mess around, simply create a new record and insert it first. + bitmap b = BITMAP_ALLOC (&m_bitmaps); + bitmap_copy (b, equiv_1); + bitmap_ior_into (b, equiv_2); + + equiv_chain *ptr = (equiv_chain *) obstack_alloc (&m_chain_obstack, + sizeof (equiv_chain)); + ptr->m_names = b; + ptr->m_bb = NULL; + ptr->m_next = m_equiv.m_next; + m_equiv.m_next = ptr; + bitmap_ior_into (m_equiv.m_names, b); +} + +// Register relation K between SSA1 and SSA2, resolving unknowns by +// querying from BB. + +void +path_oracle::register_relation (basic_block bb, relation_kind k, tree ssa1, + tree ssa2) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + { + value_relation vr (k, ssa1, ssa2); + fprintf (dump_file, " Registering value_relation (path_oracle) "); + vr.dump (dump_file); + fprintf (dump_file, " (bb%d)\n", bb->index); + } + + if (k == EQ_EXPR) + { + register_equiv (bb, ssa1, ssa2); + return; + } + + relation_kind curr = query_relation (bb, ssa1, ssa2); + if (curr != VREL_NONE) + k = relation_intersect (curr, k); + + bitmap_set_bit (m_relations.m_names, SSA_NAME_VERSION (ssa1)); + bitmap_set_bit (m_relations.m_names, SSA_NAME_VERSION (ssa2)); + relation_chain *ptr = (relation_chain *) obstack_alloc (&m_chain_obstack, + sizeof (relation_chain)); + ptr->set_relation (k, ssa1, ssa2); + ptr->m_next = m_relations.m_head; + m_relations.m_head = ptr; +} + +// Query for a relationship between equiv set B1 and B2, resolving unknowns +// starting at block BB. + +relation_kind +path_oracle::query_relation (basic_block bb, const_bitmap b1, const_bitmap b2) +{ + if (bitmap_equal_p (b1, b2)) + return EQ_EXPR; + + relation_kind k = m_relations.find_relation (b1, b2); + + if (k == VREL_NONE && m_root) + k = m_root->query_relation (bb, b1, b2); + + return k; +} + +// Query for a relationship between SSA1 and SSA2, resolving unknowns +// starting at block BB. + +relation_kind +path_oracle::query_relation (basic_block bb, tree ssa1, tree ssa2) +{ + unsigned v1 = SSA_NAME_VERSION (ssa1); + unsigned v2 = SSA_NAME_VERSION (ssa2); + + if (v1 == v2) + return EQ_EXPR; + + const_bitmap equiv_1 = equiv_set (ssa1, bb); + const_bitmap equiv_2 = equiv_set (ssa2, bb); + if (bitmap_bit_p (equiv_1, v2) && bitmap_bit_p (equiv_2, v1)) + return EQ_EXPR; + + return query_relation (bb, equiv_1, equiv_2); +} + +// Reset any relations registered on this path. + +void +path_oracle::reset_path () +{ + m_equiv.m_next = NULL; + bitmap_clear (m_equiv.m_names); + m_relations.m_head = NULL; + bitmap_clear (m_relations.m_names); +} + +// Dump relation in basic block... Do nothing here. + +void +path_oracle::dump (FILE *, basic_block) const +{ +} + +// Dump the relations and equivalencies found in the path. + +void +path_oracle::dump (FILE *f) const +{ + equiv_chain *ptr = m_equiv.m_next; + for (; ptr; ptr = ptr->m_next) + ptr->dump (f); + + relation_chain *ptr2 = m_relations.m_head; + for (; ptr2; ptr2 = ptr2->m_next) + { + fprintf (f, "Relational : "); + ptr2->dump (f); + fprintf (f, "\n"); + } +} diff --git a/gcc/value-relation.h b/gcc/value-relation.h index 27158e0..53cefbf 100644 --- a/gcc/value-relation.h +++ b/gcc/value-relation.h @@ -73,23 +73,61 @@ relation_kind relation_negate (relation_kind r); relation_kind relation_swap (relation_kind r); void print_relation (FILE *f, relation_kind rel); -// Declared internally in value-relation.cc -class equiv_chain; + +class relation_oracle +{ +public: + virtual ~relation_oracle () { } + // register a relation between 2 ssa names at a stmt. + void register_stmt (gimple *, relation_kind, tree, tree); + // register a relation between 2 ssa names on an edge. + void register_edge (edge, relation_kind, tree, tree); + + // Return equivalency set for an SSA name in a basic block. + virtual const_bitmap equiv_set (tree, basic_block) = 0; + // register a relation between 2 ssa names in a basic block. + virtual void register_relation (basic_block, relation_kind, tree, tree) = 0; + // Query for a relation between two ssa names in a basic block. + virtual relation_kind query_relation (basic_block, tree, tree) = 0; + // Query for a relation between two equivalency stes in a basic block. + virtual relation_kind query_relation (basic_block, const_bitmap, + const_bitmap) = 0; + + virtual void dump (FILE *, basic_block) const = 0; + virtual void dump (FILE *) const = 0; + void debug () const; +}; + +// This class represents an equivalency set, and contains a link to the next +// one in the list to be searched. + +class equiv_chain +{ +public: + bitmap m_names; // ssa-names in equiv set. + basic_block m_bb; // Block this belongs to + equiv_chain *m_next; // Next in block list. + void dump (FILE *f) const; // Show names in this list. + equiv_chain *find (unsigned ssa); +}; // The equivalency oracle maintains equivalencies using the dominator tree. // Equivalencies apply to an entire basic block. Equivalencies on edges // can be represented only on edges whose destination is a single-pred block, // and the equivalence is simply applied to that succesor block. -class equiv_oracle +class equiv_oracle : public relation_oracle { public: equiv_oracle (); ~equiv_oracle (); - const_bitmap equiv_set (tree ssa, basic_block bb) const; - void register_equiv (basic_block bb, tree ssa1, tree ssa2); + const_bitmap equiv_set (tree ssa, basic_block bb); + void register_relation (basic_block bb, relation_kind k, tree ssa1, + tree ssa2); + relation_kind query_relation (basic_block, tree, tree); + relation_kind query_relation (basic_block, const_bitmap, const_bitmap); void dump (FILE *f, basic_block bb) const; void dump (FILE *f) const; @@ -99,6 +137,7 @@ protected: private: bitmap m_equiv_set; // Index by ssa-name. true if an equivalence exists. vec <equiv_chain *> m_equiv; // Index by BB. list of equivalences. + vec <bitmap> m_self_equiv; // Index by ssa-name, self equivalency set. void limit_check (basic_block bb = NULL); equiv_chain *find_equiv_block (unsigned ssa, int bb) const; @@ -107,7 +146,8 @@ private: bitmap register_equiv (basic_block bb, unsigned v, equiv_chain *equiv_1); bitmap register_equiv (basic_block bb, equiv_chain *equiv_1, equiv_chain *equiv_2); - + void register_initial_def (tree ssa); + void add_equiv_to_block (basic_block bb, bitmap equiv); }; // Summary block header for relations. @@ -117,6 +157,7 @@ class relation_chain_head public: bitmap m_names; // ssa_names with relations in this block. class relation_chain *m_head; // List of relations in block. + relation_kind find_relation (const_bitmap b1, const_bitmap b2) const; }; // A relation oracle maintains a set of relations between ssa_names using the @@ -129,37 +170,70 @@ public: // relation to the destination block of the edge, but ONLY if that block // has a single successor. For now. -class relation_oracle : public equiv_oracle +class dom_oracle : public equiv_oracle { public: - relation_oracle (); - ~relation_oracle (); + dom_oracle (); + ~dom_oracle (); - void register_relation (gimple *stmt, relation_kind k, tree op1, tree op2); - void register_relation (edge e, relation_kind k, tree op1, tree op2); + void register_relation (basic_block bb, relation_kind k, tree op1, tree op2); relation_kind query_relation (basic_block bb, tree ssa1, tree ssa2); + relation_kind query_relation (basic_block bb, const_bitmap b1, + const_bitmap b2); void dump (FILE *f, basic_block bb) const; void dump (FILE *f) const; - void debug () const; private: bitmap m_tmp, m_tmp2; bitmap m_relation_set; // Index by ssa-name. True if a relation exists vec <relation_chain_head> m_relations; // Index by BB, list of relations. relation_kind find_relation_block (unsigned bb, const_bitmap b1, - const_bitmap b2); - relation_kind find_relation_dom (basic_block bb, const_bitmap b1, - const_bitmap b2); + const_bitmap b2) const; relation_kind find_relation_block (int bb, unsigned v1, unsigned v2, - relation_chain **obj = NULL); - relation_kind find_relation_dom (basic_block bb, unsigned v1, unsigned v2); - void register_relation (basic_block bb, relation_kind k, tree op1, tree op2, - bool transitive_p = false); + relation_chain **obj = NULL) const; + relation_kind find_relation_dom (basic_block bb, unsigned v1, unsigned v2) const; + relation_chain *set_one_relation (basic_block bb, relation_kind k, tree op1, + tree op2); void register_transitives (basic_block, const class value_relation &); - void register_transitives (basic_block, const value_relation &, const_bitmap, - const_bitmap); }; +// A path_oracle implements relations in a list. The only sense of ordering +// is the latest registered relation is the first found during a search. +// It can be constructed with an optional "root" oracle which will be used +// to look up any relations not found in the list. +// This allows the client to walk paths starting at some block and register +// and query relations along that path, ignoring other edges. +// +// For registering a relation, a query if made of the root oracle if there is +// any known relationship at block BB, and it is combined with this new +// relation and entered in the list. +// +// Queries are resolved by looking first in the list, and only if nothing is +// found is the root oracle queried at block BB. +// +// reset_path is used to clear all locally registered paths to initial state. + +class path_oracle : public relation_oracle +{ +public: + path_oracle (relation_oracle *oracle = NULL); + ~path_oracle (); + const_bitmap equiv_set (tree, basic_block); + void register_relation (basic_block, relation_kind, tree, tree); + relation_kind query_relation (basic_block, tree, tree); + relation_kind query_relation (basic_block, const_bitmap, const_bitmap); + void reset_path (); + void dump (FILE *, basic_block) const; + void dump (FILE *) const; +private: + void register_equiv (basic_block bb, tree ssa1, tree ssa2); + equiv_chain m_equiv; + relation_chain_head m_relations; + relation_oracle *m_root; + + bitmap_obstack m_bitmaps; + struct obstack m_chain_obstack; +}; #endif /* GCC_VALUE_RELATION_H */ diff --git a/gcc/vr-values.c b/gcc/vr-values.c index c999ca8..3b8d067 100644 --- a/gcc/vr-values.c +++ b/gcc/vr-values.c @@ -3454,6 +3454,32 @@ range_fits_type_p (const value_range *vr, return true; } +// Clear edge E of EDGE_EXECUTABLE (it is unexecutable). If it wasn't +// previously clear, propagate to successor blocks if appropriate. + +void +simplify_using_ranges::set_and_propagate_unexecutable (edge e) +{ + // If EXECUUTABLE is already clear, we're done. + if ((e->flags & EDGE_EXECUTABLE) == 0) + return; + + e->flags &= ~EDGE_EXECUTABLE; + + // Check if the destination block needs to propagate the property. + basic_block bb = e->dest; + + // If any entry edge is marked EXECUTABLE, we are done. + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->preds) + if (e->flags & EDGE_EXECUTABLE) + return; + + // This block is also unexecutable, propagate to all exit edges as well. + FOR_EACH_EDGE (e, ei, bb->succs) + set_and_propagate_unexecutable (e); +} + /* If COND can be folded entirely as TRUE or FALSE, rewrite the conditional as such, and return TRUE. */ @@ -3467,18 +3493,27 @@ simplify_using_ranges::fold_cond (gcond *cond) if (TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME && TREE_CODE (gimple_cond_rhs (cond)) != SSA_NAME) return false; - + edge e0 = EDGE_SUCC (gimple_bb (cond), 0); + edge e1 = EDGE_SUCC (gimple_bb (cond), 1); if (r.zero_p ()) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "\nPredicate evaluates to: 0\n"); gimple_cond_make_false (cond); + if (e0->flags & EDGE_TRUE_VALUE) + set_and_propagate_unexecutable (e0); + else + set_and_propagate_unexecutable (e1); } else { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "\nPredicate evaluates to: 1\n"); gimple_cond_make_true (cond); + if (e0->flags & EDGE_FALSE_VALUE) + set_and_propagate_unexecutable (e0); + else + set_and_propagate_unexecutable (e1); } update_stmt (cond); return true; @@ -3769,7 +3804,7 @@ simplify_using_ranges::simplify_switch_using_ranges (gswitch *stmt) fprintf (dump_file, "removing unreachable case label\n"); } to_remove_edges.safe_push (e); - e->flags &= ~EDGE_EXECUTABLE; + set_and_propagate_unexecutable (e); e->flags |= EDGE_IGNORE; } diff --git a/gcc/vr-values.h b/gcc/vr-values.h index 7fdefef..4693908 100644 --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@ -66,6 +66,7 @@ private: tree vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code, tree, tree, bool *, gimple *s); + void set_and_propagate_unexecutable (edge e); void cleanup_edges_and_switches (void); /* Vectors of edges that need removing and switch statements that |