diff options
author | Gaius Mulley <gaius.mulley@southwales.ac.uk> | 2022-06-06 11:04:29 +0100 |
---|---|---|
committer | Gaius Mulley <gaius.mulley@southwales.ac.uk> | 2022-06-06 11:04:29 +0100 |
commit | 568b62ce9207f56859e1116f60f6cfb35da59051 (patch) | |
tree | f58132717ccd6e7d8fb728d0e85bfccc30dafba6 /gcc | |
parent | 9409a75aa98e6365d0e08ddf9022b44c24c5d758 (diff) | |
parent | df68ed4a3cb0dc6691da6cb34c1d1feb7ba9c9d4 (diff) | |
download | gcc-568b62ce9207f56859e1116f60f6cfb35da59051.zip gcc-568b62ce9207f56859e1116f60f6cfb35da59051.tar.gz gcc-568b62ce9207f56859e1116f60f6cfb35da59051.tar.bz2 |
Merge branch 'master' into devel/modula-2.
Diffstat (limited to 'gcc')
320 files changed, 12122 insertions, 3682 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6434f55..55cb88c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,808 @@ +2022-06-04 Roger Sayle <roger@nextmovesoftware.com> + + PR middle-end/95126 + * calls.cc (load_register_parameters): When loading a suitable + immediate_const_ctor_p VAR_DECL into a single word_mode register, + construct it directly in a pseudo rather than read it (by parts) + from memory. + * expr.cc (int_expr_size): Make tree argument a const_tree. + (immediate_const_ctor_p): Helper predicate. Return true for + simple constructors that may be materialized in a register. + (expand_expr_real_1) [VAR_DECL]: When expanding a constant + VAR_DECL with a suitable immediate_const_ctor_p constructor + use store_constructor to materialize it directly in a pseudo. + * expr.h (immediate_const_ctor_p): Prototype here. + * varasm.cc (initializer_constant_valid_for_bitfield_p): Change + VALUE argument from tree to const_tree. + * varasm.h (initializer_constant_valid_for_bitfield_p): Update + prototype. + +2022-06-04 Jakub Jelinek <jakub@redhat.com> + + PR target/105825 + * config/i386/i386.md (*ashl<dwi>3_doubleword_mask, + *<insn><dwi>3_doubleword_mask): If top bit of mask is clear, but lower + bits of mask aren't all set, use operands[2] mode for the AND + operation instead of always SImode. + +2022-06-03 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/30314 + PR middle-end/105777 + * match.pd (__builtin_mul_overflow_p (x, cst, (stype) 0) -> + x > stype_max / cst || x < stype_min / cst): New simplification. + +2022-06-03 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-cache.cc (ranger_cache::range_from_dom): Use + Value_Range. + * gimple-range.cc (gimple_ranger::register_inferred_ranges): Same. + * value-range.h (Value_Range::Value_Range): Implement copy + constructor for Value_Range. + +2022-06-03 Aldy Hernandez <aldyh@redhat.com> + + * value-range.h (struct vrange_traits): Remove. + (is_a): Rewrite without vrange_traits. + (as_a): Same. + +2022-06-03 Aldy Hernandez <aldyh@redhat.com> + + * value-range.cc (vrange::contains_p): Implement. + (vrange::type): Return void. + (vrange::supports_type_p): Implement. + (irange::fits_p): Same. + (vrange::set_undefined): Same. + (irange::set_nonnegative): Same. + (vrange::set_varying): Same. + (vrange::union_): Same. + (unsupported_range::set): Move to vrange. + (unsupported_range::type): Move to vrange. + (vrange::intersect): Implement for varying and undefined. + (vrange::zero_p): Implement. + (unsupported_range::supports_type_p): Move to vrange. + (vrange::nonzero_p): Implement. + (unsupported_range::set_undefined): Move to vrange. + (unsupported_range::set_varying): Same. + (unsupported_range::dump): Same. + (unsupported_range::union_): Same. Implement for varying and + undefined. + (unsupported_range::intersect): Move to vrange. + (unsupported_range::zero_p): Same. + (unsupported_range::nonzero_p): Same. + (unsupported_range::set_nonzero): Same. + (unsupported_range::set_zero): Same. + (unsupported_range::set_nonnegative): Same. + (unsupported_range::fits_p): Same. + * value-range.h (class vrange): Remove abstract markers for most + methods. + (class unsupported_range): Remove most methods as they will now be + inherited from vrange. + +2022-06-03 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for + an object level supports_type_p for irange and a static + Value_Range::supports_type_p. + * gimple-range-fold.cc (fold_using_range::range_of_range_op): Same. + (fold_using_range::range_of_address): Same. + (fold_using_range::range_of_builtin_call): Same. + * gimple-range-fold.h (gimple_range_type): Same. + (gimple_range_ssa_p): Same. + * gimple-range-path.cc (path_range_query::internal_range_of_expr): + Same. + (path_range_query::range_of_stmt): Same. + (path_range_query::add_to_imports): Same. + * gimple-range.cc (gimple_ranger::range_on_edge): Same. + (gimple_ranger::export_global_ranges): Same. + * gimple-ssa-evrp-analyze.cc + (evrp_range_analyzer::record_ranges_from_phis): Same. + * range-op.cc (range_operator::wi_fold): Same. + (range_operator::fold_range): Same. + * tree-ssa-loop-ch.cc (entry_loop_condition_is_static): Same. + * tree-ssa-loop-unswitch.cc (struct unswitch_predicate): Same. + (evaluate_control_stmt_using_entry_checks): Same. + * tree-ssa-threadedge.cc + (hybrid_jt_simplifier::compute_ranges_from_state): Same. + * tree-vrp.cc (supported_types_p): Same. + * value-query.cc (range_query::value_of_expr): Same. + (range_query::value_on_edge): Same. + (range_query::value_of_stmt): Same. + (range_query::get_tree_range): Same. + (get_range_global): Same. + (global_range_query::range_of_expr): Same. + * value-range-equiv.h (class value_range_equiv): Same. + * value-range.cc (irange::supports_type_p): Same. + (unsupported_range::supports_type_p): Same. + * value-range.h (enum value_range_discriminator): Same. + (Value_Range::init): Same. + (Value_Range::supports_type_p): Same. + (irange::supports_type_p): Same. + (irange::supports_p): Same. + (vrange::supports_type_p): Same. + (vrange_allocator::alloc_vrange): Same. + +2022-06-03 Jan Beulich <jbeulich@suse.com> + + * Makefile.in (ORIGINAL_OBJCOPY_FOR_TARGET): New. + * configure.ac: Check for objcopy, producing + ORIGINAL_OBJCOPY_FOR_TARGET. + * configure: Update accordingly. + * exec-tool.in (ORIGINAL_OBJCOPY_FOR_TARGET): New. + Handle objcopy. + +2022-06-03 Jan Beulich <jbeulich@suse.com> + + * config/i386/mmx.md (mmx_psadbw): Convert to expander. + (*mmx_psadbw): New. Mark as commutative. + * config/i386/sse.md (<sse2_avx2>_psadbw): Convert to expander. + (*<sse2_avx2>_psadbw): New. Mark as commutative. + +2022-06-03 Alexandre Oliva <oliva@adacore.com> + + PR tree-optimization/105665 + PR tree-optimization/100810 + * tree-ssa-loop-ivopts.cc + (ssa_name_maybe_undef_p, ssa_name_set_maybe_undef): New. + (ssa_name_any_use_dominates_bb_p, mark_ssa_maybe_undefs): New. + (find_ssa_undef): Check precomputed flag and intervening uses. + (tree_ssa_iv_optimize): Call mark_ssa_maybe_undefs. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * Makefile.in (OBJS): Add tree-diagnostic-client-data-hooks.o and + tree-logical-location.o. + (OBJS-libcommon): Add diagnostic-format-sarif.o; reorder. + (CFLAGS-tree-diagnostic-client-data-hooks.o): Add TARGET_NAME. + * common.opt (fdiagnostics-format=): Add sarif-stderr and sarif-file. + (sarif-stderr, sarif-file): New enum values. + * diagnostic-client-data-hooks.h: New file. + * diagnostic-format-sarif.cc: New file. + * diagnostic-path.h (enum diagnostic_event::verb): New enum. + (enum diagnostic_event::noun): New enum. + (enum diagnostic_event::property): New enum. + (struct diagnostic_event::meaning): New struct. + (diagnostic_event::get_logical_location): New vfunc. + (diagnostic_event::get_meaning): New vfunc. + (simple_diagnostic_event::get_logical_location): New vfunc impl. + (simple_diagnostic_event::get_meaning): New vfunc impl. + * diagnostic.cc: Include "diagnostic-client-data-hooks.h". + (diagnostic_initialize): Initialize m_client_data_hooks. + (diagnostic_finish): Clean up m_client_data_hooks. + (diagnostic_event::meaning::dump_to_pp): New. + (diagnostic_event::meaning::maybe_get_verb_str): New. + (diagnostic_event::meaning::maybe_get_noun_str): New. + (diagnostic_event::meaning::maybe_get_property_str): New. + (get_cwe_url): Make non-static. + (diagnostic_output_format_init): Handle + DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR and + DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE. + * diagnostic.h (enum diagnostics_output_format): Add + DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR and + DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE. + (class diagnostic_client_data_hooks): New forward decl. + (class logical_location): New forward decl. + (diagnostic_context::m_client_data_hooks): New field. + (diagnostic_output_format_init_sarif_stderr): New decl. + (diagnostic_output_format_init_sarif_file): New decl. + (get_cwe_url): New decl. + * doc/invoke.texi (-fdiagnostics-format=): Add sarif-stderr and + sarif-file. + * doc/sourcebuild.texi (Scan a particular file): Add + scan-sarif-file and scan-sarif-file-not. + * langhooks-def.h (lhd_get_sarif_source_language): New decl. + (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): New macro. + (LANG_HOOKS_INITIALIZER): Add + LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE. + * langhooks.cc (lhd_get_sarif_source_language): New. + * langhooks.h (lang_hooks::get_sarif_source_language): New field. + * logical-location.h: New file. + * plugin.cc (struct for_each_plugin_closure): New. + (for_each_plugin_cb): New. + (for_each_plugin): New. + * plugin.h (for_each_plugin): New decl. + * tree-diagnostic-client-data-hooks.cc: New file. + * tree-diagnostic.cc: Include "diagnostic-client-data-hooks.h". + (tree_diagnostics_defaults): Populate m_client_data_hooks. + * tree-logical-location.cc: New file. + * tree-logical-location.h: New file. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * common.opt (fdiagnostics-format=): Add json-stderr and json-file + to description. + (DIAGNOSTICS_OUTPUT_FORMAT_JSON): Rename to... + (DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR): ...this. + (diagnostics_output_format): Add json-stderr and json-file. + * diagnostic-format-json.cc (json_flush_to_file): New. + (json_final_cb): Convert to... + (json_flush_to_file): ...this, ... + (json_stderr_final_cb): ...this, and... + (json_file_final_cb): ...this. + (diagnostic_output_format_init): Move to diagnostic.cc. + (json_output_base_file_name): New. + (diagnostic_output_format_init_json): New. + (diagnostic_output_format_init_json_stderr): New. + (diagnostic_output_format_init_json_file): New. + * diagnostic.cc (diagnostic_output_format_init): Move here from + diagnostic-format-json.cc; update for changes to enum. + * diagnostic.h (enum diagnostics_output_format): Rename + DIAGNOSTICS_OUTPUT_FORMAT_JSON to + DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR, and add + DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE. + (diagnostic_output_format_init): Add base_file_name param. + (diagnostic_output_format_init_json_stderr): New decl. + (diagnostic_output_format_init_json_file): New dec. + * doc/invoke.texi (-fdiagnostics-format=): Add "json-stderr" and + "json-file". Rewrite so that the existing "json" is a synonym of + "json-stderr". + * gcc.cc (driver_handle_option): Pass dump_base_name to + diagnostic_output_format_init. + * opts.cc (common_handle_option): Likewise. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * json.cc (string::print): Fix escaping of '\'. + +2022-06-02 Philipp Tomsich <philipp.tomsich@vrull.eu> + + * config/riscv/riscv.cc (riscv_build_integer_1): Rewrite value as + (-1 << 31) for the single-bit case, when operating on (1 << 31) + in SImode. + * config/riscv/riscv.h (SINGLE_BIT_MASK_OPERAND): Allow for + any single-bit value, moving the special case for (1 << 31) to + riscv_build_integer_1 (in riscv.c). + +2022-06-02 Roger Sayle <roger@nextmovesoftware.com> + + PR target/105791 + * config/i386/sse.md (V_128_256):Add V1TI and V2TI. + (define_mode_attr avxsizesuffix): Add support for V1TI and V2TI. + +2022-06-02 Jakub Jelinek <jakub@redhat.com> + + PR target/105778 + * config/i386/i386.md (*ashl<dwi>3_doubleword_mask): Remove :SI + from AND and its operands and just verify operands[2] has HImode, + SImode or for TARGET_64BIT DImode. Allow operands[3] to be a mask + with all low 6 (64-bit) or 5 (32-bit) bits set and in that case + just throw away the masking. Use force_reg before calling + gen_lowpart. + (*ashl<dwi>3_doubleword_mask_1): Allow operands[3] to be a mask + with all low 6 (64-bit) or 5 (32-bit) bits set and in that case + just throw away the masking. + (*ashl<mode>3_doubleword): Rename to ... + (ashl<mode>3_doubleword): ... this. + (*ashl<mode>3_mask): Remove :SI from AND and its operands and just + verify operands[2] has HImode, SImode or for TARGET_64BIT DImode. + Use force_reg before calling gen_lowpart. + (*<insn><mode>3_mask): Likewise. + (*<insn><dwi>3_doubleword_mask): Likewise. Allow operands[3] to be + a mask with all low 6 (64-bit) or 5 (32-bit) bits set and in that + case just throw away the masking. Use force_reg before calling + gen_lowpart. + (*<insn><dwi>3_doubleword_mask_1): Allow operands[3] to be a mask + with all low 6 (64-bit) or 5 (32-bit) bits set and in that case just + throw away the masking. + (*<insn><mode>3_doubleword): Rename to ... + (<insn><mode>3_doubleword): ... this. + (*<insn><mode>3_mask): Remove :SI from AND and its operands and just + verify operands[2] has HImode, SImode or for TARGET_64BIT DImode. + Use force_reg before calling gen_lowpart. + (splitter after it): Remove :SI from AND and its operands and just + verify operands[2] has HImode, SImode or for TARGET_64BIT DImode. + (*<btsc><mode>_mask, *<btsc><mode>_mask): Remove :SI from AND and its + operands and just verify operands[1] has HImode, SImode or for + TARGET_64BIT DImode. Use force_reg before calling gen_lowpart. + (*jcc_bt<mode>_mask_1): New define_insn_and_split pattern. + * config/i386/i386.cc (ix86_rtx_costs): For ZERO_EXTRACT with + ZERO_EXTEND QI->SI in last operand ignore the cost of the ZERO_EXTEND. + +2022-06-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101668 + * tree-vect-slp.cc (vect_build_slp_tree_1): Allow BIT_FIELD_REFs + for vector types with compatible lane types. + (vect_build_slp_tree_2): Deal with this. + (vect_add_slp_permutation): Adjust. Emit lowpart/concat + special cases without VEC_PERM. + (vectorizable_slp_permutation): Select the operand vector + type and relax requirements. Handle identity permutes + with mismatching operand types. + * optabs-query.cc (can_vec_perm_const_p): Only allow variable + permutes for op_mode == mode. + +2022-06-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105802 + * tree-ssa-loop-unswitch.cc (find_unswitching_predicates_for_bb): + Make sure to also compute the range in the type of the switch index. + +2022-06-01 David Seifert <soap@gentoo.org> + + PR plugins/95648 + * configure: Regenerate. + +2022-06-01 H.J. Lu <hjl.tools@gmail.com> + + PR rtl-optimization/105638 + * df-core.cc (df_find_single_def_src): Moved and renamed from + find_single_def_src in loop-iv.cc. Change the argument to rtx + and use rtx_equal_p. Return null for partial or conditional + defs. + * df.h (df_find_single_def_src): New prototype. + * dse.cc (record_store): Use the constant source if the source + register is set only once. + * loop-iv.cc (find_single_def_src): Moved to df-core.cc. + (replace_single_def_regs): Replace find_single_def_src with + df_find_single_def_src. + +2022-06-01 Wilco Dijkstra <wilco.dijkstra@arm.com> + + * config/aarch64/aarch64.opt (explicit_tune_core): Rename to + selected_tune. + (explicit_arch): Rename to selected_arch. + (x_aarch64_override_tune_string): Remove. + (aarch64_ra_sign_key): Add as TargetVariable so it gets saved/restored. + (aarch64_override_tune_string): Add Save so it gets saved/restored. + * config/aarch64/aarch64.h (aarch64_architecture_version): Remove. + * config/aarch64/aarch64.cc (aarch64_architecture_version): Remove. + (processor): Remove archtecture_version field. + (selected_arch): Remove global. + (selected_cpu): Remove global. + (selected_tune): Remove global. + (aarch64_ra_sign_key): Move global to aarch64.opt so it is saved. + (aarch64_override_options_internal): Use aarch64_get_tune_cpu. + (aarch64_override_options): Further simplify code to only set + selected_arch and selected_tune globals. + (aarch64_option_save): Remove now that target options are saved. + (aarch64_option_restore): Remove redundant target option restores. + * config/aarch64/aarch64-c.cc (aarch64_update_cpp_builtins): Use + AARCH64_ISA_V9. + * config/aarch64/aarch64-opts.h (aarch64_key_type): Add, moved from... + * config/aarch64/aarch64-protos.h (aarch64_key_type): Remove. + (aarch64_ra_sign_key): Remove. + +2022-06-01 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/30314 + * match.pd (__builtin_mul_overflow_p (x, cst, (utype) 0) -> + x > ~(utype)0 / cst): New simplification. + +2022-06-01 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105786 + * tree-loop-distribution.cc + (loop_distribution::transform_reduction_loop): Only do strlen + replacement for integer type reductions. + +2022-06-01 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/105770 + * tree-ssa-loop-unswitch.cc (find_unswitching_predicates_for_bb): Cast + CASE_LOW and CASE_HIGH to TREE_TYPE (idx) before comparisons with idx. + +2022-06-01 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-cache.cc (ssa_block_ranges::dump): Convert to vrange. + (sbr_vector::sbr_vector): Same. + (sbr_vector::grow): Same. + (sbr_vector::set_bb_range): Same. + (sbr_vector::get_bb_range): Same. + (sbr_sparse_bitmap::sbr_sparse_bitmap): Same. + (sbr_sparse_bitmap::set_bb_range): Same. + (sbr_sparse_bitmap::get_bb_range): Same. + (block_range_cache::set_bb_range): Same. + (block_range_cache::get_bb_range): Same. + (block_range_cache::dump): Same. + (ssa_global_cache::get_global_range): Same. + (ssa_global_cache::set_global_range): Same. + (ssa_global_cache::clear): Same. + (ssa_global_cache::dump): Same. + (ranger_cache::get_global_range): Same. + (ranger_cache::set_global_range): Same. + (ranger_cache::range_of_def): Same. + (ranger_cache::entry_range): Same. + (ranger_cache::exit_range): Same. + (ranger_cache::edge_range): Same. + (ranger_cache::range_of_expr): Same. + (ranger_cache::range_on_edge): Same. + (ranger_cache::block_range): Same. + (ranger_cache::propagate_cache): Same. + (ranger_cache::fill_block_cache): Same. + (ranger_cache::range_from_dom): Same. + * gimple-range-cache.h: Same. + * gimple-range-edge.cc (gimple_outgoing_range::get_edge_range): + Same. + (gimple_outgoing_range::switch_edge_range): Same. + (gimple_outgoing_range::edge_range_p): Same. + * gimple-range-edge.h: Same. + * gimple-range-fold.cc (fur_source::get_operand): Same. + (fur_source::get_phi_operand): Same. + (fur_edge::get_operand): Same. + (fur_edge::get_phi_operand): Same. + (fur_stmt::get_operand): Same. + (fur_stmt::get_phi_operand): Same. + (fur_list::fur_list): Same. + (fur_list::get_operand): Same. + (fur_list::get_phi_operand): Same. + (fold_range): Same. + (adjust_imagpart_expr): Same. + (adjust_realpart_expr): Same. + (gimple_range_adjustment): Same. + (fold_using_range::fold_stmt): Same. + (fold_using_range::range_of_range_op): Same. + (fold_using_range::range_of_address): Same. + (fold_using_range::range_of_phi): Same. + (fold_using_range::range_of_call): Same. + (fold_using_range::range_of_builtin_call): Same. + (fold_using_range::range_of_builtin_int_call): Same. + (fold_using_range::range_of_cond_expr): Same. + (fur_source::register_outgoing_edges): Same. + * gimple-range-fold.h (fold_range): Same. + (gimple_range_type): Same. + (gimple_range_ssa_p): Same. + * gimple-range-gori.cc (gimple_range_calc_op1): Same. + (gimple_range_calc_op2): Same. + (gori_compute::compute_operand_range_switch): Same. + (gori_compute::compute_operand_range): Same. + (gori_compute::logical_combine): Same. + (gori_compute::compute_logical_operands): Same. + (gori_compute::compute_operand1_range): Same. + (gori_compute::compute_operand2_range): Same. + (gori_compute::compute_operand1_and_operand2_range): Same. + (gori_compute::outgoing_edge_range_p): Same. + (gori_compute::condexpr_adjust): Same. + * gimple-range-gori.h (gimple_range_calc_op1): Same. + (gimple_range_calc_op2): Same. + * gimple-range-path.cc (path_range_query::get_cache): Same. + (path_range_query::set_cache): Same. + (path_range_query::range_on_path_entry): Same. + (path_range_query::internal_range_of_expr): Same. + (path_range_query::range_of_expr): Same. + (path_range_query::ssa_range_in_phi): Same. + (path_range_query::range_defined_in_block): Same. + (path_range_query::compute_ranges_in_phis): Same. + (path_range_query::compute_ranges_in_block): Same. + (path_range_query::add_to_imports): Same. + (path_range_query::range_of_stmt): Same. + * gimple-range-path.h: Same. + * gimple-range-infer.cc (gimple_infer_range::add_range): Same. + (gimple_infer_range::~side_effect_manager): Same. + (gimple_infer_range::get_nonzero): Same. + (gimple_infer_range::maybe_adjust_range): Same. + (gimple_infer_range::add_range): Same. + * gimple-range-infer.h: Same. + * gimple-range-tests.cc: Same. + * gimple-range-trace.cc (range_tracer::trailer): Same. + (debug_seed_ranger): Same. + * gimple-range-trace.h: Same. + * gimple-range.cc (gimple_ranger::range_of_expr): Same. + (gimple_ranger::range_on_entry): Same. + (gimple_ranger::range_on_exit): Same. + (gimple_ranger::range_on_edge): Same. + (gimple_ranger::fold_range_internal): Same. + (gimple_ranger::range_of_stmt): Same. + (gimple_ranger::prefill_name): Same. + (gimple_ranger::prefill_stmt_dependencies): Same. + (gimple_ranger::export_global_ranges): Same. + (gimple_ranger::dump_bb): Same. + * gimple-range.h: Same. + * gimple-ssa-warn-access.cc (check_nul_terminated_array): Same. + (memmodel_to_uhwi): Same. + * tree-ssa-loop-niter.cc (refine_value_range_using_guard): Same. + (determine_value_range): Same. + (record_nonwrapping_iv): Same. + (infer_loop_bounds_from_signedness): Same. + (scev_var_range_cant_overflow): Same. + * tree-ssa-threadedge.cc (hybrid_jt_simplifier::simplify): Same. + * value-query.cc (range_query::range_on_edge): Same. + (range_query::range_of_stmt): Same. + (range_query::value_of_expr): Same. + (range_query::value_on_edge): Same. + (range_query::value_of_stmt): Same. + (range_query::get_tree_range): Same. + (update_global_range): Same. + (get_range_global): Same. + (gimple_range_global): Same. + (global_range_query::range_of_expr): Same. + (range_query::query_relation): Same. + * value-query.h (gimple_range_global): Same. + (update_global_range): Same. + * vr-values.cc (vr_values::range_of_expr): Same. + (bounds_of_var_in_loop): Same. + (simplify_using_ranges::vrp_visit_cond_stmt): Same. + * vr-values.h (class vr_values): Same. + * tree-ssa-loop-unswitch.cc (unswitch_predicate): Same. + +2022-06-01 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-cache.cc (sbr_vector::sbr_vector): Adjust for + vrange allocator. + (sbr_vector::grow): Same. + (sbr_vector::set_bb_range): Same. + (sbr_sparse_bitmap::sbr_sparse_bitmap): Same. + (sbr_sparse_bitmap::set_bb_range): Same. + (block_range_cache::~block_range_cache): Same. + (block_range_cache::set_bb_range): Same. + (ssa_global_cache::ssa_global_cache): Same. + (ssa_global_cache::~ssa_global_cache): Same. + (ssa_global_cache::set_global_range): Same. + * gimple-range-cache.h (block_range_cache): Same. + (ssa_global_cache): Same. + * gimple-range-edge.cc + (gimple_outgoing_range::calc_switch_ranges): Same. + * gimple-range-edge.h (gimple_outgoing_range): Same. + * gimple-range-infer.cc (infer_range_manager::get_nonzero): + Same. + (infer_range_manager::add_range): Same. + * gimple-range-infer.h (class infer_range_manager): Same. + * value-range.h (class irange_allocator): Rename to... + (class vrange_allocator): ...this. + (irange_allocator::irange_allocator): New. + (vrange_allocator::vrange_allocator): New. + (irange_allocator::~irange_allocator): New. + (vrange_allocator::~vrange_allocator): New. + (irange_allocator::get_memory): Rename to... + (vrange_allocator::alloc): ...this. + (vrange_allocator::alloc_vrange): Rename from... + (irange_allocator::allocate): ...this. + (vrange_allocator::alloc_irange): New. + +2022-06-01 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for + vrange and convert range_op_handler function calls to use the + identically named object. + * gimple-range-fold.cc (gimple_range_operand1): Same. + (gimple_range_operand2): Same. + (fold_using_range::fold_stmt): Same. + (fold_using_range::range_of_range_op): Same. + (fold_using_range::range_of_builtin_ubsan_call): Same. + (fold_using_range::relation_fold_and_or): Same. + (fur_source::register_outgoing_edges): Same. + * gimple-range-fold.h (gimple_range_handler): Remove. + * gimple-range-gori.cc (gimple_range_calc_op1): Adjust for vrange. + (gimple_range_calc_op2): Same. + (range_def_chain::get_def_chain): Same. + (gori_compute::compute_operand_range): Same. + (gori_compute::condexpr_adjust): Same. + * gimple-range.cc (gimple_ranger::prefill_name): Same. + (gimple_ranger::prefill_stmt_dependencies): Same. + * range-op.cc (get_bool_state): Same. + (class operator_equal): Add using clause. + (class operator_not_equal): Same. + (class operator_lt): Same. + (class operator_le): Same. + (class operator_gt): Same. + (class operator_ge): Same. + (class operator_plus): Same. + (class operator_minus): Same. + (class operator_mult): Same. + (class operator_exact_divide): Same. + (class operator_lshift): Same. + (class operator_rshift): Same. + (class operator_cast): Same. + (class operator_logical_and): Same. + (class operator_bitwise_and): Same. + (class operator_logical_or): Same. + (class operator_bitwise_or): Same. + (class operator_bitwise_xor): Same. + (class operator_trunc_mod): Same. + (class operator_logical_not): Same. + (class operator_bitwise_not): Same. + (class operator_cst): Same. + (class operator_identity): Same. + (class operator_unknown): Same. + (class operator_abs): Same. + (class operator_negate): Same. + (class operator_addr_expr): Same. + (class pointer_or_operator): Same. + (operator_plus::op1_range): Adjust for vrange. + (operator_minus::op1_range): Same. + (operator_mult::op1_range): Same. + (operator_cast::op1_range): Same. + (operator_bitwise_not::fold_range): Same. + (operator_negate::fold_range): Same. + (range_op_handler): Rename to... + (get_handler): ...this. + (range_op_handler::range_op_handler): New. + (range_op_handler::fold_range): New. + (range_op_handler::op1_range): New. + (range_op_handler::op2_range): New. + (range_op_handler::lhs_op1_relation): New. + (range_op_handler::lhs_op2_relation): New. + (range_op_handler::op1_op2_relation): New. + (range_cast): Adjust for vrange. + * range-op.h (range_op_handler): Remove function. + (range_cast): Adjust for vrange. + (class range_op_handler): New. + (get_bool_state): Adjust for vrange. + (empty_range_varying): Same. + (relop_early_resolve): Same. + * tree-data-ref.cc (compute_distributive_range): Same. + * tree-vrp.cc (get_range_op_handler): Remove. + (range_fold_binary_symbolics_p): Use range_op_handler class + instead of get_range_op_handler. + (range_fold_unary_symbolics_p): Same. + (range_fold_binary_expr): Same. + (range_fold_unary_expr): Same. + * value-query.cc (range_query::get_tree_range): Adjust for vrange. + +2022-06-01 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-fold.h (gimple_range_type): Check type before + calling supports_type_p. + * gimple-range-path.cc (path_range_query::range_of_stmt): Same. + * value-query.cc (range_query::get_tree_range): Same. + * value-range.cc (Value_Range::lower_bound): New. + (Value_Range::upper_bound): New. + (Value_Range::dump): New. + * value-range.h (class Value_Range): New. + (irange::supports_type_p): Do not check if type is non-zero. + +2022-06-01 Aldy Hernandez <aldyh@redhat.com> + + * value-range-equiv.cc (value_range_equiv::set): New. + * value-range-equiv.h (class value_range_equiv): Make set method + virtual. + Remove default bitmap argument from set method. + * value-range.cc (vrange::contains_p): New. + (vrange::singleton_p): New. + (vrange::operator=): New. + (vrange::operator==): New. + (irange::fits_p): Move to .cc file. + (irange::set_nonnegative): New. + (unsupported_range::unsupported_range): New. + (unsupported_range::set): New. + (unsupported_range::type): New. + (unsupported_range::set_undefined): New. + (unsupported_range::set_varying): New. + (unsupported_range::dump): New. + (unsupported_range::union_): New. + (unsupported_range::intersect): New. + (unsupported_range::zero_p): New. + (unsupported_range::nonzero_p): New. + (unsupported_range::set_nonzero): New. + (unsupported_range::set_zero): New. + (unsupported_range::set_nonnegative): New. + (unsupported_range::fits_p): New. + (irange::set): Call irange::set_undefined. + (irange::verify_range): Check discriminator field. + (irange::dump): Dump [irange] marker. + (irange::debug): Move to... + (vrange::debug): ...here. + (dump_value_range): Accept vrange. + (debug): Same. + * value-range.h (enum value_range_discriminator): New. + (class vrange): New. + (class unsupported_range): New. + (struct vrange_traits): New. + (is_a): New. + (as_a): New. + (class irange): Inherit from vrange. + (dump_value_range): Adjust for vrange. + (irange::kind): Rename to... + (vrange::kind): ...this. + (irange::varying_p): Rename to... + (vrange::varying_p): ...this. + (irange::undefined_p): Rename to... + (vrange::undefined_p): ...this. + (irange::irange): Set discriminator. + (irange::union_): Convert to irange before passing to irange + method. + (irange::intersect): Same. + (vrange::supports_type_p): New. + * vr-values.cc (vr_values::extract_range_from_binary_expr): Pass + NULL bitmap argument to value_range_equiv::set. + (vr_values::extract_range_basic): Same. + +2022-06-01 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105763 + * tree-ssa-loop-unswitch.cc (find_unswitching_predicates_for_bb): + Check gimple_range_ssa_p. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Makefile.in (TAGS): Look at libcpp/*.cc. + +2022-05-31 Christophe Lyon <christophe.lyon@arm.com> + + * config/aarch64/aarch64.cc (aarch64_gimplify_va_arg_expr): + Prefix mode names with E_. + +2022-05-31 Alan Modra <amodra@gmail.com> + + * dwarf2out.cc (gen_namelist_decl): Adjust to suit correct + spelling of DW_AT_namelist_item. + +2022-05-31 Jakub Jelinek <jakub@redhat.com> + + * omp-low.cc (build_outer_var_ref): For code == OMP_CLAUSE_ALLOCATE + allow var to be private in the outer context. + (lower_private_allocate): Pass OMP_CLAUSE_ALLOCATE as last argument + to build_outer_var_ref. + +2022-05-30 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386.cc (ix86_modes_tieable_p): Allow SCmode to be + tieable with DImode on TARGET_64BIT, and SCmode tieable with + V2SFmode, and DCmode with V2DFmode. + +2022-05-30 Roger Sayle <roger@nextmovesoftware.com> + + PR rtl-optimization/101617 + * config/i386/i386-expand.cc (ix86_expand_int_movcc): Add a + special case (indicated by negate_cc_compare_p) to generate a + -1/0 mask using neg;sbb. + * config/i386/i386.md (x86_neg<mode>_ccc): New define_expand + to generate an *x86_neg<mode>_ccc instruction. + (x86_mov<mode>cc_0_m1_neg): Likewise, a new define_expand to + generate a *x86_mov<mode>cc_0_m1_neg instruction. + +2022-05-30 Roger Sayle <roger@nextmovesoftware.com> + + * rtlanal.cc (rtx_cost) <MULT>: Treat FMA, SS_MULT, US_MULT, + SMUL_HIGHPART and UMUL_HIGHPART as having the same cost as MULT. + <DIV>: Likewise, SS_DIV and US_DIV have the same default as DIV. + +2022-05-30 Roger Sayle <roger@nextmovesoftware.com> + + PR target/70321 + * config/i386/i386-expand.cc (ix86_expand_branch): Don't decompose + DI mode equality/inequality using XOR here. Instead generate a + COMPARE for doubleword modes (DImode on !TARGET_64BIT or TImode). + * config/i386/i386-features.cc (gen_gpr_to_xmm_move_src): Use + gen_rtx_SUBREG when NUNITS is 1, i.e. for TImode to V1TImode. + (general_scalar_chain::convert_compare): New function to convert + scalar equality/inequality comparison into vector operations. + (general_scalar_chain::convert_insn) [COMPARE]: Refactor. Call + new convert_compare helper method. + (convertible_comparion_p): Update to match doubleword COMPARE + of two register, memory or integer constant operands. + * config/i386/i386-features.h (general_scalar_chain::convert_compare): + Prototype/declare member function here. + * config/i386/i386.md (cstore<mode>4): Change mode to SDWIM, but + only allow new doubleword modes for EQ and NE operators. + (*cmp<dwi>_doubleword): New define_insn_and_split, to split a + doubleword comparison into a pair of XORs followed by an IOR to + set the (zero) flags register, optimizing the XORs if possible. + * config/i386/sse.md (V_AVX): Include V1TI and V2TI in mode + iterator; V_AVX is (currently) only used by ptest. + (sse4_1 mode attribute): Update to support V1TI and V2TI. + +2022-05-30 Uroš Bizjak <ubizjak@gmail.com> + + * config/i386/i386.md: Remove constraints when used with + const_int_operand, const0_operand, const_1_operand, constm1_operand, + const8_operand, const128_operand, const248_operand, const123_operand, + const2367_operand, const1248_operand, const359_operand, + const_4_or_8_to_11_operand, const48_operand, const_0_to_1_operand, + const_0_to_3_operand, const_0_to_4_operand, const_0_to_5_operand, + const_0_to_7_operand, const_0_to_15_operand, const_0_to_31_operand, + const_0_to_63_operand, const_0_to_127_operand, const_0_to_255_operand, + const_0_to_255_mul_8_operand, const_1_to_31_operand, + const_1_to_63_operand, const_2_to_3_operand, const_4_to_5_operand, + const_4_to_7_operand, const_6_to_7_operand, const_8_to_9_operand, + const_8_to_11_operand, const_8_to_15_operand, const_10_to_11_operand, + const_12_to_13_operand, const_12_to_15_operand, const_14_to_15_operand, + const_16_to_19_operand, const_16_to_31_operand, const_20_to_23_operand, + const_24_to_27_operand and const_28_to_31_operand. + * config/i386/mmx.md: Ditto. + * config/i386/sse.md: Ditto. + * config/i386/subst.md: Ditto. + * config/i386/sync.md: Ditto. + +2022-05-30 Jan Beulich <jbeulich@suse.com> + + * config/i386/i386.md (bmi2_umul<mode><dwi>3_1): Correct MEM_P() + arguments. + +2022-05-30 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org> + + * config/arm/arm.cc (arm_vectorize_vec_perm_const): Adjust prototype. + 2022-05-29 Iain Sandoe <iain@sandoe.co.uk> PR target/105599 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 158b96c..626ce17 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220530 +20220606 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 731d8dd..eea996c 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -499,6 +499,7 @@ RANLIB_FOR_TARGET := $(shell \ ORIGINAL_LD_FOR_TARGET = @ORIGINAL_LD_FOR_TARGET@ ORIGINAL_NM_FOR_TARGET = @ORIGINAL_NM_FOR_TARGET@ NM_FOR_TARGET = ./nm +ORIGINAL_OBJCOPY_FOR_TARGET = @ORIGINAL_OBJCOPY_FOR_TARGET@ STRIP_FOR_TARGET := $(shell \ if [ -f $(objdir)/../binutils/strip-new ] ; then \ echo $(objdir)/../binutils/strip-new ; \ @@ -1617,6 +1618,7 @@ OBJS = \ tree-data-ref.o \ tree-dfa.o \ tree-diagnostic.o \ + tree-diagnostic-client-data-hooks.o \ tree-diagnostic-path.o \ tree-dump.o \ tree-eh.o \ @@ -1625,6 +1627,7 @@ OBJS = \ tree-inline.o \ tree-into-ssa.o \ tree-iterator.o \ + tree-logical-location.o \ tree-loop-distribution.o \ tree-nested.o \ tree-nrv.o \ @@ -1728,9 +1731,12 @@ OBJS = \ # Objects in libcommon.a, potentially used by all host binaries and with # no target dependencies. OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \ - diagnostic-show-locus.o diagnostic-format-json.o json.o \ + diagnostic-format-json.o \ + diagnostic-format-sarif.o \ + diagnostic-show-locus.o \ edit-context.o \ pretty-print.o intl.o \ + json.o \ sbitmap.o \ vec.o input.o hash-table.o ggc-none.o memory-block.o \ selftest.o selftest-diagnostic.o sort.o @@ -2368,6 +2374,7 @@ s-bversion: BASE-VER $(STAMP) s-bversion CFLAGS-toplev.o += -DTARGET_NAME=\"$(target_noncanonical)\" +CFLAGS-tree-diagnostic-client-data-hooks.o += -DTARGET_NAME=\"$(target_noncanonical)\" CFLAGS-optinfo-emit-json.o += -DTARGET_NAME=\"$(target_noncanonical)\" $(ZLIBINC) CFLAGS-analyzer/engine.o += $(ZLIBINC) @@ -4338,10 +4345,10 @@ TAGS: lang.tags incs="$$incs --include $$dir/TAGS.sub"; \ fi; \ done; \ - $(ETAGS) -o TAGS.sub c-family/*.h c-family/*.cc c-family/*.cc \ - *.h *.c *.cc \ + $(ETAGS) -o TAGS.sub c-family/*.h c-family/*.cc \ + *.h *.cc \ ../include/*.h ../libiberty/*.c \ - ../libcpp/*.c ../libcpp/include/*.h \ + ../libcpp/*.cc ../libcpp/include/*.h \ --language=none --regex="/\(char\|unsigned int\|int\|bool\|void\|HOST_WIDE_INT\|enum [A-Za-z_0-9]+\) [*]?\([A-Za-z_0-9]+\)/\2/" common.opt \ --language=none --regex="/\(DEF_RTL_EXPR\|DEFTREECODE\|DEFGSCODE\|DEFTIMEVAR\|DEFPARAM\|DEFPARAMENUM5\)[ ]?(\([A-Za-z_0-9]+\)/\2/" rtl.def tree.def gimple.def timevar.def \ ; \ diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 1e578c1..1434ebe 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,782 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * gcc-interface/misc.cc (gnat_get_sarif_source_language): New. + (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + +2022-06-02 Pierre-Marie de Rodat <derodat@adacore.com> + + * gcc-interface/gigi.h: Update copyright notice. + * gcc-interface/lang-specs.h: Likewise. + * gcc-interface/utils.cc: Likewise. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/gigi.h (enum standard_datatypes): Remove values + for the SJLJ exception mechanism. + (jmpbuf_type): Delete. + (jmpbuf_ptr_type): Likewise. + (get_jmpbuf_decl): Likewise. + (set_jmpbuf_decl): Likewise. + (get_excptr_decl): Likewise. + (not_handled_by_others_decl): Likewise. + (setjmp_decl): Likewise. + (update_setjmp_buf_decl): Likewise. + (raise_nodefer_decl): Likewise. + (set_block_jmpbuf_decl): Likewise. + (get_block_jmpbuf_decl): Likewise. + * gcc-interface/trans.cc (gigi): Delete dead code. + * gcc-interface/utils.cc (gnat_binding_level): Remove JMPBUF_DECL. + (gnat_pushlevel): Do not clear it. + (set_block_jmpbuf_decl): Delete. + (get_block_jmpbuf_decl): Likewise. + +2022-06-02 Ghjuvan Lacambre <lacambre@adacore.com> + + * gcc-interface/decl.cc (warn_on_field_placement): Add insertion + character '.q' to warning string. + +2022-06-02 Arnaud Charlet <charlet@adacore.com> + + * gcc-interface/Makefile.in (gnatlib-shared-default): Add + -fno-lto. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/decl.cc (gnat_to_gnu_entity): Do not check the + scope of anonymous access Itypes. + * gcc-interface/trans.cc (Identifier_to_gnu): Do not translate + the return type of a subprogram here. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch7.adb (Expand_N_Package_Body): Build static dispatch + tables only for units that are not compilation units, unless + they are generic instances. Do not push a scope for this. + (Expand_N_Package_Declaration): Build static dispatch tables + only for units that are both not compilation units and generic + instances. + * exp_disp.adb (Build_Static_Dispatch_Tables): Remove redundant + early return. Push a scope for package bodies. + * sem_ch10.adb: Add with and use clauses for Exp_Disp. + (Analyze_Compilation_Unit): Build static dispatch tables here. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * sem_ch6.adb (Analyze_Subprogram_Body_Helper): Clear the Is_Public + flag on thunks. + +2022-06-02 Piotr Trojanek <trojanek@adacore.com> + + * exp_ch13.adb, exp_ch5.adb, exp_ch9.adb, exp_strm.adb, + sem_ch10.adb, sem_ch13.adb, sem_ch5.adb, sem_ch6.adb, + sem_ch8.adb, sem_elab.adb, sem_eval.adb, sem_prag.adb, + sem_util.adb: Remove checks for the missing list before + iterating with First/Next; reindent code and refill comments. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * einfo.ads (Has_Controlling_Result): Document new usage. + (Is_Thunk): Document secondary stack thunks. + (Returns_By_Ref): Adjust. + * exp_ch6.adb (Caller_Known_Size): Return true for tagged types. + (Expand_N_Extended_Return_Statement): Do not call Set_By_Ref. + (Expand_Simple_Function_Return): For a BIP return with an Alloc_Form + parameter, mark the node as returning on the secondary stack. + Replace call to Is_Limited_Interface with Is_Limited_View. Deal wit + secondary stack thunks. Do not call Set_By_Ref. Optimize the case + of a call to a function whose type also needs finalization. + (Needs_BIP_Task_Actuals): Replace Thunk_Entity with Thunk_Target. + (Needs_BIP_Finalization_Master): Cosmetic fixes. + (Needs_BIP_Alloc_Form): Check No_Secondary_Stack restriction and + return true for tagged types. + * exp_ch7.adb (Transient Scope Management): Update description. + * exp_disp.adb (Expand_Dispatching_Call): Always set Returns_By_Ref + on designated type if the call is dispatching on result. Tidy up. + (Expand_Interface_Thunk): Change type of Thunk_Code from Node_Id to + List_Id. Change type of local variables from Node_Id to Entity_Id. + Propagate Aliased_Present flag to create the formals and explicitly + set Has_Controlling_Result to False. Build a secondary stack thunk + if necessary in the function case. + (Expand_Secondary_Stack_Thunk): New function. + (Make_Secondary_DT): Build secondary stack thunks if necessary. + (Make_DT): Likewise. + (Register_Predefined_Primitive): Likewise. + (Register_Primitive): Likewise. + * exp_util.ads (Is_Secondary_Stack_Thunk): Declare. + (Thunk_Target): Likewise. + * exp_util.adb (Is_Secondary_Stack_Thunk): New function. + (Thunk_Target): Likewise. + * fe.h (Is_Secondary_Stack_Thunk): Declare. + (Thunk_Target): Likewise. + * gen_il-fields.ads (Opt_Field_Enum): Remove By_Ref. + * gen_il-gen-gen_nodes.adb (N_Simple_Return_Statement): Likewise. + (N_Extended_Return_Statement): Likewise. + * sem_ch6.adb (Analyze_Subprogram_Specification): Skip check for + abstract return type in the thunk case. + (Create_Extra_Formals): Replace Thunk_Entity with Thunk_Target. + * sem_disp.adb (Check_Controlling_Formals): Skip in the thunk case. + * sem_util.adb: Add use and with clauses for Exp_Ch6. + (Compute_Returns_By_Ref): Do not process procedures and only set + the flag for direct return by reference. + (Needs_Secondary_Stack): Do not return true for specific tagged + types and adjust comments accordingly. + * sinfo.ads (By_Ref): Delete. + (N_Simple_Return_Statement): Remove By_Ref. + (N_Extended_Return_Statement): Likewise. + * gcc-interface/ada-tree.h (TYPE_RETURN_UNCONSTRAINED_P): Delete. + * gcc-interface/decl.cc (gnat_to_gnu_subprog_type): Do not use it. + Return by direct reference if the return type needs the secondary + stack as well as for secondary stack thunks. + * gcc-interface/gigi.h (fntype_same_flags_p): Remove parameter. + * gcc-interface/misc.cc (gnat_type_hash_eq): Adjust to above change. + * gcc-interface/trans.cc (finalize_nrv): Replace test on + TYPE_RETURN_UNCONSTRAINED_P with TYPE_RETURN_BY_DIRECT_REF_P. + (Subprogram_Body_to_gnu): Do not call maybe_make_gnu_thunk for + secondary stack thunks. + (Call_to_gnu): Do not test TYPE_RETURN_UNCONSTRAINED_P. + (gnat_to_gnu) <N_Simple_Return_Statement>: In the return by direct + reference case, test for the presence of Storage_Pool on the node + to build an allocator. + (maybe_make_gnu_thunk): Deal with Thunk_Entity and Thunk_Target. + * gcc-interface/utils.cc (fntype_same_flags_p): Remove parameter. + +2022-06-02 Marc Poulhiès <poulhies@adacore.com> + + * einfo.ads: Fix reference to Global_Entity_Suppress and + Local_Entity_Suppress variable in the comments. + * sem.ads: Likewise. + * sem_prag.adb: Likewise. + +2022-06-02 Claire Dross <dross@adacore.com> + + * libgnat/s-aridou.adb: Use Always_Return instead of Terminating + to annotate termination for GNATprove. + * libgnat/s-arit32.adb: Idem. + * libgnat/s-spcuop.ads: Idem. + +2022-06-02 Julien Bortolussi <bortolussi@adacore.com> + + * libgnat/a-cofuse.ads, libgnat/a-cofuse.adb, + libgnat/a-cofuma.ads, libgnat/a-cofuma.adb: Make Length and + Num_Overlaps return Big_Natural. + * libgnat/a-cforse.ads, libgnat/a-cforse.adb, + libgnat/a-cforma.adb, libgnat/a-cfhase.ads, + libgnat/a-cfhase.adb, libgnat/a-cfhama.adb, + libgnat/a-cfdlli.adb: Adapt code to handle Big_Integers instead + of Count_Type. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch3.adb (Init_Secondary_Tags.Initialize_Tag): Initialize the + Offset_Func component by means of 'Unrestricted_Access. + +2022-06-02 Ghjuvan Lacambre <lacambre@adacore.com> + + * errout.adb (Write_JSON_Span): Add subprogram name to emitted + JSON. + +2022-06-02 Arnaud Charlet <charlet@adacore.com> + + * sem_ch7.adb (Set_Referencer_Of_Non_Subprograms): New local + procedure, used for code refactoring. Also take into account + Inline_Always pragma when deciding to make a symbol public for + C generation. + +2022-06-02 Yannick Moy <moy@adacore.com> + + * atree.adb (New_Copy): Reset flags related to ghost entities + before marking the new node. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch6.adb (Freeze_Subprogram.Register_Predefined_DT_Entry): Move + procedure to... + * exp_disp.ads (Expand_Interface_Thunk): Move declaration to... + (Register_Predefined_Primitive): Declare. + * exp_disp.adb (Expand_Interface_Thunk): ...here. + (Register_Predefined_Primitive): ...here and change into a function + returning List_Id. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch3.adb (Expand_Freeze_Record_Type): Adjust comment. + (Expand_N_Object_Declaration): Do not build static dispatch tables. + * exp_disp.adb (Make_And_Insert_Dispatch_Table): New procedure. + (Build_Static_Dispatch_Tables): Call it to build the dispatch tables + and wrap them in the Actions list of a freeze node. + +2022-06-02 Doug Rupp <rupp@adacore.com> + + * libgnat/system-vxworks7-arm.ads (Support_Atomic_Primitives): + Set True. + * libgnat/system-vxworks7-arm-rtp-smp.ads: Likewise. + * libgnat/system-vxworks7-aarch64.ads: Likewise. + * libgnat/system-vxworks7-aarch64-rtp-smp.ads: Likewise: + +2022-06-02 Javier Miranda <miranda@adacore.com> + + * libgnat/g-dyntab.ads (Table_Type): Update documentation. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * freeze.adb (Check_Expression_Function.Find_Constant): Make test + for deferred constants more robust. + +2022-06-02 Joffrey Huguet <huguet@adacore.com> + + * libgnat/i-cstrin.ads (Update): Update precondition. + +2022-06-02 Yannick Moy <moy@adacore.com> + + * sem_ch2.adb (Analyze_Identifier): Add checking for ghost + context. + * sem_ch5.adb (Analyze_Implicit_Label_Declaration): Treat + implicit labels like other entities by setting their ghost + status according to context. + * ghost.adb (Check_Ghost_Context): Adapt checking. + +2022-06-02 Joffrey Huguet <huguet@adacore.com> + + * libgnat/i-cstrin.ads (Update): Add precondition. + +2022-06-02 Yannick Moy <moy@adacore.com> + + * sem_ch5.adb (Analyze_Label_Entity): Remove body. + * sem_ch5.ads (Analyze_Label_Entity): Remove spec. + +2022-06-02 Eric Botcazou <ebotcazou@adacore.com> + + * sem_util.adb (Propagate_DIC_Attributes): Add ??? comment. + (Propagate_Invariant_Attributes): Likewise. Propagate the + Has_Inheritable_Invariants and Has_Inherited_Invariants to + the base type of the target type. + +2022-06-02 Doug Rupp <rupp@adacore.com> + + * libgnat/system-linux-arm.ads (Memory_Size): Compute based on + Word_Size. + +2022-06-02 Doug Rupp <rupp@adacore.com> + + * libgnat/system-vxworks7-aarch64-rtp-smp.ads (Word_Size): + Compute based on Standard'Word_Size. (Memory_Size): Compute + based on Word_Size. + * libgnat/system-vxworks7-arm-rtp-smp.ads: Likewise. + * libgnat/system-vxworks7-e500-rtp-smp.ads: Likewise. + * libgnat/system-vxworks7-e500-rtp.ads: Likewise. + * libgnat/system-vxworks7-ppc-rtp-smp.ads: Likewise. + * libgnat/system-vxworks7-ppc-rtp.ads: Likewise. + * libgnat/system-vxworks7-ppc64-rtp-smp.ads: Likewise. + * libgnat/system-vxworks7-x86-rtp-smp.ads: Likewise. + * libgnat/system-vxworks7-x86-rtp.ads: Likewise. + +2022-06-02 Justin Squirek <squirek@adacore.com> + + * gnatbind.adb (Gnatbind): Add initialize call for Uintp + * gnatls.adb (Gnatls): Likewise. + * gprep.adb (Gnatprep): Likewise. + * make.adb (Initialize): Likewise. + +2022-06-02 Claire Dross <dross@adacore.com> + + * libgnat/a-cfinve.ads (Element): Change the type of the + Position parameter to Extended_Index. + * libgnat/a-cfinve.adb (Element): Idem. + * libgnat/a-cofove.ads (Element): Idem. + * libgnat/a-cofove.adb (Element): Idem. + +2022-06-02 Joffrey Huguet <huguet@adacore.com> + + * libgnat/s-atacco.ads (To_Pointer): Add Global => null. + (To_Address): Add SPARK_Mode => Off. + +2022-06-02 Joffrey Huguet <huguet@adacore.com> + + * libgnat/i-cstrin.ads (To_Chars_Ptr): Add SPARK_Mode => Off. + (Free): Likewise. + (New_Char_Array): Add global contracts and Volatile attribute. + (New_String): Likewise. + (Value, Strlen, Update): Add global contracts and preconditions. + * libgnat/i-cstrin.adb: Add SPARK_Mode => Off to the package + body. + +2022-06-01 Yannick Moy <moy@adacore.com> + + * contracts.adb (Check_Type_Or_Object_External_Properties): Check + the validity of combinations only when No_Caching is not used. + * sem_prag.adb (Analyze_External_Property_In_Decl_Part): Check + valid combinations with No_Caching. + +2022-06-01 Doug Rupp <rupp@adacore.com> + + * libgnat/system-vxworks7-aarch64.ads (Word_Size): Compute + based on Standard'Word_Size. (Memory_Size): Compute based + on Word_Size. + * libgnat/system-vxworks7-arm.ads: Likewise. + * libgnat/system-vxworks7-e500-kernel.ads: Likewise. + * libgnat/system-vxworks7-ppc-kernel.ads: Likewise. + * libgnat/system-vxworks7-ppc64-kernel.ads: Likewise. + * libgnat/system-vxworks7-x86-kernel.ads: Likewise. + * libgnat/system-vxworks7-x86_64-kernel.ads: Likewise. + +2022-06-01 Doug Rupp <rupp@adacore.com> + + * libgnat/system-qnx-arm.ads (Memory_Size): Compute based on + Word_Size. + +2022-06-01 Piotr Trojanek <trojanek@adacore.com> + + * par-util.adb (Ignore): Add missing space to message string. + +2022-06-01 Yannick Moy <moy@adacore.com> + + * sem_prag.ads (Assertion_Expression_Pragmas): Fix value for + pragma Subprogram_Variant. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch6.adb (Caller_Known_Size): Invoke Needs_Secondary_Stack in + lieu of Returns_On_Secondary_Stack. + (Expand_Call_Helper): Likewise. + (Expand_Simple_Function_Return): Likewise. + (Needs_BIP_Alloc_Form): Likewise. + * exp_ch7.adb (Wrap_Transient_Declaration): Likewise. + * sem_res.adb (Resolve_Call): Likewise. + (Resolve_Entry_Call): Likewise. + * sem_util.ads (Returns_On_Secondary_Stack): Rename into... + (Needs_Secondary_Stack): ...this. + * sem_util.adb (Returns_On_Secondary_Stack): Rename into... + (Needs_Secondary_Stack): ...this. + * fe.h (Returns_On_Secondary_Stack): Delete. + (Needs_Secondary_Stack): New function. + * gcc-interface/decl.cc (gnat_to_gnu_subprog_type): Replace call + to Returns_On_Secondary_Stack with Needs_Secondary_Stack. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * sem_ch6.adb (Analyze_Subprogram_Body_Helper): For the case where + there is no previous declaration, freeze the body entity only after + it has been processed as a new overloaded name. + Use Was_Expression_Function to recognize expression functions. + * sem_disp.adb (Check_Dispatching_Operation): Do not require a body + which is the last primitive to be frozen here. + +2022-06-01 Julien Bortolussi <bortolussi@adacore.com> + + * libgnat/a-cfdlli.adb ("="): Make the function properly loop + over the right list. + +2022-06-01 Marc Poulhiès <poulhies@adacore.com> + + * checks.adb (Apply_Predicate_Check): Refine condition for + applying optimization. + * sem_ch3.adb (Analyze_Component_Declaration): Adjust calls to + Should_Build_Subtype. + (Analyze_Object_Declaration): Likewise. + (Should_Build_Subtype): Rename/move to ... + * sem_util.ads (Build_Default_Subtype_OK): ... this. + * sem_util.adb (Build_Default_Subtype_OK): Moved from + sem_ch3.adb. + +2022-06-01 Doug Rupp <rupp@adacore.com> + + * init.c (__gnat_adjust_context_for_raise) [QNX][__thumb2__]: Bump + the pc an extra byte. + +2022-06-01 Ghjuvan Lacambre <lacambre@adacore.com> + + * doc/gnat_ugn/building_executable_programs_with_gnat.rst: + Document new behavior. + * errout.adb (Write_JSON_Location): Output absolute paths when + needed. + * switch-c.adb (Scan_Front_End_Switches): Update -gnatef + comment. + * usage.adb (Usage): Update description of -gnatef. + * gnat_ugn.texi: Regenerate. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * contracts.adb (Build_Postconditions_Procedure): Set Is_Inlined + unconditionnally on the procedure entity. + +2022-06-01 Piotr Trojanek <trojanek@adacore.com> + + * sem_ch3.adb (Constrain_Access): Propagate null-exclusion flag + from parent type. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * sem_ch5.adb (Analyze_Loop_Statement): Add a comment about + a finalization issue. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch6.adb (Caller_Known_Size): Call Returns_On_Secondary_Stack + instead of Requires_Transient_Scope and tidy up. + (Needs_BIP_Alloc_Form): Likewise. + * exp_util.adb (Initialized_By_Aliased_BIP_Func_Call): Also return + true if the build-in-place function call has no BIPalloc parameter. + (Is_Finalizable_Transient): Remove redundant test. + +2022-06-01 Alexandre Oliva <oliva@adacore.com> + + * doc/gnat_rm/security_hardening_features.rst: Note that hardening + features are experimental. + * gnat_rm.texi: Regenerate. + +2022-06-01 Steve Baird <baird@adacore.com> + + * exp_ch3.adb (Make_Controlling_Function_Wrappers): Set the + Corresponding_Spec field of a wrapper subprogram body before + analyzing the subprogram body; the field will be set (again) + during analysis, but we need it to be set earlier. + * exp_ch13.adb (Expand_N_Freeze_Entity): Add wrapper subprogram + bodies to the list of declarations for which we do not want to + suppress checks. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * sem_util.adb (Indirect_Temp_Needed): Adjust reference in comment. + +2022-06-01 Doug Rupp <rupp@adacore.com> + + * Makefile.rtl (GNATLIB_SHARED): Revert disablement for arm-qnx. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * sem_util.adb + (Returns_On_Secondary_Stack.Caller_Known_Size_Record): Directly + check the dependence on discriminants for the variant part, if + any, instead of calling the Is_Definite_Subtype predicate. + +2022-06-01 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_warn.adb (Warn_On_Unreferenced_Entity): Fix warning tag. + +2022-06-01 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_warn.adb (Check_References): Adjust conditions under which + warning messages should be emitted and their tags as well. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * exp_disp.ads (Expand_Interface_Thunk): Change type of Prim. + * exp_disp.adb (Expand_Interface_Thunk): Declare Is_Predef_Op + earlier, do not initialize Iface_Formal, use No idiom and tweaks + comments. + (Register_Primitive): Declare L earlier and tweak comments. + * sem_disp.adb (Check_Dispatching_Operation): Move tests out of + loop. + +2022-06-01 Steve Baird <baird@adacore.com> + + * exp_ch3.ads: Replace visible Build_Discr_Checking_Funcs (which + did not need to be visible - it was not referenced outside this + package) with Build_Or_Copy_Discr_Checking_Funcs. + * exp_ch3.adb: Refactor existing code into 3 procedures - + Build_Discr_Checking_Funcs, Copy_Discr_Checking_Funcs, and + Build_Or_Copy_Discr_Checking_Funcs. This refactoring is intended + to be semantics-preserving. + * exp_ch4.adb (Expand_N_Selected_Component): Detect case where a + call should be generated to the Discriminant_Checking_Func for + the component in question, but that subprogram does not yet + exist. + * sem_ch13.adb (Freeze_Entity_Checks): Immediately before + calling Build_Predicate_Function, add a call to + Exp_Ch3.Build_Or_Copy_Discr_Checking_Funcs in order to ensure + that Discriminant_Checking_Func attributes are already set when + Build_Predicate_Function is called. + * sem_ch6.adb (Analyze_Expression_Function): If the expression + of a static expression function has been transformed into an + N_Raise_xxx_Error node, then we need to copy the original + expression in order to check the requirement that the expression + must be a potentially static expression. We also want to set + aside a copy the untransformed expression for later use in + checking calls to the expression function via + Inline_Static_Function_Call. So introduce a new function, + Make_Expr_Copy, for use in these situations. + * sem_res.adb (Preanalyze_And_Resolve): When analyzing certain + expressions (e.g., a default parameter expression in a + subprogram declaration) we want to suppress checks. However, we + do not want to suppress checks for the expression of an + expression function. + +2022-06-01 Bob Duff <duff@adacore.com> + + * exp_ch5.adb (Expand_Iterator_Loop_Over_Container): For each + subprogram found, assert that the variable is Empty, so we can + detect bugs where we find two or more things with the same name. + Without this patch, that bug would happen when we add the new + Next procedure. For Step, make sure we pick the right one, by + checking name and number of parameters. For Get_Element_Access, + check that we're picking a function. That's not really + necessary, because there is no procedure with that name, but it + seems cleaner this way. + * rtsfind.ads: Minor comment improvement. It seems kind of odd + to say "under no circumstances", and then immediately contradict + that with "The one exception is...". + +2022-06-01 Doug Rupp <rupp@adacore.com> + + * init.c (QNX): __gnat_adjust_context_for_raise: New + implementation for arm-qnx. + +2022-06-01 Julien Bortolussi <bortolussi@adacore.com> + + * libgnat/a-cofuba.ads, libgnat/a-cofuba.adb: Add reference + counting. + +2022-06-01 Yannick Moy <moy@adacore.com> + + * sem_ch8.adb (Use_One_Package): Possibly warn. + * sem_util.adb (Enter_Name): Factor out warning on hidden entity. + (Warn_On_Hiding_Entity): Extract warning logic from Enter_Name and + generalize it to be applied also on use_clause. + * sem_util.ads (Warn_On_Hiding_Entity): Add new procedure. + +2022-06-01 Yannick Moy <moy@adacore.com> + + * par-ch3.adb (P_Known_Discriminant_Part_Opt): Reword error + message to benefit from existing codefix. + (P_Record_Definition): Detect out-of-order keywords in record + definition and issue appropriate messages. Other cases are + already caught at appropriate places. + +2022-06-01 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch6.adb (Freeze_Subprogram.Register_Predefined_DT_Entry): Put + the actions into the Actions field of the freeze node instead of + inserting them after it. + +2022-06-01 Marc Poulhiès <poulhies@adacore.com> + + * sinfo.ads: Add inline documention for Is_Parenthesis_Aggregate + and Is_Enum_Array_Aggregate. + +2022-06-01 Bob Duff <duff@adacore.com> + + * einfo-utils.adb (Set_Convention): Call Set_Convention + recursively, so that Set_Can_Use_Internal_Rep is called (if + appropriate) on the anonymous access type of the object, and its + designated subprogram type. + * sem_ch3.adb (Access_Definition): Remove redundant call to + Set_Can_Use_Internal_Rep. + +2022-06-01 Bob Duff <duff@adacore.com> + + * exp_ch4.adb (Expand_N_In): Do not warn in the above-mentioned + cases. + * fe.h (Assume_No_Invalid_Values): Remove from fe.h, because + this is not used in gigi. + * opt.ads (Assume_No_Invalid_Values): Improve the comment. We + don't need to "clearly prove"; we can just "prove". Remove the + comment about fe.h, which is no longer true. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * erroutc.adb (Get_Warning_Option): Don't consider `?` as a + valid option switch. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * erroutc.ads (Get_Warning_Option): New function returning the + option responsible for a warning if it exists. + * erroutc.adb (Get_Warning_Option): Likewise. + (Get_Warning_Tag): Rely on Get_Warning_Option when possible. + * errout.adb (Output_JSON_Message): Emit option field. + +2022-05-30 Julien Bortolussi <bortolussi@adacore.com> + + * libgnat/a-cfdlli.ads (Insert): Remove the duplication. + +2022-05-30 Piotr Trojanek <trojanek@adacore.com> + + * exp_ch6.adb (Check_Subprogram_Variant): Ignore structural + variants. + +2022-05-30 Piotr Trojanek <trojanek@adacore.com> + + * osint.adb (Locate_File): Change variable to constant and + initialize it by concatenation of directory, file name and NUL. + +2022-05-30 Piotr Trojanek <trojanek@adacore.com> + + * doc/gnat_rm/implementation_advice.rst (Packed Types): Remove + duplicated and wrongly placed paragraph. + * gnat_rm.texi: Regenerate. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * inline.adb (Check_Package_Body_For_Inlining): Add insertion + character. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * freeze.adb (Warn_Overlay): Add 'o' insertion character. + * sem_ch13.adb (Analyze_Attribute_Definition_Clause): Likewise. + * sem_util.adb (Note_Possible_Modifications): Likewise. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_warn.adb (Warn_On_Useless_Assignment): Fix insertion + character. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_disp.adb (Warn_On_Late_Primitive_After_Private_Extension): + Fix insertion character. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * sem_elab.adb (Process_Conditional_ABE_Access_Taken): Add '.f' + insertion characters. + +2022-05-30 Piotr Trojanek <trojanek@adacore.com> + + * lib-xref.ads (Deferred_Reference_Entry, Defer_Reference, + Process_Deferred_References, Has_Deferred_Reference): Remove + client API. + * lib-xref.adb (Deferred_References, Defer_Reference, + Has_Deferred_Reference, Process_Deferred_References): Remove + implementation. + * frontend.adb, sem_ch11.adb, sem_ch5.adb, sem_res.adb, + sem_util.adb, sem_warn.adb: Remove uses of Deferred_References. + +2022-05-30 Bob Duff <duff@adacore.com> + + * exp_ch7.adb (Wrap_HSS_In_Block): Do not create a new block in + the case of function bodies. We include all subprogram bodies, + because it's harmless for procedures. We cannot easily avoid + creating this block in ALL cases, because some transformations + of (e.g.) task bodies end up moving some code such that the + wrong exception handlers apply to that code. + (Build_Finalizer_Call): Remove code for creating a new block. + This was unreachable code, given that Wrap_HSS_In_Block has + already done that, but with the above change to + Wrap_HSS_In_Block, this code becomes reachable, and triggers + essentially the same bug. + * exp_ch7.ads: Adjust comment. + +2022-05-30 Justin Squirek <squirek@adacore.com> + + * par-ch6.adb (P_Formal_Part): Set Aspect_Specifications on all + formals instead of just the last in a formal id list. + * sem_ch6.adb (Analyze_Null_Procedure): Mark expanded null + generic procedures as trivial in order to avoid spurious + unreferenced warnings. + +2022-05-30 Romain Beguet <beguet@adacore.com> + + * libgnat/s-dwalin.adb: Add a subtype declaration to fix the + ambiguity. + +2022-05-30 Steve Baird <baird@adacore.com> + + * sem_ch13.adb (Is_Predicate_Static): Do not generate warnings + about subexpressions of enclosing expressions. Generate warnings + for predicates that are known to be always true or always false, + except in the case where the predicate is expressed as a Boolean + literal. Deal with non-predicate-static expressions that have + been transformed into predicate-static expressions. Add missing + Is_Type_Ref call to N_Membership_Test case. + +2022-05-30 Eric Botcazou <ebotcazou@adacore.com> + + * exp_aggr.adb (Expand_Record_Aggregate.Build_Back_End_Aggregate): + Skip the discriminants at the start of the component list before + looking for the components inherited from the parent in the case + of a tagged extension. + +2022-05-30 Eric Botcazou <ebotcazou@adacore.com> + + * exp_disp.adb (Make_DT): Remove remaining freezing code. + +2022-05-30 Eric Botcazou <ebotcazou@adacore.com> + + * sem_attr.adb (Resolve_Attribute) <Attribute_Access>: Don't analyze + the body of an expression function in the case of a dispatch table. + +2022-05-30 Arnaud Charlet <charlet@adacore.com> + + * gnat1drv.adb, opt.ads, sem_ch7.adb: Introduce CCG_Mode. + +2022-05-30 Yannick Moy <moy@adacore.com> + + * Makefile.rtl: Add new units. + * libgnat/s-aridou.adb (Scaled_Divide): Add ghost code for provers. + * libgnat/s-spcuop.adb: New unit for ghost cut operations. + * libgnat/s-spcuop.ads: New unit for ghost cut operations. + * libgnat/s-spark.ads: New unit. + +2022-05-30 Alexandre Oliva <oliva@adacore.com> + + * doc/gnat_rm/security_hardening_features.rst: Mention + availability in other languages when applicable. + (Stack Scrubbing): Associate the attribute with types, expand + some comments, fix the example involving access to variables. + * gnat_rm.texi: Regenerate. + +2022-05-30 Piotr Trojanek <trojanek@adacore.com> + + * libgnat/a-cofuse.ads (Empty_Set): Fix typo in comment. + +2022-05-30 Eric Botcazou <ebotcazou@adacore.com> + + * sem_ch6.adb (New_Overloaded_Entity): Deal specifically with the + overriding of the "=" operator for tagged types. + +2022-05-30 Eric Botcazou <ebotcazou@adacore.com> + + * exp_ch3.adb (Expand_N_Object_Declaration): Adjust call to Make_DT. + * exp_disp.ads (Building_Static_DT): Remove pragma Inline. + (Building_Static_Secondary_DT): Likewise. + (Convert_Tag_To_Interface): Likewise. + (Make_DT): Remove second parameter. + * exp_disp.adb (Make_DT): Likewise. + (Check_Premature_Freezing): Delete. + Pass Do_Freeze_Profile as False in call to Freeze_Entity. + * freeze.ads (Freezing_Library_Level_Tagged_Type): Delete. + * freeze.adb (Freeze_Profile): Remove obsolete code. + (Freeze_Entity): Tweak comment. + +2022-05-30 Yannick Moy <moy@adacore.com> + + * libgnat/s-arit32.adb (Scaled_Divide32): Move assertion up. + +2022-05-30 Yannick Moy <moy@adacore.com> + + PR ada/105303 + * libgnat/s-gearop.adb: Add pragma Assertion_Policy in generic + bodies making use of additional assertions or ghost code. + * libgnat/s-gearop.ads: Remove confusing Assertion_Policy. + +2022-05-30 Steve Baird <baird@adacore.com> + + * exp_ch11.adb (Expand_N_Raise_Expression): Remove + Convert_To_Return_False test. + * gen_il-fields.ads: Remove Convert_To_Return_False field. + * gen_il-gen-gen_nodes.adb: Remove use of + Convert_To_Return_False field. + * sinfo.ads: Remove comment describing Convert_To_Return_False + flag. + +2022-05-30 Julien Bortolussi <bortolussi@adacore.com> + + * libgnat/a-cofuma.ads, libgnat/a-cofuma.adb, + libgnat/a-cofuse.ads, libgnat/a-cofuse.adb, + libgnat/a-cofuve.ads, libgnat/a-cofuve.adb: Add empty + constructors. + +2022-05-30 Ghjuvan Lacambre <lacambre@adacore.com> + + * bindgen.adb (Gen_CUDA_Init): Remove code generating CUDA + definitions. + (Gen_CUDA_Defs): New function, generating definitions + initialized by Gen_CUDA_Init. + (Gen_Output_File_Ada): Call Gen_CUDA_Defs instead of + Gen_CUDA_Init. + (Gen_Adainit): Call Gen_CUDA_Init. + 2022-05-28 Alexandre Oliva <oliva@adacore.com> * gcc-interface/Makefile.in (OSCONS_CC): Rename to... diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl index 8812d15..43d54f1 100644 --- a/gcc/ada/Makefile.rtl +++ b/gcc/ada/Makefile.rtl @@ -1542,9 +1542,8 @@ ifeq ($(strip $(filter-out arm aarch64 %qnx,$(target_cpu) $(target_os))),) s-dorepr.adb<libgnat/s-dorepr__fma.adb LIBGNAT_TARGET_PAIRS += $(GNATRTL_128BIT_PAIRS) EXTRA_GNATRTL_NONTASKING_OBJS = $(GNATRTL_128BIT_OBJS) - # Temporarily restrict shared library build to aarch64 (V303-025) - GNATLIB_SHARED = gnatlib-shared-dual endif + GNATLIB_SHARED = gnatlib-shared-dual EXTRA_LIBGNAT_OBJS+=$(SIGTRAMP_OBJ) EXTRA_LIBGNAT_SRCS+=sigtramp.h diff --git a/gcc/ada/atree.adb b/gcc/ada/atree.adb index a949761..2d7962c 100644 --- a/gcc/ada/atree.adb +++ b/gcc/ada/atree.adb @@ -1775,6 +1775,11 @@ package body Atree is -- Mark the copy as Ghost depending on the current Ghost region + if Nkind (New_Id) in N_Entity then + Set_Is_Checked_Ghost_Entity (New_Id, False); + Set_Is_Ignored_Ghost_Entity (New_Id, False); + end if; + Mark_New_Ghost_Node (New_Id); New_Node_Debugging_Output (New_Id); diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb index 14f4f95..204d13e 100644 --- a/gcc/ada/checks.adb +++ b/gcc/ada/checks.adb @@ -2944,14 +2944,28 @@ package body Checks is -- Similarly, if the expression is an aggregate in an object -- declaration, apply it to the object after the declaration. - -- This is only necessary in rare cases of tagged extensions - -- initialized with an aggregate with an "others => <>" clause. + + -- This is only necessary in cases of tagged extensions + -- initialized with an aggregate with an "others => <>" clause, + -- when the subtypes of LHS and RHS do not statically match or + -- when we know the object's type will be rewritten later. + -- The condition for the later is copied from the + -- Analyze_Object_Declaration procedure when it actually builds the + -- subtype. elsif Nkind (Par) = N_Object_Declaration then - Insert_Action_After (Par, - Make_Predicate_Check (Typ, - New_Occurrence_Of (Defining_Identifier (Par), Sloc (N)))); - return; + if Subtypes_Statically_Match + (Etype (Defining_Identifier (Par)), Typ) + and then (Nkind (N) = N_Extension_Aggregate + or else (Is_Definite_Subtype (Typ) + and then Build_Default_Subtype_OK (Typ))) + then + Insert_Action_After (Par, + Make_Predicate_Check (Typ, + New_Occurrence_Of (Defining_Identifier (Par), Sloc (N)))); + return; + end if; + end if; end if; diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb index 9463642..1081b98 100644 --- a/gcc/ada/contracts.adb +++ b/gcc/ada/contracts.adb @@ -892,9 +892,15 @@ package body Contracts is end; end if; - -- Verify the mutual interaction of the various external properties - - if Seen then + -- Verify the mutual interaction of the various external properties. + -- For variables for which No_Caching is enabled, it has been checked + -- already that only False values for other external properties are + -- allowed. + + if Seen + and then (Ekind (Type_Or_Obj_Id) /= E_Variable + or else not No_Caching_Enabled (Type_Or_Obj_Id)) + then Check_External_Properties (Type_Or_Obj_Id, AR_Val, AW_Val, ER_Val, EW_Val); end if; @@ -2365,6 +2371,10 @@ package body Contracts is Set_Debug_Info_Needed (Proc_Id); Set_Postconditions_Proc (Subp_Id, Proc_Id); + -- Mark it inlined to speed up the call + + Set_Is_Inlined (Proc_Id); + -- Force the front-end inlining of _Postconditions when generating C -- code, since its body may have references to itypes defined in the -- enclosing subprogram, which would cause problems for unnesting @@ -2373,7 +2383,6 @@ package body Contracts is if Modify_Tree_For_C then Set_Has_Pragma_Inline (Proc_Id); Set_Has_Pragma_Inline_Always (Proc_Id); - Set_Is_Inlined (Proc_Id); end if; -- The related subprogram is a function: create the specification of diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index 0631a53..f4f752d 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -7,6 +7,9 @@ Security Hardening Features This chapter describes Ada extensions aimed at security hardening that are provided by GNAT. +The features in this chapter are currently experimental and subject to +change. + .. Register Scrubbing: Register Scrubbing diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst index ed6b463..29293e1 100644 --- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst +++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst @@ -1238,7 +1238,8 @@ Alphabetical List of All Switches :switch:`-fdiagnostics-format=json` Makes GNAT emit warning and error messages as JSON. Inhibits printing of text warning and errors messages except if :switch:`-gnatv` or - :switch:`-gnatl` are present. + :switch:`-gnatl` are present. Uses absolute file paths when used along + :switch:`-gnatef`. .. index:: -fdump-scos (gcc) @@ -1582,7 +1583,8 @@ Alphabetical List of All Switches .. index:: -gnatef (gcc) :switch:`-gnatef` - Display full source path name in brief error messages. + Display full source path name in brief error messages and absolute paths in + :switch:`-fdiagnostics-format=json`'s output. .. index:: -gnateF (gcc) diff --git a/gcc/ada/einfo-utils.adb b/gcc/ada/einfo-utils.adb index 48a1bce..5e778b1 100644 --- a/gcc/ada/einfo-utils.adb +++ b/gcc/ada/einfo-utils.adb @@ -2659,7 +2659,7 @@ package body Einfo.Utils is | E_Anonymous_Access_Subprogram_Type and then not Has_Convention_Pragma (Typ) then - Set_Basic_Convention (Typ, Val); + Set_Convention (Typ, Val); Set_Has_Convention_Pragma (Typ); -- And for the access subprogram type, deal similarly with the @@ -2669,10 +2669,9 @@ package body Einfo.Utils is declare Dtype : constant Entity_Id := Designated_Type (Typ); begin - if Ekind (Dtype) = E_Subprogram_Type - and then not Has_Convention_Pragma (Dtype) - then - Set_Basic_Convention (Dtype, Val); + if Ekind (Dtype) = E_Subprogram_Type then + pragma Assert (not Has_Convention_Pragma (Dtype)); + Set_Convention (Dtype, Val); Set_Has_Convention_Pragma (Dtype); end if; end; diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads index b0601a9..c5843f2 100644 --- a/gcc/ada/einfo.ads +++ b/gcc/ada/einfo.ads @@ -605,10 +605,10 @@ package Einfo is -- Checks_May_Be_Suppressed -- Defined in all entities. Set if a pragma Suppress or Unsuppress --- mentions the entity specifically in the second argument. If this --- flag is set the Global_Entity_Suppress and Local_Entity_Suppress --- tables must be consulted to determine if there actually is an active --- Suppress or Unsuppress pragma that applies to the entity. +-- mentions the entity specifically in the second argument. If this flag +-- is set the global and local suppress stacks must be consulted to +-- determine if there actually is an active Suppress or Unsuppress pragma +-- that applies to the entity. -- Class_Postconditions -- Defined on subprogram entities. Set if the subprogram has class-wide @@ -1576,7 +1576,8 @@ package Einfo is -- Has_Controlling_Result -- Defined in E_Function entities. Set if the function is a primitive --- function of a tagged type which can dispatch on result. +-- function of a tagged type which can dispatch on result. Also set on +-- secondary stack thunks built for such a primitive function. -- Has_Convention_Pragma -- Defined in all entities. Set for an entity for which a valid pragma @@ -3322,17 +3323,29 @@ package Einfo is -- Applies to all entities. True for task types and subtypes -- Is_Thunk --- Defined in all entities. True for subprograms that are thunks: that is --- small subprograms built by the expander for tagged types that cover --- interface types. As part of the runtime call to an interface, thunks +-- Defined in all entities. True for subprograms that are thunks, that is +-- small subprograms built by the expander for particular tagged types. +-- There are two different kinds of thunk: interface thunk and secondary +-- stack thunk. Interface thunks are built for tagged types that cover +-- interface types. As part of the runtime call to an interface, they -- displace the pointer to the object (pointer named "this" in the C++ -- terminology) from a secondary dispatch table to the primary dispatch -- table associated with a given tagged type; if the thunk is a function -- that returns an object which covers an interface type then the thunk -- displaces the pointer to the object from the primary dispatch table to --- the secondary dispatch table associated with the interface type. Set --- by Expand_Interface_Thunk and used by Expand_Call to handle extra --- actuals associated with accessibility level. +-- the secondary dispatch table associated with the interface type. + +-- Secondary stack thunks are built for tagged types that do not need to +-- be returned on the secondary stack but have primitive functions which +-- can dispatch on result. In this case, dispatching calls made to these +-- primitive functions nevertheless need to return on the secondary stack +-- and a thunk is built to move the result from the primary stack onto +-- the secondary stack on return from the primitive function. The flag +-- Has_Controlling_Result is set on secondary stack thunks but not on +-- interface thunks. + +-- Thunks may be chained in a single way: an interface thunk may point to +-- a secondary stack thunk, which points to the final thunk target. -- Is_Trivial_Subprogram -- Defined in all entities. Set in subprograms where either the body @@ -4241,8 +4254,7 @@ package Einfo is -- Returns_By_Ref -- Defined in subprogram type entities and functions. Set if a function -- (or an access-to-function type) returns a result by reference, either --- because its return type is a by-reference-type or because the function --- explicitly uses the secondary stack. +-- because the result is built in place, or its type is by-reference. -- Reverse_Bit_Order [base type only] -- Defined in all record type entities. Set if entity has a Bit_Order diff --git a/gcc/ada/errout.adb b/gcc/ada/errout.adb index 8658c38..4e095a7 100644 --- a/gcc/ada/errout.adb +++ b/gcc/ada/errout.adb @@ -51,6 +51,7 @@ with Sinfo.Utils; use Sinfo.Utils; with Snames; use Snames; with Stand; use Stand; with Stylesw; use Stylesw; +with System.OS_Lib; with Uname; use Uname; package body Errout is @@ -2082,6 +2083,7 @@ package body Errout is -- Return True if E is a continuation message. procedure Write_JSON_Escaped_String (Str : String_Ptr); + procedure Write_JSON_Escaped_String (Str : String); -- Write each character of Str, taking care of preceding each quote and -- backslash with a backslash. Note that this escaping differs from what -- GCC does. @@ -2095,11 +2097,14 @@ package body Errout is -- Write Sptr as a JSON location, an object containing a file attribute, -- a line number and a column number. - procedure Write_JSON_Span (Span : Source_Span); - -- Write Span as a JSON span, an object containing a "caret" attribute - -- whose value is the JSON location of Span.Ptr. If Span.First and - -- Span.Last are different from Span.Ptr, they will be printed as JSON + procedure Write_JSON_Span (Error : Error_Msg_Object); + -- Write Error as a JSON span, an object containing a "caret" attribute + -- whose value is the JSON location of Error.Sptr.Ptr. If Sptr.First and + -- Sptr.Last are different from Sptr.Ptr, they will be printed as JSON -- locations under the names "start" and "finish". + -- When Include_Subprogram_In_Messages is true (-gnatdJ) an additional, + -- non-standard, attribute named "subprogram" will be added, allowing + -- precisely identifying the subprogram surrounding the span. ----------------------- -- Is_Continuation -- @@ -2114,9 +2119,9 @@ package body Errout is -- Write_JSON_Escaped_String -- ------------------------------- - procedure Write_JSON_Escaped_String (Str : String_Ptr) is + procedure Write_JSON_Escaped_String (Str : String) is begin - for C of Str.all loop + for C of Str loop if C = '"' or else C = '\' then Write_Char ('\'); end if; @@ -2125,14 +2130,30 @@ package body Errout is end loop; end Write_JSON_Escaped_String; + ------------------------------- + -- Write_JSON_Escaped_String -- + ------------------------------- + + procedure Write_JSON_Escaped_String (Str : String_Ptr) is + begin + Write_JSON_Escaped_String (Str.all); + end Write_JSON_Escaped_String; + ------------------------- -- Write_JSON_Location -- ------------------------- procedure Write_JSON_Location (Sptr : Source_Ptr) is + Name : constant File_Name_Type := + Full_Ref_Name (Get_Source_File_Index (Sptr)); begin Write_Str ("{""file"":"""); - Write_Name (Full_Ref_Name (Get_Source_File_Index (Sptr))); + if Full_Path_Name_For_Brief_Errors then + Write_JSON_Escaped_String + (System.OS_Lib.Normalize_Pathname (Get_Name_String (Name))); + else + Write_Name (Name); + end if; Write_Str (""",""line"":"); Write_Int (Pos (Get_Physical_Line_Number (Sptr))); Write_Str (", ""column"":"); @@ -2144,7 +2165,8 @@ package body Errout is -- Write_JSON_Span -- --------------------- - procedure Write_JSON_Span (Span : Source_Span) is + procedure Write_JSON_Span (Error : Error_Msg_Object) is + Span : constant Source_Span := Error.Sptr; begin Write_Str ("{""caret"":"); Write_JSON_Location (Span.Ptr); @@ -2159,6 +2181,11 @@ package body Errout is Write_JSON_Location (Span.Last); end if; + if Include_Subprogram_In_Messages then + Write_Str + (",""subprogram"":""" & Subprogram_Name_Ptr (Error.Node) & """"); + end if; + Write_Str ("}"); end Write_JSON_Span; @@ -2192,7 +2219,7 @@ package body Errout is -- Print message location Write_Str (",""locations"":["); - Write_JSON_Span (Errors.Table (E).Sptr); + Write_JSON_Span (Errors.Table (E)); if Errors.Table (E).Optr /= Errors.Table (E).Sptr.Ptr then Write_Str (",{""caret"":"); diff --git a/gcc/ada/exp_ch13.adb b/gcc/ada/exp_ch13.adb index 6b6da81..444f752 100644 --- a/gcc/ada/exp_ch13.adb +++ b/gcc/ada/exp_ch13.adb @@ -626,59 +626,61 @@ package body Exp_Ch13 is end if; -- Analyze actions generated by freezing. The init_proc contains source - -- expressions that may raise Constraint_Error, and the assignment + -- expressions that may raise Constraint_Error, the assignment -- procedure for complex types needs checks on individual component - -- assignments, but all other freezing actions should be compiled with - -- all checks off. - - if Present (Actions (N)) then - Decl := First (Actions (N)); - while Present (Decl) loop - if Nkind (Decl) = N_Subprogram_Body - and then (Is_Init_Proc (Defining_Entity (Decl)) - or else - Chars (Defining_Entity (Decl)) = Name_uAssign) - then - Analyze (Decl); + -- assignments, and wrappers may need checks. Other freezing actions + -- should be compiled with all checks off. + + Decl := First (Actions (N)); + while Present (Decl) loop + if Nkind (Decl) = N_Subprogram_Body + and then (Is_Init_Proc (Defining_Entity (Decl)) + or else + Chars (Defining_Entity (Decl)) = Name_uAssign + or else + (Present (Corresponding_Spec (Decl)) + and then Is_Wrapper + (Corresponding_Spec (Decl)))) + then + Analyze (Decl); - -- A subprogram body created for a renaming_as_body completes - -- a previous declaration, which may be in a different scope. - -- Establish the proper scope before analysis. + -- A subprogram body created for a renaming_as_body completes + -- a previous declaration, which may be in a different scope. + -- Establish the proper scope before analysis. - elsif Nkind (Decl) = N_Subprogram_Body - and then Present (Corresponding_Spec (Decl)) - and then Scope (Corresponding_Spec (Decl)) /= Current_Scope - then - Push_Scope (Scope (Corresponding_Spec (Decl))); - Analyze (Decl, Suppress => All_Checks); - Pop_Scope; - - -- We treat generated equality specially, if validity checks are - -- enabled, in order to detect components default-initialized - -- with invalid values. - - elsif Nkind (Decl) = N_Subprogram_Body - and then Chars (Defining_Entity (Decl)) = Name_Op_Eq - and then Validity_Checks_On - and then Initialize_Scalars - then - declare - Save_Force : constant Boolean := Force_Validity_Checks; - begin - Force_Validity_Checks := True; - Analyze (Decl); - Force_Validity_Checks := Save_Force; - end; + elsif Nkind (Decl) = N_Subprogram_Body + and then Present (Corresponding_Spec (Decl)) + and then Scope (Corresponding_Spec (Decl)) /= Current_Scope + then + Push_Scope (Scope (Corresponding_Spec (Decl))); + Analyze (Decl, Suppress => All_Checks); + Pop_Scope; + + -- We treat generated equality specially, if validity checks are + -- enabled, in order to detect components default-initialized with + -- invalid values. + + elsif Nkind (Decl) = N_Subprogram_Body + and then Chars (Defining_Entity (Decl)) = Name_Op_Eq + and then Validity_Checks_On + and then Initialize_Scalars + then + declare + Save_Force : constant Boolean := Force_Validity_Checks; + begin + Force_Validity_Checks := True; + Analyze (Decl); + Force_Validity_Checks := Save_Force; + end; - -- All other freezing actions + -- All other freezing actions - else - Analyze (Decl, Suppress => All_Checks); - end if; + else + Analyze (Decl, Suppress => All_Checks); + end if; - Next (Decl); - end loop; - end if; + Next (Decl); + end loop; -- If we are to delete this N_Freeze_Entity, do so by rewriting so that -- a loop on all nodes being inserted will work propertly. diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index 87a84b4..d02a863 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -106,6 +106,13 @@ package body Exp_Ch3 is -- types with discriminants. Otherwise new identifiers are created, -- with the source names of the discriminants. + procedure Build_Discr_Checking_Funcs (N : Node_Id); + -- For each variant component, builds a function which checks whether + -- the component name is consistent with the current discriminants + -- and sets the component's Dcheck_Function attribute to refer to it. + -- N is the full type declaration node; the discriminant checking + -- functions are inserted after this node. + function Build_Equivalent_Array_Aggregate (T : Entity_Id) return Node_Id; -- This function builds a static aggregate that can serve as the initial -- value for an array type whose bounds are static, and whose component @@ -152,6 +159,12 @@ package body Exp_Ch3 is -- needed after an initialization. Typ is the component type, and Proc_Id -- the initialization procedure for the enclosing composite type. + procedure Copy_Discr_Checking_Funcs (N : Node_Id); + -- For a derived untagged type, copy the attributes that were set + -- for the components of the parent type onto the components of the + -- derived type. No new subprograms are constructed. + -- N is the full type declaration node, as for Build_Discr_Checking_Funcs. + procedure Expand_Freeze_Array_Type (N : Node_Id); -- Freeze an array type. Deals with building the initialization procedure, -- creating the packed array type for a packed array and also with the @@ -1219,6 +1232,25 @@ package body Exp_Ch3 is end if; end Build_Discr_Checking_Funcs; + ---------------------------------------- + -- Build_Or_Copy_Discr_Checking_Funcs -- + ---------------------------------------- + + procedure Build_Or_Copy_Discr_Checking_Funcs (N : Node_Id) is + Typ : constant Entity_Id := Defining_Identifier (N); + begin + if Is_Unchecked_Union (Typ) or else not Has_Discriminants (Typ) then + null; + elsif not Is_Derived_Type (Typ) + or else Has_New_Non_Standard_Rep (Typ) + or else Is_Tagged_Type (Typ) + then + Build_Discr_Checking_Funcs (N); + else + Copy_Discr_Checking_Funcs (N); + end if; + end Build_Or_Copy_Discr_Checking_Funcs; + -------------------------------- -- Build_Discriminant_Formals -- -------------------------------- @@ -4842,6 +4874,27 @@ package body Exp_Ch3 is end if; end Clean_Task_Names; + ------------------------------- + -- Copy_Discr_Checking_Funcs -- + ------------------------------- + + procedure Copy_Discr_Checking_Funcs (N : Node_Id) is + Typ : constant Entity_Id := Defining_Identifier (N); + Comp : Entity_Id := First_Component (Typ); + Old_Comp : Entity_Id := First_Component + (Base_Type (Underlying_Type (Etype (Typ)))); + begin + while Present (Comp) loop + if Chars (Comp) = Chars (Old_Comp) then + Set_Discriminant_Checking_Func + (Comp, Discriminant_Checking_Func (Old_Comp)); + end if; + + Next_Component (Old_Comp); + Next_Component (Comp); + end loop; + end Copy_Discr_Checking_Funcs; + ---------------------------------------- -- Ensure_Activation_Chain_And_Master -- ---------------------------------------- @@ -5527,40 +5580,7 @@ package body Exp_Ch3 is -- we copy explicitly the discriminant checking functions from the -- parent into the components of the derived type. - if not Is_Derived_Type (Typ) - or else Has_New_Non_Standard_Rep (Typ) - or else Is_Tagged_Type (Typ) - then - Build_Discr_Checking_Funcs (Typ_Decl); - - elsif Is_Derived_Type (Typ) - and then not Is_Tagged_Type (Typ) - - -- If we have a derived Unchecked_Union, we do not inherit the - -- discriminant checking functions from the parent type since the - -- discriminants are non existent. - - and then not Is_Unchecked_Union (Typ) - and then Has_Discriminants (Typ) - then - declare - Old_Comp : Entity_Id; - - begin - Old_Comp := - First_Component (Base_Type (Underlying_Type (Etype (Typ)))); - Comp := First_Component (Typ); - while Present (Comp) loop - if Chars (Comp) = Chars (Old_Comp) then - Set_Discriminant_Checking_Func - (Comp, Discriminant_Checking_Func (Old_Comp)); - end if; - - Next_Component (Old_Comp); - Next_Component (Comp); - end loop; - end; - end if; + Build_Or_Copy_Discr_Checking_Funcs (Typ_Decl); if Is_Derived_Type (Typ) and then Is_Limited_Type (Typ) @@ -5743,7 +5763,7 @@ package body Exp_Ch3 is -- Generate dispatch table of locally defined tagged type. -- Dispatch tables of library level tagged types are built - -- later (see Analyze_Declarations). + -- later (see Build_Static_Dispatch_Tables). if not Building_Static_DT (Typ) then Append_Freeze_Actions (Typ, Make_DT (Typ)); @@ -6887,37 +6907,6 @@ package body Exp_Ch3 is return; end if; - -- First we do special processing for objects of a tagged type where - -- this is the point at which the type is frozen. The creation of the - -- dispatch table and the initialization procedure have to be deferred - -- to this point, since we reference previously declared primitive - -- subprograms. - - -- Force construction of dispatch tables of library level tagged types - - if Tagged_Type_Expansion - and then Building_Static_Dispatch_Tables - and then Is_Library_Level_Entity (Def_Id) - and then Is_Library_Level_Tagged_Type (Base_Typ) - and then Ekind (Base_Typ) in E_Record_Type - | E_Protected_Type - | E_Task_Type - and then not Has_Dispatch_Table (Base_Typ) - then - declare - New_Nodes : List_Id := No_List; - - begin - if Is_Concurrent_Type (Base_Typ) then - New_Nodes := Make_DT (Corresponding_Record_Type (Base_Typ)); - else - New_Nodes := Make_DT (Base_Typ); - end if; - - Insert_List_Before (N, New_Nodes); - end; - end if; - -- Make shared memory routines for shared passive variable if Is_Shared_Passive (Def_Id) then @@ -9517,7 +9506,7 @@ package body Exp_Ch3 is -- Prim_T => Typ'Tag, -- Interface_T => Iface'Tag, -- Offset_Value => n, - -- Offset_Func => Fn'Address) + -- Offset_Func => Fn'Unrestricted_Access) Append_To (Stmts_List, Make_Procedure_Call_Statement (Loc, @@ -9552,7 +9541,7 @@ package body Exp_Ch3 is Make_Attribute_Reference (Loc, Prefix => New_Occurrence_Of (DT_Offset_To_Top_Func (Tag_Comp), Loc), - Attribute_Name => Name_Address))))); + Attribute_Name => Name_Unrestricted_Access))))); -- In this case the next component stores the value of the offset -- to the top. @@ -10011,6 +10000,13 @@ package body Exp_Ch3 is Mutate_Ekind (Func_Id, E_Function); Set_Is_Wrapper (Func_Id); + -- Corresponding_Spec will be set again to the same value during + -- analysis, but we need this information earlier. + -- Expand_N_Freeze_Entity needs to know whether a subprogram body + -- is a wrapper's body in order to get check suppression right. + + Set_Corresponding_Spec (Func_Body, Func_Id); + Override_Dispatching_Operation (Tag_Typ, Subp, New_Op => Func_Id); end if; diff --git a/gcc/ada/exp_ch3.ads b/gcc/ada/exp_ch3.ads index 23fecfd..ca8a550 100644 --- a/gcc/ada/exp_ch3.ads +++ b/gcc/ada/exp_ch3.ads @@ -56,10 +56,15 @@ package Exp_Ch3 is -- checks on the relevant aspects. The wrapper body could be simplified to -- a null body when expansion is disabled ??? - procedure Build_Discr_Checking_Funcs (N : Node_Id); - -- Builds function which checks whether the component name is consistent - -- with the current discriminants. N is the full type declaration node, - -- and the discriminant checking functions are inserted after this node. + procedure Build_Or_Copy_Discr_Checking_Funcs (N : Node_Id); + -- For each variant component, builds a function that checks whether + -- the component name is consistent with the current discriminants + -- and sets the component's Dcheck_Function attribute to refer to it. + -- N is the full type declaration node; the discriminant checking + -- functions are inserted after this node. + -- In the case of a derived untagged type, copy the attributes that were + -- set for the components of the parent type onto the components of the + -- derived type; no new subprograms are constructed in this case. function Build_Initialization_Call (Loc : Source_Ptr; diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 75f0e56..140789a 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -46,6 +46,7 @@ with Exp_Tss; use Exp_Tss; with Exp_Util; use Exp_Util; with Freeze; use Freeze; with Inline; use Inline; +with Lib; use Lib; with Namet; use Namet; with Nlists; use Nlists; with Nmake; use Nmake; @@ -6388,7 +6389,7 @@ package body Exp_Ch4 is Lcheck : Compare_Result; Ucheck : Compare_Result; - Warn1 : constant Boolean := + Warn : constant Boolean := Constant_Condition_Warnings and then Comes_From_Source (N) and then not In_Instance; @@ -6397,16 +6398,6 @@ package body Exp_Ch4 is -- also skip these warnings in an instance since it may be the -- case that different instantiations have different ranges. - Warn2 : constant Boolean := - Warn1 - and then Nkind (Original_Node (Rop)) = N_Range - and then Is_Integer_Type (Etype (Lo)); - -- For the case where only one bound warning is elided, we also - -- insist on an explicit range and an integer type. The reason is - -- that the use of enumeration ranges including an end point is - -- common, as is the use of a subtype name, one of whose bounds is - -- the same as the type of the expression. - begin -- If test is explicit x'First .. x'Last, replace by valid check @@ -6491,7 +6482,7 @@ package body Exp_Ch4 is -- legality checks, because we are constant-folding beyond RM 4.9. if Lcheck = LT or else Ucheck = GT then - if Warn1 then + if Warn then Error_Msg_N ("?c?range test optimized away", N); Error_Msg_N ("\?c?value is known to be out of range", N); end if; @@ -6505,7 +6496,7 @@ package body Exp_Ch4 is -- since we know we are in range. elsif Lcheck in Compare_GE and then Ucheck in Compare_LE then - if Warn1 then + if Warn then Error_Msg_N ("?c?range test optimized away", N); Error_Msg_N ("\?c?value is known to be in range", N); end if; @@ -6520,11 +6511,6 @@ package body Exp_Ch4 is -- a comparison against the upper bound. elsif Lcheck in Compare_GE then - if Warn2 and then not In_Instance then - Error_Msg_N ("??lower bound test optimized away", Lo); - Error_Msg_N ("\??value is known to be in range", Lo); - end if; - Rewrite (N, Make_Op_Le (Loc, Left_Opnd => Lop, @@ -6532,16 +6518,9 @@ package body Exp_Ch4 is Analyze_And_Resolve (N, Restyp); goto Leave; - -- If upper bound check succeeds and lower bound check is not - -- known to succeed or fail, then replace the range check with - -- a comparison against the lower bound. + -- Inverse of previous case. elsif Ucheck in Compare_LE then - if Warn2 and then not In_Instance then - Error_Msg_N ("??upper bound test optimized away", Hi); - Error_Msg_N ("\??value is known to be in range", Hi); - end if; - Rewrite (N, Make_Op_Ge (Loc, Left_Opnd => Lop, @@ -6555,7 +6534,7 @@ package body Exp_Ch4 is -- see if we can determine the outcome assuming everything is -- valid, and if so give an appropriate warning. - if Warn1 and then not Assume_No_Invalid_Values then + if Warn and then not Assume_No_Invalid_Values then Lcheck := Compile_Time_Compare (Lop, Lo, Assume_Valid => True); Ucheck := Compile_Time_Compare (Lop, Hi, Assume_Valid => True); @@ -6570,18 +6549,6 @@ package body Exp_Ch4 is elsif Lcheck in Compare_GE and then Ucheck in Compare_LE then Error_Msg_N ("?c?value can only be out of range if it is invalid", N); - - -- Lower bound check succeeds if value is valid - - elsif Warn2 and then Lcheck in Compare_GE then - Error_Msg_N - ("?c?lower bound check only fails if it is invalid", Lo); - - -- Upper bound check succeeds if value is valid - - elsif Warn2 and then Ucheck in Compare_LE then - Error_Msg_N - ("?c?upper bound check only fails for invalid values", Hi); end if; end if; end; @@ -11042,6 +11009,16 @@ package body Exp_Ch4 is -- actually performed. else + if (not Is_Unchecked_Union + (Implementation_Base_Type (Etype (Prefix (N))))) + and then not Is_Predefined_Unit (Get_Source_Unit (N)) + then + Error_Msg_N + ("sorry - unable to generate discriminant check for" & + " reference to variant component &", + Selector_Name (N)); + end if; + Set_Do_Discriminant_Check (N, False); end if; end if; diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb index 9c7a370..2072935 100644 --- a/gcc/ada/exp_ch5.adb +++ b/gcc/ada/exp_ch5.adb @@ -4530,75 +4530,72 @@ package body Exp_Ch5 is -- Loop through elsif parts, dealing with constant conditions and -- possible condition actions that are present. - if Present (Elsif_Parts (N)) then - E := First (Elsif_Parts (N)); - while Present (E) loop + E := First (Elsif_Parts (N)); + while Present (E) loop - -- Do not consider controlled objects found in an if statement - -- which actually models an if expression because their early - -- finalization will affect the result of the expression. + -- Do not consider controlled objects found in an if statement which + -- actually models an if expression because their early finalization + -- will affect the result of the expression. - if not From_Conditional_Expression (N) then - Process_Statements_For_Controlled_Objects (E); - end if; + if not From_Conditional_Expression (N) then + Process_Statements_For_Controlled_Objects (E); + end if; - Adjust_Condition (Condition (E)); + Adjust_Condition (Condition (E)); - -- If there are condition actions, then rewrite the if statement - -- as indicated above. We also do the same rewrite for a True or - -- False condition. The further processing of this constant - -- condition is then done by the recursive call to expand the - -- newly created if statement + -- If there are condition actions, then rewrite the if statement as + -- indicated above. We also do the same rewrite for a True or False + -- condition. The further processing of this constant condition is + -- then done by the recursive call to expand the newly created if + -- statement - if Present (Condition_Actions (E)) - or else Compile_Time_Known_Value (Condition (E)) - then - New_If := - Make_If_Statement (Sloc (E), - Condition => Condition (E), - Then_Statements => Then_Statements (E), - Elsif_Parts => No_List, - Else_Statements => Else_Statements (N)); - - -- Elsif parts for new if come from remaining elsif's of parent - - while Present (Next (E)) loop - if No (Elsif_Parts (New_If)) then - Set_Elsif_Parts (New_If, New_List); - end if; + if Present (Condition_Actions (E)) + or else Compile_Time_Known_Value (Condition (E)) + then + New_If := + Make_If_Statement (Sloc (E), + Condition => Condition (E), + Then_Statements => Then_Statements (E), + Elsif_Parts => No_List, + Else_Statements => Else_Statements (N)); + + -- Elsif parts for new if come from remaining elsif's of parent + + while Present (Next (E)) loop + if No (Elsif_Parts (New_If)) then + Set_Elsif_Parts (New_If, New_List); + end if; - Append (Remove_Next (E), Elsif_Parts (New_If)); - end loop; + Append (Remove_Next (E), Elsif_Parts (New_If)); + end loop; - Set_Else_Statements (N, New_List (New_If)); + Set_Else_Statements (N, New_List (New_If)); - Insert_List_Before (New_If, Condition_Actions (E)); + Insert_List_Before (New_If, Condition_Actions (E)); - Remove (E); + Remove (E); - if Is_Empty_List (Elsif_Parts (N)) then - Set_Elsif_Parts (N, No_List); - end if; + if Is_Empty_List (Elsif_Parts (N)) then + Set_Elsif_Parts (N, No_List); + end if; - Analyze (New_If); + Analyze (New_If); - -- Note this is not an implicit if statement, since it is part - -- of an explicit if statement in the source (or of an implicit - -- if statement that has already been tested). We set the flag - -- after calling Analyze to avoid generating extra warnings - -- specific to pure if statements, however (see - -- Sem_Ch5.Analyze_If_Statement). + -- Note this is not an implicit if statement, since it is part of + -- an explicit if statement in the source (or of an implicit if + -- statement that has already been tested). We set the flag after + -- calling Analyze to avoid generating extra warnings specific to + -- pure if statements, however (see Sem_Ch5.Analyze_If_Statement). - Preserve_Comes_From_Source (New_If, N); - return; + Preserve_Comes_From_Source (New_If, N); + return; - -- No special processing for that elsif part, move to next + -- No special processing for that elsif part, move to next - else - Next (E); - end if; - end loop; - end if; + else + Next (E); + end if; + end loop; -- Some more optimizations applicable if we still have an IF statement @@ -5203,22 +5200,36 @@ package body Exp_Ch5 is Ent := First_Entity (Pack); while Present (Ent) loop + -- Get_Element_Access function with one parameter called + -- Position. + if Chars (Ent) = Name_Get_Element_Access + and then Ekind (Ent) = E_Function and then Present (First_Formal (Ent)) and then Chars (First_Formal (Ent)) = Name_Position and then No (Next_Formal (First_Formal (Ent))) then + pragma Assert (No (Fast_Element_Access_Op)); Fast_Element_Access_Op := Ent; + -- Next or Prev procedure with one parameter called + -- Position. + elsif Chars (Ent) = Name_Step and then Ekind (Ent) = E_Procedure + and then Present (First_Formal (Ent)) + and then Chars (First_Formal (Ent)) = Name_Position + and then No (Next_Formal (First_Formal (Ent))) then + pragma Assert (No (Fast_Step_Op)); Fast_Step_Op := Ent; elsif Chars (Ent) = Name_Reference_Control_Type then + pragma Assert (No (Reference_Control_Type)); Reference_Control_Type := Ent; elsif Chars (Ent) = Name_Pseudo_Reference then + pragma Assert (No (Pseudo_Reference)); Pseudo_Reference := Ent; end if; diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb index 7d50727..15a2039 100644 --- a/gcc/ada/exp_ch6.adb +++ b/gcc/ada/exp_ch6.adb @@ -164,7 +164,7 @@ package body Exp_Ch6 is function Caller_Known_Size (Func_Call : Node_Id; Result_Subt : Entity_Id) return Boolean; - -- True if result subtype is definite, or has a size that does not require + -- True if result subtype is definite or has a size that does not require -- secondary stack usage (i.e. no variant part or components whose type -- depends on discriminants). In particular, untagged types with only -- access discriminants do not require secondary stack use. Note we must @@ -1055,11 +1055,12 @@ package body Exp_Ch6 is (Func_Call : Node_Id; Result_Subt : Entity_Id) return Boolean is + Utyp : constant Entity_Id := Underlying_Type (Result_Subt); + begin - return - (Is_Definite_Subtype (Underlying_Type (Result_Subt)) - and then No (Controlling_Argument (Func_Call))) - or else not Requires_Transient_Scope (Underlying_Type (Result_Subt)); + return not Needs_Secondary_Stack (Utyp) + and then not (Is_Tagged_Type (Utyp) + and then Present (Controlling_Argument (Func_Call))); end Caller_Known_Size; ----------------------- @@ -4945,7 +4946,7 @@ package body Exp_Ch6 is Is_Build_In_Place_Function_Call (Parent (Call_Node))) then Establish_Transient_Scope - (Call_Node, Returns_On_Secondary_Stack (Etype (Subp))); + (Call_Node, Needs_Secondary_Stack (Etype (Subp))); end if; end if; end Expand_Call_Helper; @@ -5548,10 +5549,6 @@ package body Exp_Ch6 is Present (Unqual_BIP_Iface_Function_Call (Expression (Original_Node (Ret_Obj_Decl)))))); - -- Return the build-in-place result by reference - - Set_By_Ref (Return_Stmt); - elsif Is_BIP_Func then -- Locate the implicit access parameter associated with the @@ -5585,10 +5582,6 @@ package body Exp_Ch6 is Obj_Alloc_Formal : Entity_Id; begin - -- Build-in-place results must be returned by reference - - Set_By_Ref (Return_Stmt); - -- Retrieve the implicit access parameter passed by the caller Obj_Acc_Formal := @@ -7315,13 +7308,18 @@ package body Exp_Ch6 is -- Deal with returning variable length objects and controlled types - -- Nothing to do if we are returning by reference, or this is not a - -- type that requires special processing (indicated by the fact that - -- it requires a cleanup scope for the secondary stack case). + -- Nothing to do if we are returning by reference - if Is_Build_In_Place_Function (Scope_Id) - or else Is_Limited_Interface (Exp_Typ) - then + if Is_Build_In_Place_Function (Scope_Id) then + -- Prevent the reclamation of the secondary stack by all enclosing + -- blocks and loops as well as the related function; otherwise the + -- result would be reclaimed too early. + + if Needs_BIP_Alloc_Form (Scope_Id) then + Set_Enclosing_Sec_Stack_Return (N); + end if; + + elsif Is_Limited_View (R_Type) then null; -- No copy needed for thunks returning interface type objects since @@ -7332,7 +7330,7 @@ package body Exp_Ch6 is null; -- If the call is within a thunk and the type is a limited view, the - -- backend will eventually see the non-limited view of the type. + -- back end will eventually see the non-limited view of the type. elsif Is_Thunk (Scope_Id) and then Is_Incomplete_Type (Exp_Typ) then return; @@ -7340,7 +7338,8 @@ package body Exp_Ch6 is -- A return statement from an ignored Ghost function does not use the -- secondary stack (or any other one). - elsif not Returns_On_Secondary_Stack (R_Type) + elsif (not Needs_Secondary_Stack (R_Type) + and then not Is_Secondary_Stack_Thunk (Scope_Id)) or else Is_Ignored_Ghost_Entity (Scope_Id) then -- Mutable records with variable-length components are not returned @@ -7379,8 +7378,9 @@ package body Exp_Ch6 is -- return Rnn.all; -- but optimize the case where the result is a function call that - -- also needs finalization. In this case the result is already on - -- the return stack and no further processing is required. + -- also needs finalization. In this case the result can directly be + -- allocated on the the return stack of the caller and no further + -- processing is required. if Present (Utyp) and then Needs_Finalization (Utyp) @@ -7447,17 +7447,11 @@ package body Exp_Ch6 is -- Optimize the case where the result is a function call that also -- returns on the secondary stack. In this case the result is already - -- on the secondary stack and no further processing is required - -- except to set the By_Ref flag to ensure that gigi does not attempt - -- an extra unnecessary copy. (Actually not just unnecessary but - -- wrong in the case of a controlled type, where gigi does not know - -- how to do a copy.) + -- on the secondary stack and no further processing is required. if Exp_Is_Function_Call - and then Returns_On_Secondary_Stack (Exp_Typ) + and then Needs_Secondary_Stack (Exp_Typ) then - Set_By_Ref (N); - -- Remove side effects from the expression now so that other parts -- of the expander do not have to reanalyze this node without this -- optimization @@ -7487,7 +7481,15 @@ package body Exp_Ch6 is -- controlled (by the virtue of restriction No_Finalization) because -- gigi is not able to properly allocate class-wide types. - elsif CW_Or_Needs_Finalization (Utyp) then + -- But optimize the case where the result is a function call that + -- also needs finalization. In this case the result can directly be + -- allocated on the secondary stack and no further processing is + -- required. + + elsif CW_Or_Needs_Finalization (Utyp) + and then not (Exp_Is_Function_Call + and then Needs_Finalization (Exp_Typ)) + then declare Loc : constant Source_Ptr := Sloc (N); Acc_Typ : constant Entity_Id := Make_Temporary (Loc, 'A'); @@ -7827,101 +7829,9 @@ package body Exp_Ch6 is ----------------------- procedure Freeze_Subprogram (N : Node_Id) is - Loc : constant Source_Ptr := Sloc (N); - - procedure Register_Predefined_DT_Entry (Prim : Entity_Id); - -- (Ada 2005): Register a predefined primitive in all the secondary - -- dispatch tables of its primitive type. - - ---------------------------------- - -- Register_Predefined_DT_Entry -- - ---------------------------------- - - procedure Register_Predefined_DT_Entry (Prim : Entity_Id) is - Iface_DT_Ptr : Elmt_Id; - Tagged_Typ : Entity_Id; - Thunk_Id : Entity_Id; - Thunk_Code : Node_Id; - - begin - Tagged_Typ := Find_Dispatching_Type (Prim); - - if No (Access_Disp_Table (Tagged_Typ)) - or else not Has_Interfaces (Tagged_Typ) - or else not RTE_Available (RE_Interface_Tag) - or else Restriction_Active (No_Dispatching_Calls) - then - return; - end if; - - -- Skip the first two access-to-dispatch-table pointers since they - -- leads to the primary dispatch table (predefined DT and user - -- defined DT). We are only concerned with the secondary dispatch - -- table pointers. Note that the access-to- dispatch-table pointer - -- corresponds to the first implemented interface retrieved below. - - Iface_DT_Ptr := - Next_Elmt (Next_Elmt (First_Elmt (Access_Disp_Table (Tagged_Typ)))); - - while Present (Iface_DT_Ptr) - and then Ekind (Node (Iface_DT_Ptr)) = E_Constant - loop - pragma Assert (Has_Thunks (Node (Iface_DT_Ptr))); - Expand_Interface_Thunk (Prim, Thunk_Id, Thunk_Code, - Iface => Related_Type (Node (Iface_DT_Ptr))); - - if Present (Thunk_Code) then - Insert_Actions_After (N, New_List ( - Thunk_Code, - - Build_Set_Predefined_Prim_Op_Address (Loc, - Tag_Node => - New_Occurrence_Of (Node (Next_Elmt (Iface_DT_Ptr)), Loc), - Position => DT_Position (Prim), - Address_Node => - Unchecked_Convert_To (RTE (RE_Prim_Ptr), - Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (Thunk_Id, Loc), - Attribute_Name => Name_Unrestricted_Access))), - - Build_Set_Predefined_Prim_Op_Address (Loc, - Tag_Node => - New_Occurrence_Of - (Node (Next_Elmt (Next_Elmt (Next_Elmt (Iface_DT_Ptr)))), - Loc), - Position => DT_Position (Prim), - Address_Node => - Unchecked_Convert_To (RTE (RE_Prim_Ptr), - Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (Prim, Loc), - Attribute_Name => Name_Unrestricted_Access))))); - end if; - - -- Skip the tag of the predefined primitives dispatch table - - Next_Elmt (Iface_DT_Ptr); - pragma Assert (Has_Thunks (Node (Iface_DT_Ptr))); - - -- Skip tag of the no-thunks dispatch table - - Next_Elmt (Iface_DT_Ptr); - pragma Assert (not Has_Thunks (Node (Iface_DT_Ptr))); - - -- Skip tag of predefined primitives no-thunks dispatch table - - Next_Elmt (Iface_DT_Ptr); - pragma Assert (not Has_Thunks (Node (Iface_DT_Ptr))); - - Next_Elmt (Iface_DT_Ptr); - end loop; - end Register_Predefined_DT_Entry; - - -- Local variables - + Loc : constant Source_Ptr := Sloc (N); Subp : constant Entity_Id := Entity (N); - -- Start of processing for Freeze_Subprogram - begin -- We suppress the initialization of the dispatch table entry when -- not Tagged_Type_Expansion because the dispatching mechanism is @@ -7976,10 +7886,12 @@ package body Exp_Ch6 is or else Present (Interface_Alias (Subp)) then if Is_Predefined_Dispatching_Operation (Subp) then - Register_Predefined_DT_Entry (Subp); + L := Register_Predefined_Primitive (Loc, Subp); + else + L := New_List; end if; - L := Register_Primitive (Loc, Prim => Subp); + Append_List_To (L, Register_Primitive (Loc, Subp)); if Is_Empty_List (L) then null; @@ -10136,7 +10048,7 @@ package body Exp_Ch6 is -- formals. if Is_Thunk (Func_Id) then - Subp_Id := Thunk_Entity (Func_Id); + Subp_Id := Thunk_Target (Func_Id); -- Common case @@ -10180,26 +10092,25 @@ package body Exp_Ch6 is -- Needs_BIP_Finalization_Master -- ----------------------------------- - function Needs_BIP_Finalization_Master - (Func_Id : Entity_Id) return Boolean + function Needs_BIP_Finalization_Master (Func_Id : Entity_Id) return Boolean is - pragma Assert (Is_Build_In_Place_Function (Func_Id)); - Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id)); + Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id)); + begin + pragma Assert (Is_Build_In_Place_Function (Func_Id)); + -- A formal giving the finalization master is needed for build-in-place -- functions whose result type needs finalization or is a tagged type. -- Tagged primitive build-in-place functions need such a formal because -- they can be called by a dispatching call, and extensions may require - -- finalization even if the root type doesn't. This means they're also - -- needed for tagged nonprimitive build-in-place functions with tagged - -- results, since such functions can be called via access-to-function - -- types, and those can be used to call primitives, so masters have to - -- be passed to all such build-in-place functions, primitive or not. - - return - not Restriction_Active (No_Finalization) - and then (Needs_Finalization (Func_Typ) - or else Is_Tagged_Type (Func_Typ)); + -- finalization even if the root type doesn't. This means nonprimitive + -- build-in-place functions with tagged results also need it, since such + -- functions can be called via access-to-function types, and those can + -- be used to call primitives, so the formal needs to be passed to all + -- such build-in-place functions, primitive or not. + + return not Restriction_Active (No_Finalization) + and then (Needs_Finalization (Typ) or else Is_Tagged_Type (Typ)); end Needs_BIP_Finalization_Master; -------------------------- @@ -10207,10 +10118,23 @@ package body Exp_Ch6 is -------------------------- function Needs_BIP_Alloc_Form (Func_Id : Entity_Id) return Boolean is - pragma Assert (Is_Build_In_Place_Function (Func_Id)); - Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id)); + Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id)); + begin - return Requires_Transient_Scope (Func_Typ); + pragma Assert (Is_Build_In_Place_Function (Func_Id)); + + -- A formal giving the allocation method is needed for build-in-place + -- functions whose result type is returned on the secondary stack or + -- is a tagged type. Tagged primitive build-in-place functions need + -- such a formal because they can be called by a dispatching call, and + -- the secondary stack is always used for dispatching-on-result calls. + -- This means nonprimitive build-in-place functions with tagged results + -- also need it, as such functions can be called via access-to-function + -- types, and those can be used to call primitives, so the formal needs + -- to be passed to all such build-in-place functions, primitive or not. + + return not Restriction_Active (No_Secondary_Stack) + and then (Needs_Secondary_Stack (Typ) or else Is_Tagged_Type (Typ)); end Needs_BIP_Alloc_Form; ------------------------------------- diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb index d611d0e..5f1c357 100644 --- a/gcc/ada/exp_ch7.adb +++ b/gcc/ada/exp_ch7.adb @@ -76,15 +76,15 @@ package body Exp_Ch7 is -- Transient Scope Management -- -------------------------------- - -- A transient scope is created when temporary objects are created by the - -- compiler. These temporary objects are allocated on the secondary stack - -- and the transient scope is responsible for finalizing the object when - -- appropriate and reclaiming the memory at the right time. The temporary - -- objects are generally the objects allocated to store the result of a - -- function returning an unconstrained or a tagged value. Expressions - -- needing to be wrapped in a transient scope (functions calls returning - -- unconstrained or tagged values) may appear in 3 different contexts which - -- lead to 3 different kinds of transient scope expansion: + -- A transient scope is needed when certain temporary objects are created + -- by the compiler. These temporary objects are allocated on the secondary + -- stack and/or need finalization, and the transient scope is responsible + -- for finalizing the objects and reclaiming the memory of the secondary + -- stack at the appropriate time. They are generally objects allocated to + -- store the result of a function returning an unconstrained or controlled + -- value. Expressions needing to be wrapped in a transient scope may appear + -- in three different contexts which lead to different kinds of transient + -- scope expansion: -- 1. In a simple statement (procedure call, assignment, ...). In this -- case the instruction is wrapped into a transient block. See @@ -99,29 +99,6 @@ package body Exp_Ch7 is -- declaration and the secondary stack deallocation is done in the -- proper enclosing scope. See Wrap_Transient_Declaration for details. - -- Note about functions returning tagged types: it has been decided to - -- always allocate their result in the secondary stack, even though is not - -- absolutely mandatory when the tagged type is constrained because the - -- caller knows the size of the returned object and thus could allocate the - -- result in the primary stack. An exception to this is when the function - -- builds its result in place, as is done for functions with inherently - -- limited result types for Ada 2005. In that case, certain callers may - -- pass the address of a constrained object as the target object for the - -- function result. - - -- By always allocating tagged results in the secondary stack, a couple of - -- implementation difficulties are avoided: - - -- - If this is a dispatching function call, the computation of the size - -- of the result is possible but complex from the outside. - - -- - If the result type is class-wide, it is unconstrained anyway. - - -- Furthermore, the small loss in efficiency which is the result of this - -- decision is not such a big deal because functions returning tagged types - -- are not as common in practice compared to functions returning access to - -- a tagged type. - -------------------------------------------------- -- Transient Blocks and Finalization Management -- -------------------------------------------------- @@ -5899,16 +5876,20 @@ package body Exp_Ch7 is -- This is done only for non-generic packages if Ekind (Spec_Id) = E_Package then - Push_Scope (Spec_Id); - - -- Build dispatch tables of library level tagged types + -- Build dispatch tables of library-level tagged types for bodies + -- that are not compilation units (see Analyze_Compilation_Unit), + -- except for instances because they have no N_Compilation_Unit. if Tagged_Type_Expansion and then Is_Library_Level_Entity (Spec_Id) + and then (not Is_Compilation_Unit (Spec_Id) + or else Is_Generic_Instance (Spec_Id)) then Build_Static_Dispatch_Tables (N); end if; + Push_Scope (Spec_Id); + Expand_CUDA_Package (N); Build_Task_Activation_Call (N); @@ -6058,12 +6039,13 @@ 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 for instances + -- that are not compilation units (see Analyze_Compilation_Unit). if Tagged_Type_Expansion - and then (Is_Compilation_Unit (Id) - or else (Is_Generic_Instance (Id) - and then Is_Library_Level_Entity (Id))) + and then Is_Library_Level_Entity (Id) + and then Is_Generic_Instance (Id) + and then not Is_Compilation_Unit (Id) then Build_Static_Dispatch_Tables (N); end if; @@ -10312,7 +10294,7 @@ package body Exp_Ch7 is -- reclamation is done by the caller. if Ekind (Curr_S) = E_Function - and then Returns_On_Secondary_Stack (Etype (Curr_S)) + and then Needs_Secondary_Stack (Etype (Curr_S)) then null; diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb index be791c3..ed6844e 100644 --- a/gcc/ada/exp_ch9.adb +++ b/gcc/ada/exp_ch9.adb @@ -9303,171 +9303,167 @@ package body Exp_Ch9 is -- Add private field components - if Present (Private_Declarations (Pdef)) then - Priv := First (Private_Declarations (Pdef)); - while Present (Priv) loop - if Nkind (Priv) = N_Component_Declaration then - if not Static_Component_Size (Defining_Identifier (Priv)) then - - -- When compiling for a restricted profile, the private - -- components must have a static size. If not, this is an - -- error for a single protected declaration, and rates a - -- warning on a protected type declaration. - - if not Comes_From_Source (Prot_Typ) then - - -- It's ok to be checking this restriction at expansion - -- time, because this is only for the restricted profile, - -- which is not subject to strict RM conformance, so it - -- is OK to miss this check in -gnatc mode. - - Check_Restriction (No_Implicit_Heap_Allocations, Priv); - Check_Restriction - (No_Implicit_Protected_Object_Allocations, Priv); - - elsif Restriction_Active (No_Implicit_Heap_Allocations) then - if not Discriminated_Size (Defining_Identifier (Priv)) - then - -- Any object of the type will be non-static + Priv := First (Private_Declarations (Pdef)); + while Present (Priv) loop + if Nkind (Priv) = N_Component_Declaration then + if not Static_Component_Size (Defining_Identifier (Priv)) then - Error_Msg_N ("component has non-static size??", Priv); - Error_Msg_NE - ("\creation of protected object of type& will " - & "violate restriction " - & "No_Implicit_Heap_Allocations??", Priv, Prot_Typ); - else - -- Object will be non-static if discriminants are + -- When compiling for a restricted profile, the private + -- components must have a static size. If not, this is an error + -- for a single protected declaration, and rates a warning on a + -- protected type declaration. - Error_Msg_NE - ("creation of protected object of type& with " - & "non-static discriminants will violate " - & "restriction No_Implicit_Heap_Allocations??", - Priv, Prot_Typ); - end if; + if not Comes_From_Source (Prot_Typ) then + + -- It's ok to be checking this restriction at expansion + -- time, because this is only for the restricted profile, + -- which is not subject to strict RM conformance, so it + -- is OK to miss this check in -gnatc mode. - -- Likewise for No_Implicit_Protected_Object_Allocations + Check_Restriction (No_Implicit_Heap_Allocations, Priv); + Check_Restriction + (No_Implicit_Protected_Object_Allocations, Priv); - elsif Restriction_Active - (No_Implicit_Protected_Object_Allocations) + elsif Restriction_Active (No_Implicit_Heap_Allocations) then + if not Discriminated_Size (Defining_Identifier (Priv)) then - if not Discriminated_Size (Defining_Identifier (Priv)) - then - -- Any object of the type will be non-static - - Error_Msg_N ("component has non-static size??", Priv); - Error_Msg_NE - ("\creation of protected object of type& will " - & "violate restriction " - & "No_Implicit_Protected_Object_Allocations??", - Priv, Prot_Typ); - else - -- Object will be non-static if discriminants are - - Error_Msg_NE - ("creation of protected object of type& with " - & "non-static discriminants will violate " - & "restriction " - & "No_Implicit_Protected_Object_Allocations??", - Priv, Prot_Typ); - end if; + -- Any object of the type will be non-static + + Error_Msg_N ("component has non-static size??", Priv); + Error_Msg_NE + ("\creation of protected object of type& will " + & "violate restriction " + & "No_Implicit_Heap_Allocations??", Priv, Prot_Typ); + else + -- Object will be non-static if discriminants are + + Error_Msg_NE + ("creation of protected object of type& with " + & "non-static discriminants will violate " + & "restriction No_Implicit_Heap_Allocations??", + Priv, Prot_Typ); + end if; + + -- Likewise for No_Implicit_Protected_Object_Allocations + + elsif Restriction_Active + (No_Implicit_Protected_Object_Allocations) + then + if not Discriminated_Size (Defining_Identifier (Priv)) then + -- Any object of the type will be non-static + + Error_Msg_N ("component has non-static size??", Priv); + Error_Msg_NE + ("\creation of protected object of type& will violate " + & "restriction " + & "No_Implicit_Protected_Object_Allocations??", + Priv, Prot_Typ); + else + -- Object will be non-static if discriminants are + + Error_Msg_NE + ("creation of protected object of type& with " + & "non-static discriminants will violate restriction " + & "No_Implicit_Protected_Object_Allocations??", + Priv, Prot_Typ); end if; end if; + end if; - -- The component definition consists of a subtype indication, - -- or (in Ada 2005) an access definition. Make a copy of the - -- proper definition. + -- The component definition consists of a subtype indication, or + -- (in Ada 2005) an access definition. Make a copy of the proper + -- definition. - declare - Old_Comp : constant Node_Id := Component_Definition (Priv); - Oent : constant Entity_Id := Defining_Identifier (Priv); - Nent : constant Entity_Id := - Make_Defining_Identifier (Sloc (Oent), - Chars => Chars (Oent)); - New_Comp : Node_Id; + declare + Old_Comp : constant Node_Id := Component_Definition (Priv); + Oent : constant Entity_Id := Defining_Identifier (Priv); + Nent : constant Entity_Id := + Make_Defining_Identifier (Sloc (Oent), + Chars => Chars (Oent)); + New_Comp : Node_Id; - begin - if Present (Subtype_Indication (Old_Comp)) then - New_Comp := - Make_Component_Definition (Sloc (Oent), - Aliased_Present => False, - Subtype_Indication => - New_Copy_Tree - (Subtype_Indication (Old_Comp), Discr_Map)); - else - New_Comp := - Make_Component_Definition (Sloc (Oent), - Aliased_Present => False, - Access_Definition => - New_Copy_Tree - (Access_Definition (Old_Comp), Discr_Map)); - - -- A self-reference in the private part becomes a - -- self-reference to the corresponding record. - - if Entity (Subtype_Mark (Access_Definition (New_Comp))) - = Prot_Typ - then - Replace_Access_Definition (New_Comp); - end if; + begin + if Present (Subtype_Indication (Old_Comp)) then + New_Comp := + Make_Component_Definition (Sloc (Oent), + Aliased_Present => False, + Subtype_Indication => + New_Copy_Tree + (Subtype_Indication (Old_Comp), Discr_Map)); + else + New_Comp := + Make_Component_Definition (Sloc (Oent), + Aliased_Present => False, + Access_Definition => + New_Copy_Tree + (Access_Definition (Old_Comp), Discr_Map)); + + -- A self-reference in the private part becomes a + -- self-reference to the corresponding record. + + if Entity (Subtype_Mark (Access_Definition (New_Comp))) + = Prot_Typ + then + Replace_Access_Definition (New_Comp); end if; + end if; - New_Priv := - Make_Component_Declaration (Loc, - Defining_Identifier => Nent, - Component_Definition => New_Comp, - Expression => Expression (Priv)); + New_Priv := + Make_Component_Declaration (Loc, + Defining_Identifier => Nent, + Component_Definition => New_Comp, + Expression => Expression (Priv)); - Set_Has_Per_Object_Constraint (Nent, - Has_Per_Object_Constraint (Oent)); + Set_Has_Per_Object_Constraint (Nent, + Has_Per_Object_Constraint (Oent)); - Append_To (Cdecls, New_Priv); - end; + Append_To (Cdecls, New_Priv); + end; - elsif Nkind (Priv) = N_Subprogram_Declaration then + elsif Nkind (Priv) = N_Subprogram_Declaration then - -- Make the unprotected version of the subprogram available - -- for expansion of intra object calls. There is need for - -- a protected version only if the subprogram is an interrupt - -- handler, otherwise this operation can only be called from - -- within the body. + -- Make the unprotected version of the subprogram available for + -- expansion of intra object calls. There is need for a protected + -- version only if the subprogram is an interrupt handler, + -- otherwise this operation can only be called from within the + -- body. - Sub := - Make_Subprogram_Declaration (Loc, - Specification => - Build_Protected_Sub_Specification - (Priv, Prot_Typ, Unprotected_Mode)); + Sub := + Make_Subprogram_Declaration (Loc, + Specification => + Build_Protected_Sub_Specification + (Priv, Prot_Typ, Unprotected_Mode)); - Insert_After (Current_Node, Sub); - Analyze (Sub); + Insert_After (Current_Node, Sub); + Analyze (Sub); - Set_Protected_Body_Subprogram - (Defining_Unit_Name (Specification (Priv)), - Defining_Unit_Name (Specification (Sub))); - Check_Inlining (Defining_Unit_Name (Specification (Priv))); - Current_Node := Sub; + Set_Protected_Body_Subprogram + (Defining_Unit_Name (Specification (Priv)), + Defining_Unit_Name (Specification (Sub))); + Check_Inlining (Defining_Unit_Name (Specification (Priv))); + Current_Node := Sub; - Sub := - Make_Subprogram_Declaration (Loc, - Specification => - Build_Protected_Sub_Specification - (Priv, Prot_Typ, Protected_Mode)); + Sub := + Make_Subprogram_Declaration (Loc, + Specification => + Build_Protected_Sub_Specification + (Priv, Prot_Typ, Protected_Mode)); - Insert_After (Current_Node, Sub); - Analyze (Sub); - Current_Node := Sub; + Insert_After (Current_Node, Sub); + Analyze (Sub); + Current_Node := Sub; - if Is_Interrupt_Handler - (Defining_Unit_Name (Specification (Priv))) - then - if not Restricted_Profile then - Register_Handler; - end if; + if Is_Interrupt_Handler + (Defining_Unit_Name (Specification (Priv))) + then + if not Restricted_Profile then + Register_Handler; end if; end if; + end if; - Next (Priv); - end loop; - end if; + Next (Priv); + end loop; -- Except for the lock-free implementation, append the _Object field -- with the right type to the component list. We need to compute the @@ -9708,16 +9704,14 @@ package body Exp_Ch9 is -- If there are some private entry declarations, expand it as if they -- were visible entries. - if Present (Private_Declarations (Pdef)) then - Comp := First (Private_Declarations (Pdef)); - while Present (Comp) loop - if Nkind (Comp) = N_Entry_Declaration then - Expand_Entry_Declaration (Comp); - end if; + Comp := First (Private_Declarations (Pdef)); + while Present (Comp) loop + if Nkind (Comp) = N_Entry_Declaration then + Expand_Entry_Declaration (Comp); + end if; - Next (Comp); - end loop; - end if; + Next (Comp); + end loop; -- Create the declaration of an array object which contains the values -- of aspect/pragma Max_Queue_Length for all entries of the protected diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb index 1f43458..17043d1 100644 --- a/gcc/ada/exp_disp.adb +++ b/gcc/ada/exp_disp.adb @@ -80,6 +80,35 @@ package body Exp_Disp is -- Ada 2005 (AI-251): Returns the fixed position in the dispatch table -- of the default primitive operations. + procedure Expand_Interface_Thunk + (Prim : Entity_Id; + Thunk_Id : out Entity_Id; + Thunk_Code : out List_Id; + Iface : Entity_Id); + -- Ada 2005 (AI-251): When a tagged type implements abstract interfaces we + -- generate additional subprograms (thunks) associated with each primitive + -- Prim to have a layout compatible with the C++ ABI. The thunk displaces + -- the pointers to the actuals that depend on the controlling type before + -- transferring control to the target subprogram. If there is no need to + -- generate the thunk, then Thunk_Id is set to Empty. Otherwise Thunk_Id + -- is set to the defining identifier of the thunk and Thunk_Code to the + -- code generated for the thunk respectively. + + procedure Expand_Secondary_Stack_Thunk + (Prim : Entity_Id; + Thunk_Id : out Entity_Id; + Thunk_Code : out Node_Id); + -- When a primitive function of a tagged type can dispatch on result and + -- the tagged type is not returned on the secondary stack, we generate an + -- additional function (thunk) that calls the primitive function with the + -- same actuals and move its result onto the secondary stack. This thunk + -- is intended to be put into the slot of the primitive function in the + -- dispatch table, so as to be invoked in lieu of the primitive function + -- in dispatching calls. If there is no need to generate the thunk, then + -- Thunk_Id is set to Empty. Otherwise Thunk_Id is set to the defining + -- identifier of the thunk and Thunk_Code to the code generated for the + -- thunk respectively. + function Has_DT (Typ : Entity_Id) return Boolean; pragma Inline (Has_DT); -- Returns true if we generate a dispatch table for tagged type Typ @@ -358,6 +387,12 @@ package body Exp_Disp is procedure Build_Package_Dispatch_Tables (N : Node_Id); -- Build static dispatch tables associated with package declaration N + procedure Make_And_Insert_Dispatch_Table (Typ : Entity_Id); + -- Build the dispatch table of the tagged type Typ and insert it at the + -- end of Target_List after wrapping it in the Actions list of a freeze + -- node, so that it is skipped by Sem_Elab (Expand_Freeze_Record_Type + -- does the same for nonstatic dispatch tables). + --------------------------- -- Build_Dispatch_Tables -- --------------------------- @@ -410,8 +445,7 @@ package body Exp_Disp is then null; else - Insert_List_After_And_Analyze (Last (Target_List), - Make_DT (Defining_Entity (D))); + Make_And_Insert_Dispatch_Table (Defining_Entity (D)); end if; -- Handle private types of library level tagged types. We must @@ -434,8 +468,7 @@ package body Exp_Disp is and then not Is_Concurrent_Type (E2) then Exchange_Declarations (E1); - Insert_List_After_And_Analyze (Last (Target_List), - Make_DT (E1)); + Make_And_Insert_Dispatch_Table (E1); Exchange_Declarations (E2); end if; end; @@ -469,15 +502,28 @@ package body Exp_Disp is Pop_Scope; end Build_Package_Dispatch_Tables; + ------------------------------------ + -- Make_And_Insert_Dispatch_Table -- + ------------------------------------ + + procedure Make_And_Insert_Dispatch_Table (Typ : Entity_Id) is + F_Typ : constant Entity_Id := Create_Itype (E_Class_Wide_Type, Typ); + -- The code generator discards freeze nodes of CW types after + -- evaluating their side effects, so create an artificial one. + + F_Nod : constant Node_Id := Make_Freeze_Entity (Sloc (Typ)); + + begin + Set_Is_Frozen (F_Typ); + Set_Entity (F_Nod, F_Typ); + Set_Actions (F_Nod, Make_DT (Typ)); + + Insert_After_And_Analyze (Last (Target_List), F_Nod); + end Make_And_Insert_Dispatch_Table; + -- Start of processing for Build_Static_Dispatch_Tables begin - if not Expander_Active - or else not Tagged_Type_Expansion - then - return; - end if; - if Nkind (N) = N_Package_Declaration then declare Spec : constant Node_Id := Specification (N); @@ -501,8 +547,15 @@ package body Exp_Disp is end; else pragma Assert (Nkind (N) = N_Package_Body); - Target_List := Declarations (N); - Build_Dispatch_Tables (Target_List); + declare + Spec_Id : constant Entity_Id := Corresponding_Spec (N); + + begin + Push_Scope (Spec_Id); + Target_List := Declarations (N); + Build_Dispatch_Tables (Target_List); + Pop_Scope; + end; end if; end Build_Static_Dispatch_Tables; @@ -690,7 +743,6 @@ package body Exp_Disp is New_Call_Name : Node_Id; New_Params : List_Id := No_List; Param : Node_Id; - Res_Typ : Entity_Id; Subp_Ptr_Typ : Entity_Id; Subp_Typ : Entity_Id; Typ : Entity_Id; @@ -838,21 +890,20 @@ package body Exp_Disp is end loop; end if; - -- Generate the appropriate subprogram pointer type + -- Generate the appropriate subprogram designated type + + Subp_Typ := Create_Itype (E_Subprogram_Type, Call_Node); + Copy_Strub_Mode (Subp_Typ, Subp); + Set_Convention (Subp_Typ, Convention (Subp)); if Etype (Subp) = Typ then - Res_Typ := CW_Typ; + Set_Etype (Subp_Typ, CW_Typ); + Set_Returns_By_Ref (Subp_Typ, True); else - Res_Typ := Etype (Subp); + Set_Etype (Subp_Typ, Etype (Subp)); + Set_Returns_By_Ref (Subp_Typ, Returns_By_Ref (Subp)); end if; - Subp_Typ := Create_Itype (E_Subprogram_Type, Call_Node); - Copy_Strub_Mode (Subp_Typ, Subp); - Subp_Ptr_Typ := Create_Itype (E_Access_Subprogram_Type, Call_Node); - Set_Etype (Subp_Typ, Res_Typ); - Set_Returns_By_Ref (Subp_Typ, Returns_By_Ref (Subp)); - Set_Convention (Subp_Typ, Convention (Subp)); - -- Notify gigi that the designated type is a dispatching primitive Set_Is_Dispatch_Table_Entity (Subp_Typ); @@ -949,14 +1000,13 @@ package body Exp_Disp is end if; end; - -- Complete description of pointer type, including size information, as - -- must be done with itypes to prevent order-of-elaboration anomalies - -- in gigi. + -- Generate the appropriate subprogram pointer type and decorate it - Set_Etype (Subp_Ptr_Typ, Subp_Ptr_Typ); + Subp_Ptr_Typ := Create_Itype (E_Access_Subprogram_Type, Call_Node); + Set_Etype (Subp_Ptr_Typ, Subp_Ptr_Typ); Set_Directly_Designated_Type (Subp_Ptr_Typ, Subp_Typ); - Set_Convention (Subp_Ptr_Typ, Convention (Subp_Typ)); - Layout_Type (Subp_Ptr_Typ); + Set_Convention (Subp_Ptr_Typ, Convention (Subp_Typ)); + Layout_Type (Subp_Ptr_Typ); -- If the controlling argument is a value of type Ada.Tag or an abstract -- interface class-wide type then use it directly. Otherwise, the tag @@ -1731,49 +1781,50 @@ package body Exp_Disp is ---------------------------- procedure Expand_Interface_Thunk - (Prim : Node_Id; + (Prim : Entity_Id; Thunk_Id : out Entity_Id; - Thunk_Code : out Node_Id; + Thunk_Code : out List_Id; Iface : Entity_Id) is - Loc : constant Source_Ptr := Sloc (Prim); - Actuals : constant List_Id := New_List; - Decl : constant List_Id := New_List; - Formals : constant List_Id := New_List; - Target : constant Entity_Id := Ultimate_Alias (Prim); + Actuals : constant List_Id := New_List; + Decl : constant List_Id := New_List; + Formals : constant List_Id := New_List; + Loc : constant Source_Ptr := Sloc (Prim); + Target : constant Entity_Id := Ultimate_Alias (Prim); + Is_Predef_Op : constant Boolean := + Is_Predefined_Dispatching_Operation (Prim) + or else Is_Predefined_Dispatching_Operation (Target); Decl_1 : Node_Id; Decl_2 : Node_Id; Expr : Node_Id; - Formal : Node_Id; + Formal : Entity_Id; Ftyp : Entity_Id; - Iface_Formal : Node_Id := Empty; -- initialize to prevent warning - Is_Predef_Op : constant Boolean := - Is_Predefined_Dispatching_Operation (Prim) - or else Is_Predefined_Dispatching_Operation (Target); + Iface_Formal : Entity_Id; New_Arg : Node_Id; Offset_To_Top : Node_Id; Target_Formal : Entity_Id; begin Thunk_Id := Empty; - Thunk_Code := Empty; + Thunk_Code := Empty_List; -- No thunk needed if the primitive has been eliminated if Is_Eliminated (Target) then return; - -- In case of primitives that are functions without formals and a - -- controlling result there is no need to build the thunk. + -- No thunk needed if the primitive has no formals. In this case, this + -- must be a function with a controlling result. - elsif not Present (First_Formal (Target)) then + elsif No (First_Formal (Target)) then pragma Assert (Ekind (Target) = E_Function and then Has_Controlling_Result (Target)); + return; end if; - -- Duplicate the formals of the Target primitive. In the thunk, the type + -- Duplicate the formals of the target primitive. In the thunk, the type -- of the controlling formal is the covered interface type (instead of -- the target tagged type). Done to avoid problems with discriminated -- tagged types because, if the controlling type has discriminants with @@ -1785,14 +1836,14 @@ package body Exp_Disp is -- because they don't have available the Interface_Alias attribute (see -- Sem_Ch3.Add_Internal_Interface_Entities). - if not Is_Predef_Op then + if Is_Predef_Op then + Iface_Formal := Empty; + else Iface_Formal := First_Formal (Interface_Alias (Prim)); end if; Formal := First_Formal (Target); while Present (Formal) loop - Ftyp := Etype (Formal); - -- Use the interface type as the type of the controlling formal (see -- comment above). @@ -1814,10 +1865,10 @@ package body Exp_Disp is -- Sanity check performed to ensure the proper controlling type -- when the thunk has exactly one controlling parameter and it - -- comes first. In such case the GCC backend reuses the C++ + -- comes first. In such a case, the GCC back end reuses the C++ -- thunks machinery which perform a computation equivalent to -- the code generated by the expander; for other cases the GCC - -- backend translates the expanded code unmodified. However, as + -- back end translates the expanded code unmodified. However, as -- a generalization, the check is performed for all controlling -- types. @@ -1835,6 +1886,7 @@ package body Exp_Disp is Defining_Identifier => Make_Defining_Identifier (Sloc (Formal), Chars => Chars (Formal)), + Aliased_Present => Aliased_Present (Parent (Formal)), In_Present => In_Present (Parent (Formal)), Out_Present => Out_Present (Parent (Formal)), Parameter_Type => New_Occurrence_Of (Ftyp, Loc), @@ -2024,14 +2076,17 @@ package body Exp_Disp is Mutate_Ekind (Thunk_Id, Ekind (Prim)); Set_Is_Thunk (Thunk_Id); + Set_Has_Controlling_Result (Thunk_Id, False); Set_Convention (Thunk_Id, Convention (Prim)); Set_Needs_Debug_Info (Thunk_Id, Needs_Debug_Info (Target)); Set_Thunk_Entity (Thunk_Id, Target); + Thunk_Code := New_List; + -- Procedure case if Ekind (Target) = E_Procedure then - Thunk_Code := + Append_To (Thunk_Code, Make_Subprogram_Body (Loc, Specification => Make_Procedure_Specification (Loc, @@ -2043,14 +2098,16 @@ package body Exp_Disp is Statements => New_List ( Make_Procedure_Call_Statement (Loc, Name => New_Occurrence_Of (Target, Loc), - Parameter_Associations => Actuals)))); + Parameter_Associations => Actuals))))); -- Function case else pragma Assert (Ekind (Target) = E_Function); declare - Result_Def : Node_Id; - Call_Node : Node_Id; + Call_Node : Node_Id; + Result_Def : Node_Id; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; begin Call_Node := @@ -2084,6 +2141,19 @@ package body Exp_Disp is -- function F (O : T) return T; else + Expand_Secondary_Stack_Thunk + (Target, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + Set_Thunk_Entity (Thunk_Id, SS_Thunk_Id); + Call_Node := + Make_Function_Call (Loc, + Name => + New_Occurrence_Of (SS_Thunk_Id, Loc), + Parameter_Associations => Actuals); + Append_To (Thunk_Code, SS_Thunk_Code); + end if; + Result_Def := New_Occurrence_Of (Class_Wide_Type (Etype (Prim)), Loc); @@ -2098,7 +2168,7 @@ package body Exp_Disp is Expression => Relocate_Node (Call_Node)); end if; - Thunk_Code := + Append_To (Thunk_Code, Make_Subprogram_Body (Loc, Specification => Make_Function_Specification (Loc, @@ -2109,11 +2179,135 @@ package body Exp_Disp is Handled_Statement_Sequence => Make_Handled_Sequence_Of_Statements (Loc, Statements => New_List ( - Make_Simple_Return_Statement (Loc, Call_Node)))); + Make_Simple_Return_Statement (Loc, Call_Node))))); end; end if; end Expand_Interface_Thunk; + ------------------------------------ + -- Expand_Secondary_Stack_Thunk -- + ------------------------------------ + + procedure Expand_Secondary_Stack_Thunk + (Prim : Entity_Id; + Thunk_Id : out Entity_Id; + Thunk_Code : out Node_Id) + is + Actuals : constant List_Id := New_List; + Formals : constant List_Id := New_List; + Loc : constant Source_Ptr := Sloc (Prim); + Typ : constant Entity_Id := Etype (Prim); + + Call_Node : Node_Id; + Expr : Node_Id; + Formal : Entity_Id; + Prim_Formal : Entity_Id; + Result_Def : Node_Id; + + begin + Thunk_Id := Empty; + Thunk_Code := Empty; + + -- No thunk needed if the primitive has been eliminated + + if Is_Eliminated (Prim) then + return; + + -- No thunk needed for procedures or functions not dispatching on result + + elsif Ekind (Prim) = E_Procedure + or else not Has_Controlling_Result (Prim) + then + return; + + -- No thunk needed if the result type is an access type + + elsif Is_Access_Type (Typ) then + return; + + -- No thunk needed if the tagged type is returned in place + + elsif Is_Build_In_Place_Result_Type (Typ) then + return; + + -- No thunk needed if the tagged type is returned on the secondary stack + + elsif Needs_Secondary_Stack (Typ) then + return; + end if; + + pragma Assert (Is_Tagged_Type (Typ)); + + -- Duplicate the formals of the target primitive and build the actuals + + Prim_Formal := First_Formal (Prim); + while Present (Prim_Formal) loop + Expr := New_Copy_Tree (Expression (Parent (Prim_Formal))); + + Formal := + Make_Defining_Identifier (Sloc (Prim_Formal), + Chars => Chars (Prim_Formal)); + + Append_To (Formals, + Make_Parameter_Specification (Loc, + Defining_Identifier => Formal, + Aliased_Present => Aliased_Present (Parent (Prim_Formal)), + In_Present => In_Present (Parent (Prim_Formal)), + Out_Present => Out_Present (Parent (Prim_Formal)), + Parameter_Type => New_Occurrence_Of (Etype (Prim_Formal), Loc), + Expression => Expr)); + + -- Ensure proper matching of access types. Required to avoid + -- reporting spurious errors. + + if Is_Access_Type (Etype (Prim_Formal)) then + Append_To (Actuals, + Unchecked_Convert_To (Base_Type (Etype (Prim_Formal)), + New_Occurrence_Of (Formal, Loc))); + + -- No special management required for this actual + + else + Append_To (Actuals, New_Occurrence_Of (Formal, Loc)); + end if; + + Next_Formal (Prim_Formal); + end loop; + + Thunk_Id := Make_Temporary (Loc, 'T'); + + -- Note: any change to this symbol name needs to be coordinated + -- with GNATcoverage, as that tool relies on it to identify + -- thunks and exclude them from source coverage analysis. + + Mutate_Ekind (Thunk_Id, E_Function); + Set_Is_Thunk (Thunk_Id); + Set_Has_Controlling_Result (Thunk_Id, True); + Set_Convention (Thunk_Id, Convention (Prim)); + Set_Needs_Debug_Info (Thunk_Id, Needs_Debug_Info (Prim)); + Set_Thunk_Entity (Thunk_Id, Prim); + + Result_Def := New_Copy (Result_Definition (Parent (Prim))); + + Call_Node := + Make_Function_Call (Loc, + Name => New_Occurrence_Of (Prim, Loc), + Parameter_Associations => Actuals); + + Thunk_Code := + Make_Subprogram_Body (Loc, + Specification => + Make_Function_Specification (Loc, + Defining_Unit_Name => Thunk_Id, + Parameter_Specifications => Formals, + Result_Definition => Result_Def), + Declarations => Empty_List, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => New_List ( + Make_Simple_Return_Statement (Loc, Call_Node)))); + end Expand_Secondary_Stack_Thunk; + -------------------------- -- Has_CPP_Constructors -- -------------------------- @@ -3830,11 +4024,14 @@ package body Exp_Disp is -- save their entity to fill the aggregate. declare - Nb_P_Prims : constant Nat := Number_Of_Predefined_Prims (Typ); - Prim_Table : array (Nat range 1 .. Nb_P_Prims) of Entity_Id; - Decl : Node_Id; - Thunk_Id : Entity_Id; - Thunk_Code : Node_Id; + Nb_P_Prims : constant Nat := Number_Of_Predefined_Prims (Typ); + Prim_Table : array (Nat range 1 .. Nb_P_Prims) of Entity_Id; + Decl : Node_Id; + E : Entity_Id; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; + Thunk_Id : Entity_Id; + Thunk_Code : List_Id; begin Prim_Ops_Aggr_List := New_List; @@ -3849,19 +4046,27 @@ package body Exp_Disp is and then not Is_Abstract_Subprogram (Prim) and then not Is_Eliminated (Prim) and then not Generate_SCIL - and then not Present (Prim_Table - (UI_To_Int (DT_Position (Prim)))) + and then not + Present (Prim_Table (UI_To_Int (DT_Position (Prim)))) then if not Build_Thunks then - Prim_Table (UI_To_Int (DT_Position (Prim))) := - Alias (Prim); + E := Ultimate_Alias (Prim); + Expand_Secondary_Stack_Thunk + (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (Result, SS_Thunk_Code); + end if; + + Prim_Table (UI_To_Int (DT_Position (Prim))) := E; else Expand_Interface_Thunk (Prim, Thunk_Id, Thunk_Code, Iface); if Present (Thunk_Id) then - Append_To (Result, Thunk_Code); + Append_List_To (Result, Thunk_Code); Prim_Table (UI_To_Int (DT_Position (Prim))) := Thunk_Id; end if; @@ -4004,17 +4209,20 @@ package body Exp_Disp is OSD_Aggr_List := New_List; declare - Prim_Table : array (Nat range 1 .. Nb_Prim) of Entity_Id; - Prim : Entity_Id; - Prim_Alias : Entity_Id; - Prim_Elmt : Elmt_Id; - E : Entity_Id; - Count : Nat := 0; - Pos : Nat; + Prim_Table : array (Nat range 1 .. Nb_Prim) of Entity_Id; + Prim : Entity_Id; + Prim_Alias : Entity_Id; + Prim_Elmt : Elmt_Id; + E : Entity_Id; + Count : Nat; + Pos : Nat; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; begin Prim_Table := (others => Empty); Prim_Alias := Empty; + Count := 0; Prim_Elmt := First_Elmt (Primitive_Operations (Typ)); while Present (Prim_Elmt) loop @@ -4028,11 +4236,15 @@ package body Exp_Disp is E := Ultimate_Alias (Prim); Pos := UI_To_Int (DT_Position (Prim_Alias)); - if Present (Prim_Table (Pos)) then - pragma Assert (Prim_Table (Pos) = E); - null; + if No (Prim_Table (Pos)) then + Expand_Secondary_Stack_Thunk + (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (Result, SS_Thunk_Code); + end if; - else Prim_Table (Pos) := E; Append_To (OSD_Aggr_List, @@ -4120,12 +4332,14 @@ package body Exp_Disp is else declare - CPP_Nb_Prims : constant Nat := CPP_Num_Prims (Typ); - E : Entity_Id; - Prim_Pos : Nat; - Prim_Table : array (Nat range 1 .. Nb_Prim) of Entity_Id; - Thunk_Code : Node_Id; - Thunk_Id : Entity_Id; + CPP_Nb_Prims : constant Nat := CPP_Num_Prims (Typ); + E : Entity_Id; + Prim_Pos : Nat; + Prim_Table : array (Nat range 1 .. Nb_Prim) of Entity_Id; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; + Thunk_Id : Entity_Id; + Thunk_Code : List_Id; begin Prim_Table := (others => Empty); @@ -4160,9 +4374,18 @@ package body Exp_Disp is Use_Full_View => True) then if not Build_Thunks then + E := Alias (Prim); + Expand_Secondary_Stack_Thunk + (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (Result, SS_Thunk_Code); + end if; + Prim_Pos := UI_To_Int (DT_Position (Interface_Alias (Prim))); - Prim_Table (Prim_Pos) := Alias (Prim); + Prim_Table (Prim_Pos) := E; else Expand_Interface_Thunk @@ -4173,7 +4396,7 @@ package body Exp_Disp is UI_To_Int (DT_Position (Interface_Alias (Prim))); Prim_Table (Prim_Pos) := Thunk_Id; - Append_To (Result, Thunk_Code); + Append_List_To (Result, Thunk_Code); end if; end if; end if; @@ -5623,10 +5846,12 @@ package body Exp_Disp is else declare - Nb_P_Prims : constant Nat := Number_Of_Predefined_Prims (Typ); - Prim_Table : array (Nat range 1 .. Nb_P_Prims) of Entity_Id; - Decl : Node_Id; - E : Entity_Id; + Nb_P_Prims : constant Nat := Number_Of_Predefined_Prims (Typ); + Prim_Table : array (Nat range 1 .. Nb_P_Prims) of Entity_Id; + Decl : Node_Id; + E : Entity_Id; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; begin Prim_Ops_Aggr_List := New_List; @@ -5646,6 +5871,15 @@ package body Exp_Disp is then E := Ultimate_Alias (Prim); pragma Assert (not Is_Abstract_Subprogram (E)); + + Expand_Secondary_Stack_Thunk + (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (Result, SS_Thunk_Code); + end if; + Prim_Table (UI_To_Int (DT_Position (Prim))) := E; end if; @@ -5756,12 +5990,14 @@ package body Exp_Disp is else declare - CPP_Nb_Prims : constant Nat := CPP_Num_Prims (Typ); - E : Entity_Id; - Prim : Entity_Id; - Prim_Elmt : Elmt_Id; - Prim_Pos : Nat; - Prim_Table : array (Nat range 1 .. Nb_Prim) of Entity_Id; + CPP_Nb_Prims : constant Nat := CPP_Num_Prims (Typ); + E : Entity_Id; + Prim : Entity_Id; + Prim_Elmt : Elmt_Id; + Prim_Pos : Nat; + Prim_Table : array (Nat range 1 .. Nb_Prim) of Entity_Id; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; begin Prim_Table := (others => Empty); @@ -5818,6 +6054,14 @@ package body Exp_Disp is pragma Assert (UI_To_Int (DT_Position (Prim)) <= Nb_Prim); + Expand_Secondary_Stack_Thunk + (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (Result, SS_Thunk_Code); + end if; + Prim_Table (UI_To_Int (DT_Position (Prim))) := E; end if; @@ -7107,6 +7351,107 @@ package body Exp_Disp is end if; end Prim_Op_Kind; + ----------------------------------- + -- Register_Predefined_Primitive -- + ----------------------------------- + + function Register_Predefined_Primitive + (Loc : Source_Ptr; + Prim : Entity_Id) return List_Id + is + L : constant List_Id := New_List; + Tagged_Typ : constant Entity_Id := Find_Dispatching_Type (Prim); + + E : Entity_Id; + Iface_DT_Ptr : Elmt_Id; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; + Thunk_Id : Entity_Id; + Thunk_Code : List_Id; + + begin + if No (Access_Disp_Table (Tagged_Typ)) + or else not Has_Interfaces (Tagged_Typ) + or else not RTE_Available (RE_Interface_Tag) + or else Restriction_Active (No_Dispatching_Calls) + then + return L; + end if; + + -- Skip the first two access-to-dispatch-table pointers since they + -- leads to the primary dispatch table (predefined DT and user + -- defined DT). We are only concerned with the secondary dispatch + -- table pointers. Note that the access-to- dispatch-table pointer + -- corresponds to the first implemented interface retrieved below. + + Iface_DT_Ptr := + Next_Elmt (Next_Elmt (First_Elmt (Access_Disp_Table (Tagged_Typ)))); + + while Present (Iface_DT_Ptr) + and then Ekind (Node (Iface_DT_Ptr)) = E_Constant + loop + pragma Assert (Has_Thunks (Node (Iface_DT_Ptr))); + + Expand_Interface_Thunk + (Prim, Thunk_Id, Thunk_Code, Related_Type (Node (Iface_DT_Ptr))); + + if Present (Thunk_Id) then + Append_List_To (L, Thunk_Code); + + E := Prim; + Expand_Secondary_Stack_Thunk (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (L, SS_Thunk_Code); + end if; + + Append_To (L, + Build_Set_Predefined_Prim_Op_Address (Loc, + Tag_Node => + New_Occurrence_Of (Node (Next_Elmt (Iface_DT_Ptr)), Loc), + Position => DT_Position (Prim), + Address_Node => + Unchecked_Convert_To (RTE (RE_Prim_Ptr), + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Thunk_Id, Loc), + Attribute_Name => Name_Unrestricted_Access)))); + + Append_To (L, + Build_Set_Predefined_Prim_Op_Address (Loc, + Tag_Node => + New_Occurrence_Of + (Node (Next_Elmt (Next_Elmt (Next_Elmt (Iface_DT_Ptr)))), + Loc), + Position => DT_Position (Prim), + Address_Node => + Unchecked_Convert_To (RTE (RE_Prim_Ptr), + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (E, Loc), + Attribute_Name => Name_Unrestricted_Access)))); + end if; + + -- Skip the tag of the predefined primitives dispatch table + + Next_Elmt (Iface_DT_Ptr); + pragma Assert (Has_Thunks (Node (Iface_DT_Ptr))); + + -- Skip tag of the no-thunks dispatch table + + Next_Elmt (Iface_DT_Ptr); + pragma Assert (not Has_Thunks (Node (Iface_DT_Ptr))); + + -- Skip tag of predefined primitives no-thunks dispatch table + + Next_Elmt (Iface_DT_Ptr); + pragma Assert (not Has_Thunks (Node (Iface_DT_Ptr))); + + Next_Elmt (Iface_DT_Ptr); + end loop; + + return L; + end Register_Predefined_Primitive; + ------------------------ -- Register_Primitive -- ------------------------ @@ -7115,22 +7460,26 @@ package body Exp_Disp is (Loc : Source_Ptr; Prim : Entity_Id) return List_Id is + L : constant List_Id := New_List; + DT_Ptr : Entity_Id; + E : Entity_Id; Iface_Prim : Entity_Id; Iface_Typ : Entity_Id; Iface_DT_Ptr : Entity_Id; Iface_DT_Elmt : Elmt_Id; - L : constant List_Id := New_List; Pos : Uint; + SS_Thunk_Id : Entity_Id; + SS_Thunk_Code : Node_Id; Tag : Entity_Id; Tag_Typ : Entity_Id; Thunk_Id : Entity_Id; - Thunk_Code : Node_Id; + Thunk_Code : List_Id; begin pragma Assert (not Restriction_Active (No_Dispatching_Calls)); - -- Do not register in the dispatch table eliminated primitives + -- Do not register eliminated primitives in the dispatch table if not RTE_Available (RE_Tag) or else Is_Eliminated (Ultimate_Alias (Prim)) @@ -7139,10 +7488,20 @@ package body Exp_Disp is return L; end if; + -- Primitive associated with a tagged type + if not Present (Interface_Alias (Prim)) then Tag_Typ := Scope (DTC_Entity (Prim)); - Pos := DT_Position (Prim); - Tag := First_Tag_Component (Tag_Typ); + Pos := DT_Position (Prim); + Tag := First_Tag_Component (Tag_Typ); + + E := Prim; + Expand_Secondary_Stack_Thunk (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (L, SS_Thunk_Code); + end if; if Is_Predefined_Dispatching_Operation (Prim) or else Is_Predefined_Dispatching_Alias (Prim) @@ -7157,7 +7516,7 @@ package body Exp_Disp is Address_Node => Unchecked_Convert_To (RTE (RE_Prim_Ptr), Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (Prim, Loc), + Prefix => New_Occurrence_Of (E, Loc), Attribute_Name => Name_Unrestricted_Access)))); -- Register copy of the pointer to the 'size primitive in the TSD @@ -7190,7 +7549,7 @@ package body Exp_Disp is Address_Node => Unchecked_Convert_To (RTE (RE_Prim_Ptr), Make_Attribute_Reference (Loc, - Prefix => New_Occurrence_Of (Prim, Loc), + Prefix => New_Occurrence_Of (E, Loc), Attribute_Name => Name_Unrestricted_Access)))); end if; end if; @@ -7227,8 +7586,8 @@ package body Exp_Disp is Expand_Interface_Thunk (Prim, Thunk_Id, Thunk_Code, Iface_Typ); - if not Is_Ancestor (Iface_Typ, Tag_Typ, Use_Full_View => True) - and then Present (Thunk_Code) + if Present (Thunk_Id) + and then not Is_Ancestor (Iface_Typ, Tag_Typ, Use_Full_View => True) then -- Generate the code necessary to fill the appropriate entry of -- the secondary dispatch table of Prim's controlling type with @@ -7242,7 +7601,15 @@ package body Exp_Disp is Pos := DT_Position (Iface_Prim); Tag := First_Tag_Component (Iface_Typ); - Prepend_To (L, Thunk_Code); + Append_List_To (L, Thunk_Code); + + E := Ultimate_Alias (Prim); + Expand_Secondary_Stack_Thunk (E, SS_Thunk_Id, SS_Thunk_Code); + + if Present (SS_Thunk_Id) then + E := SS_Thunk_Id; + Append_To (L, SS_Thunk_Code); + end if; if Is_Predefined_Dispatching_Operation (Prim) or else Is_Predefined_Dispatching_Alias (Prim) @@ -7271,8 +7638,7 @@ package body Exp_Disp is Address_Node => Unchecked_Convert_To (RTE (RE_Prim_Ptr), Make_Attribute_Reference (Loc, - Prefix => - New_Occurrence_Of (Alias (Prim), Loc), + Prefix => New_Occurrence_Of (E, Loc), Attribute_Name => Name_Unrestricted_Access)))); else @@ -7303,8 +7669,7 @@ package body Exp_Disp is Address_Node => Unchecked_Convert_To (RTE (RE_Prim_Ptr), Make_Attribute_Reference (Loc, - Prefix => - New_Occurrence_Of (Ultimate_Alias (Prim), Loc), + Prefix => New_Occurrence_Of (E, Loc), Attribute_Name => Name_Unrestricted_Access)))); end if; diff --git a/gcc/ada/exp_disp.ads b/gcc/ada/exp_disp.ads index 96eae30..a02e4498 100644 --- a/gcc/ada/exp_disp.ads +++ b/gcc/ada/exp_disp.ads @@ -233,20 +233,6 @@ package Exp_Disp is -- to the object to give access to the interface tag associated with the -- dispatch table of the target type. - procedure Expand_Interface_Thunk - (Prim : Node_Id; - Thunk_Id : out Entity_Id; - Thunk_Code : out Node_Id; - Iface : Entity_Id); - -- Ada 2005 (AI-251): When a tagged type implements abstract interfaces we - -- generate additional subprograms (thunks) associated with each primitive - -- Prim to have a layout compatible with the C++ ABI. The thunk displaces - -- the pointers to the actuals that depend on the controlling type before - -- transferring control to the target subprogram. If there is no need to - -- generate the thunk then Thunk_Id and Thunk_Code are set to Empty. - -- Otherwise they are set to the defining identifier and the subprogram - -- body of the generated thunk. - function Has_CPP_Constructors (Typ : Entity_Id) return Boolean; -- Returns true if the type has CPP constructors @@ -337,6 +323,15 @@ package Exp_Disp is -- tagged types this routine imports the forward declaration of the tag -- entity, that will be declared and exported by Make_DT. + function Register_Predefined_Primitive + (Loc : Source_Ptr; + Prim : Entity_Id) return List_Id; + -- Ada 2005: Register a predefined primitive in all the secondary dispatch + -- tables of its primitive type. + -- + -- The caller is responsible for inserting the generated code in the + -- proper place. + function Register_Primitive (Loc : Source_Ptr; Prim : Entity_Id) return List_Id; diff --git a/gcc/ada/exp_strm.adb b/gcc/ada/exp_strm.adb index 6eaef4e..d7a73f5 100644 --- a/gcc/ada/exp_strm.adb +++ b/gcc/ada/exp_strm.adb @@ -1548,37 +1548,32 @@ package body Exp_Strm is function Make_Field_Attributes (Clist : List_Id) return List_Id is Item : Node_Id; - Result : List_Id; + Result : constant List_Id := New_List; begin - Result := New_List; - - if Present (Clist) then - Item := First (Clist); - - -- Loop through components, skipping all internal components, - -- which are not part of the value (e.g. _Tag), except that we - -- don't skip the _Parent, since we do want to process that - -- recursively. If _Parent is an interface type, being abstract - -- with no components there is no need to handle it. - - while Present (Item) loop - if Nkind (Item) = N_Component_Declaration - and then - ((Chars (Defining_Identifier (Item)) = Name_uParent - and then not Is_Interface - (Etype (Defining_Identifier (Item)))) - or else - not Is_Internal_Name (Chars (Defining_Identifier (Item)))) - then - Append_To - (Result, - Make_Field_Attribute (Defining_Identifier (Item))); - end if; - - Next (Item); - end loop; - end if; + -- Loop through components, skipping all internal components, which + -- are not part of the value (e.g. _Tag), except that we don't skip + -- the _Parent, since we do want to process that recursively. If + -- _Parent is an interface type, being abstract with no components + -- there is no need to handle it. + + Item := First (Clist); + while Present (Item) loop + if Nkind (Item) = N_Component_Declaration + and then + ((Chars (Defining_Identifier (Item)) = Name_uParent + and then not Is_Interface + (Etype (Defining_Identifier (Item)))) + or else + not Is_Internal_Name (Chars (Defining_Identifier (Item)))) + then + Append_To + (Result, + Make_Field_Attribute (Defining_Identifier (Item))); + end if; + + Next (Item); + end loop; return Result; end Make_Field_Attributes; diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb index 290c380..0f19318 100644 --- a/gcc/ada/exp_util.adb +++ b/gcc/ada/exp_util.adb @@ -8368,9 +8368,10 @@ package body Exp_Util is function Initialized_By_Aliased_BIP_Func_Call (Trans_Id : Entity_Id) return Boolean; -- Determine whether transient object Trans_Id is initialized by a - -- build-in-place function call where the BIPalloc parameter is of - -- value 1 and BIPaccess is not null. This case creates an aliasing - -- between the returned value and the value denoted by BIPaccess. + -- build-in-place function call where the BIPalloc parameter either + -- does not exist or is Caller_Allocation, and BIPaccess is not null. + -- This case creates an aliasing between the returned value and the + -- value denoted by BIPaccess. function Is_Aliased (Trans_Id : Entity_Id; @@ -8427,11 +8428,14 @@ package body Exp_Util is if Is_Build_In_Place_Function_Call (Call) then declare + Caller_Allocation_Val : constant Uint := + UI_From_Int (BIP_Allocation_Form'Pos (Caller_Allocation)); + Access_Nam : Name_Id := No_Name; Access_OK : Boolean := False; Actual : Node_Id; Alloc_Nam : Name_Id := No_Name; - Alloc_OK : Boolean := False; + Alloc_OK : Boolean := True; Formal : Node_Id; Func_Id : Entity_Id; Param : Node_Id; @@ -8466,7 +8470,7 @@ package body Exp_Util is BIP_Formal_Suffix (BIP_Alloc_Form)); end if; - -- A match for BIPaccess => Temp has been found + -- A nonnull BIPaccess has been found if Chars (Formal) = Access_Nam and then Nkind (Actual) /= N_Null @@ -8474,13 +8478,12 @@ package body Exp_Util is Access_OK := True; end if; - -- A match for BIPalloc => 1 has been found + -- A BIPalloc has been found if Chars (Formal) = Alloc_Nam and then Nkind (Actual) = N_Integer_Literal - and then Intval (Actual) = Uint_1 then - Alloc_OK := True; + Alloc_OK := Intval (Actual) = Caller_Allocation_Val; end if; end if; @@ -8767,7 +8770,6 @@ package body Exp_Util is return Ekind (Obj_Id) in E_Constant | E_Variable and then Needs_Finalization (Desig) - and then Requires_Transient_Scope (Desig) and then Nkind (Rel_Node) /= N_Simple_Return_Statement and then not Is_Part_Of_BIP_Return_Statement (Rel_Node) @@ -9292,6 +9294,17 @@ package body Exp_Util is return False; end Is_Secondary_Stack_BIP_Func_Call; + ------------------------------ + -- Is_Secondary_Stack_Thunk -- + ------------------------------ + + function Is_Secondary_Stack_Thunk (Id : Entity_Id) return Boolean is + begin + return Ekind (Id) = E_Function + and then Is_Thunk (Id) + and then Has_Controlling_Result (Id); + end Is_Secondary_Stack_Thunk; + ------------------------------------- -- Is_Tag_To_Class_Wide_Conversion -- ------------------------------------- @@ -14057,6 +14070,23 @@ package body Exp_Util is end if; end Small_Integer_Type_For; + ------------------ + -- Thunk_Target -- + ------------------ + + function Thunk_Target (Thunk : Entity_Id) return Entity_Id is + Target : Entity_Id := Thunk; + + begin + pragma Assert (Is_Thunk (Thunk)); + + while Is_Thunk (Target) loop + Target := Thunk_Entity (Target); + end loop; + + return Target; + end Thunk_Target; + ------------------- -- Type_Map_Hash -- ------------------- diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads index 464f66f..e812ca0 100644 --- a/gcc/ada/exp_util.ads +++ b/gcc/ada/exp_util.ads @@ -837,6 +837,11 @@ package Exp_Util is -- Determine whether Expr denotes a build-in-place function which returns -- its result on the secondary stack. + function Is_Secondary_Stack_Thunk (Id : Entity_Id) return Boolean; + -- Determine whether Id denotes a secondary stack thunk + + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Is_Tag_To_Class_Wide_Conversion (Obj_Id : Entity_Id) return Boolean; -- Determine whether object Obj_Id is the result of a tag-to-class-wide @@ -1190,6 +1195,12 @@ package Exp_Util is -- Return the smallest standard integer type containing at least S bits and -- of the signedness given by Uns. + function Thunk_Target (Thunk : Entity_Id) return Entity_Id; + -- Return the entity ultimately called by the thunk, that is to say return + -- the Thunk_Entity of the last member on the thunk chain. + + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Type_May_Have_Bit_Aligned_Components (Typ : Entity_Id) return Boolean; -- Determines if Typ is a composite type that has within it (looking down @@ -1216,4 +1227,6 @@ private pragma Inline (Force_Evaluation); pragma Inline (Get_Mapped_Entity); pragma Inline (Is_Library_Level_Tagged_Type); + pragma Inline (Is_Secondary_Stack_Thunk); + pragma Inline (Thunk_Target); end Exp_Util; diff --git a/gcc/ada/fe.h b/gcc/ada/fe.h index bfd9054..983f6c3 100644 --- a/gcc/ada/fe.h +++ b/gcc/ada/fe.h @@ -182,13 +182,17 @@ extern Boolean Is_Init_Proc (Entity_Id); /* exp_util: */ +#define Find_Interface_Tag exp_util__find_interface_tag #define Is_Fully_Repped_Tagged_Type exp_util__is_fully_repped_tagged_type #define Is_Related_To_Func_Return exp_util__is_related_to_func_return -#define Find_Interface_Tag exp_util__find_interface_tag +#define Is_Secondary_Stack_Thunk exp_util__is_secondary_stack_thunk +#define Thunk_Target exp_util__thunk_target +extern Entity_Id Find_Interface_Tag (Entity_Id, Entity_Id); extern Boolean Is_Fully_Repped_Tagged_Type (Entity_Id); extern Boolean Is_Related_To_Func_Return (Entity_Id); -extern Entity_Id Find_Interface_Tag (Entity_Id, Entity_Id); +extern Boolean Is_Secondary_Stack_Thunk (Entity_Id); +extern Entity_Id Thunk_Target (Entity_Id); /* lib: */ @@ -203,7 +207,6 @@ extern Boolean In_Extended_Main_Code_Unit (Entity_Id); /* opt: */ #define Ada_Version opt__ada_version -#define Assume_No_Invalid_Values opt__assume_no_invalid_values #define Back_End_Inlining opt__back_end_inlining #define Debug_Generated_Code opt__debug_generated_code #define Enable_128bit_Types opt__enable_128bit_types @@ -220,7 +223,6 @@ typedef enum { } Ada_Version_Type; extern Ada_Version_Type Ada_Version; -extern Boolean Assume_No_Invalid_Values; extern Boolean Back_End_Inlining; extern Boolean Debug_Generated_Code; extern Boolean Enable_128bit_Types; @@ -299,15 +301,15 @@ extern Boolean Compile_Time_Known_Value (Node_Id); #define First_Actual sem_util__first_actual #define Is_Expression_Function sem_util__is_expression_function #define Is_Variable_Size_Record sem_util__is_variable_size_record +#define Needs_Secondary_Stack sem_util__needs_secondary_stack #define Next_Actual sem_util__next_actual -#define Returns_On_Secondary_Stack sem_util__returns_on_secondary_stack extern Entity_Id Defining_Entity (Node_Id); extern Node_Id First_Actual (Node_Id); extern Boolean Is_Expression_Function (Entity_Id); extern Boolean Is_Variable_Size_Record (Entity_Id); +extern Boolean Needs_Secondary_Stack (Entity_Id); extern Node_Id Next_Actual (Node_Id); -extern Boolean Returns_On_Secondary_Stack (Entity_Id); /* sinfo: */ diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb index f4ebf30..b7310a4 100644 --- a/gcc/ada/freeze.adb +++ b/gcc/ada/freeze.adb @@ -1458,7 +1458,8 @@ package body Freeze is N_Object_Declaration and then not Is_Imported (Entity (Nod)) and then not Has_Completion (Entity (Nod)) - and then not Is_Frozen (Entity (Nod)) + and then not (Present (Full_View (Entity (Nod))) + and then Has_Completion (Full_View (Entity (Nod)))) then Error_Msg_NE ("premature use of& in call or instance", N, Entity (Nod)); diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in index 8c34f42..6b19b8b 100644 --- a/gcc/ada/gcc-interface/Makefile.in +++ b/gcc/ada/gcc-interface/Makefile.in @@ -663,8 +663,8 @@ gnatlib: ../stamp-gnatlib1-$(RTSDIR) ../stamp-gnatlib2-$(RTSDIR) $(RTSDIR)/s-osc gnatlib-shared-default: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ - GNATLIBCFLAGS="$(GNATLIBCFLAGS) $(PICFLAG_FOR_TARGET)" \ - GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C) $(PICFLAG_FOR_TARGET)" \ + GNATLIBCFLAGS="$(GNATLIBCFLAGS) $(PICFLAG_FOR_TARGET) -fno-lto" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C) $(PICFLAG_FOR_TARGET) -fno-lto" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ LN_S="$(LN_S)" \ diff --git a/gcc/ada/gcc-interface/ada-tree.h b/gcc/ada/gcc-interface/ada-tree.h index ec52024..6d9639d 100644 --- a/gcc/ada/gcc-interface/ada-tree.h +++ b/gcc/ada/gcc-interface/ada-tree.h @@ -97,11 +97,6 @@ do { \ an Ada array other than the first. */ #define TYPE_MULTI_ARRAY_P(NODE) TYPE_LANG_FLAG_1 (ARRAY_TYPE_CHECK (NODE)) -/* For FUNCTION_TYPE and METHOD_TYPE, nonzero if function returns an - unconstrained array or record type. */ -#define TYPE_RETURN_UNCONSTRAINED_P(NODE) \ - TYPE_LANG_FLAG_1 (FUNC_OR_METHOD_CHECK (NODE)) - /* For RECORD_TYPE, UNION_TYPE, and QUAL_UNION_TYPE, nonzero if this denotes a justified modular type (will only be true for RECORD_TYPE). */ #define TYPE_JUSTIFIED_MODULAR_P(NODE) \ diff --git a/gcc/ada/gcc-interface/decl.cc b/gcc/ada/gcc-interface/decl.cc index 50d17f7..6e22feb 100644 --- a/gcc/ada/gcc-interface/decl.cc +++ b/gcc/ada/gcc-interface/decl.cc @@ -346,10 +346,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) && !present_gnu_tree (gnat_entity) && In_Extended_Main_Code_Unit (gnat_entity)) { - /* Ensure that we are in a subprogram mentioned in the Scope chain of + /* Unless it's for an anonymous access type, whose scope is irrelevant, + ensure that we are in a subprogram mentioned in the Scope chain of this entity, our current scope is global, or we encountered a task or entry (where we can't currently accurately check scoping). */ - if (!current_function_decl + if (Ekind (gnat_entity) == E_Anonymous_Access_Type + || !current_function_decl || DECL_ELABORATION_PROC_P (current_function_decl)) { process_type (gnat_entity); @@ -5807,7 +5809,6 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, bool pure_flag = Is_Pure (gnat_subprog); bool return_by_direct_ref_p = false; bool return_by_invisi_ref_p = false; - bool return_unconstrained_p = false; bool incomplete_profile_p = false; int num; @@ -5822,7 +5823,6 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, && !TYPE_IS_DUMMY_P (TREE_TYPE (gnu_type))) { gnu_return_type = TREE_TYPE (gnu_type); - return_unconstrained_p = TYPE_RETURN_UNCONSTRAINED_P (gnu_type); return_by_direct_ref_p = TYPE_RETURN_BY_DIRECT_REF_P (gnu_type); return_by_invisi_ref_p = TREE_ADDRESSABLE (gnu_type); } @@ -5838,38 +5838,16 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, else gnu_return_type = gnat_to_gnu_profile_type (gnat_return_type); - /* If this function returns by reference, make the actual return type - the reference type and make a note of that. */ - if (Returns_By_Ref (gnat_subprog)) + /* If this function returns by reference or on the secondary stack, make + the actual return type the reference type and make a note of that. */ + if (Returns_By_Ref (gnat_subprog) + || Needs_Secondary_Stack (gnat_return_type) + || Is_Secondary_Stack_Thunk (gnat_subprog)) { gnu_return_type = build_reference_type (gnu_return_type); return_by_direct_ref_p = true; } - /* If the return type is an unconstrained array type, the return value - will be allocated on the secondary stack so the actual return type - is the fat pointer type. */ - else if (TREE_CODE (gnu_return_type) == UNCONSTRAINED_ARRAY_TYPE) - { - gnu_return_type = TYPE_REFERENCE_TO (gnu_return_type); - return_unconstrained_p = true; - } - - /* This is the same unconstrained array case, but for a dummy type. */ - else if (TYPE_REFERENCE_TO (gnu_return_type) - && TYPE_IS_FAT_POINTER_P (TYPE_REFERENCE_TO (gnu_return_type))) - { - gnu_return_type = TYPE_REFERENCE_TO (gnu_return_type); - return_unconstrained_p = true; - } - - /* This is for the other types returned on the secondary stack. */ - else if (Returns_On_Secondary_Stack (gnat_return_type)) - { - gnu_return_type = build_reference_type (gnu_return_type); - return_unconstrained_p = true; - } - /* If the Mechanism is By_Reference, ensure this function uses the target's by-invisible-reference mechanism, which may not be the same as above (e.g. it might be passing an extra parameter). */ @@ -5949,8 +5927,7 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, } if (kind == E_Function) - Set_Mechanism (gnat_subprog, return_unconstrained_p - || return_by_direct_ref_p + Set_Mechanism (gnat_subprog, return_by_direct_ref_p || return_by_invisi_ref_p ? By_Reference : By_Copy); } @@ -5962,7 +5939,7 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, Similarly, if the function returns an unconstrained type, then the function will allocate the return value on the secondary stack and thus calls to it cannot be CSE'ed, lest the stack be reclaimed. */ - if (VOID_TYPE_P (gnu_return_type) || return_unconstrained_p) + if (VOID_TYPE_P (gnu_return_type) || return_by_direct_ref_p) pure_flag = false; /* Loop over the parameters and get their associated GCC tree. While doing @@ -6250,7 +6227,6 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, gnu_type = make_node (method_p ? METHOD_TYPE : FUNCTION_TYPE); TREE_TYPE (gnu_type) = gnu_return_type; TYPE_ARG_TYPES (gnu_type) = gnu_param_type_list; - TYPE_RETURN_UNCONSTRAINED_P (gnu_type) = return_unconstrained_p; TYPE_RETURN_BY_DIRECT_REF_P (gnu_type) = return_by_direct_ref_p; TREE_ADDRESSABLE (gnu_type) = return_by_invisi_ref_p; } @@ -6267,7 +6243,6 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, = TYPE_MAIN_VARIANT (gnu_basetype); } TYPE_CI_CO_LIST (gnu_type) = gnu_cico_list; - TYPE_RETURN_UNCONSTRAINED_P (gnu_type) = return_unconstrained_p; TYPE_RETURN_BY_DIRECT_REF_P (gnu_type) = return_by_direct_ref_p; TREE_ADDRESSABLE (gnu_type) = return_by_invisi_ref_p; TYPE_CANONICAL (gnu_type) = gnu_type; @@ -6289,13 +6264,11 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, /* GNU_TYPE may be shared since GCC hashes types. Unshare it if it has a different TYPE_CI_CO_LIST or flags. */ if (!fntype_same_flags_p (gnu_type, gnu_cico_list, - return_unconstrained_p, return_by_direct_ref_p, return_by_invisi_ref_p)) { gnu_type = copy_type (gnu_type); TYPE_CI_CO_LIST (gnu_type) = gnu_cico_list; - TYPE_RETURN_UNCONSTRAINED_P (gnu_type) = return_unconstrained_p; TYPE_RETURN_BY_DIRECT_REF_P (gnu_type) = return_by_direct_ref_p; TREE_ADDRESSABLE (gnu_type) = return_by_invisi_ref_p; } @@ -7797,20 +7770,20 @@ warn_on_field_placement (tree gnu_field, Node_Id gnat_component_list, const char *msg1 = in_variant - ? "??variant layout may cause performance issues" - : "??record layout may cause performance issues"; + ? "?.q?variant layout may cause performance issues" + : "?.q?record layout may cause performance issues"; const char *msg2 = Ekind (gnat_field) == E_Discriminant - ? "??discriminant & whose length is not multiple of a byte" + ? "?.q?discriminant & whose length is not multiple of a byte" : field_has_self_size (gnu_field) - ? "??component & whose length depends on a discriminant" + ? "?.q?component & whose length depends on a discriminant" : field_has_variable_size (gnu_field) - ? "??component & whose length is not fixed" - : "??component & whose length is not multiple of a byte"; + ? "?.q?component & whose length is not fixed" + : "?.q?component & whose length is not multiple of a byte"; const char *msg3 = do_reorder - ? "??comes too early and was moved down" - : "??comes too early and ought to be moved down"; + ? "?.q?comes too early and was moved down" + : "?.q?comes too early and ought to be moved down"; post_error (msg1, gnat_field); post_error_ne (msg2, gnat_field, gnat_field); diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index bd559d1..b88dfc1 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -6,7 +6,7 @@ * * * C Header File * * * - * Copyright (C) 1992-2021, Free Software Foundation, Inc. * + * Copyright (C) 1992-2022, 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- * @@ -399,18 +399,7 @@ enum standard_datatypes /* Identifier for the name of the Not_Handled_By_Others field. */ ADT_not_handled_by_others_name_id, - /* Types and decls used by the SJLJ exception mechanism. */ - ADT_jmpbuf_type, - ADT_jmpbuf_ptr_type, - ADT_get_jmpbuf_decl, - ADT_set_jmpbuf_decl, - ADT_get_excptr_decl, - ADT_not_handled_by_others_decl, - ADT_setjmp_decl, - ADT_update_setjmp_buf_decl, - ADT_raise_nodefer_decl, - - /* Types and decls used by the ZCX exception mechanism. */ + /* Types and decls used by the exception mechanism. */ ADT_reraise_zcx_decl, ADT_set_exception_parameter_decl, ADT_begin_handler_decl, @@ -469,25 +458,15 @@ extern GTY(()) tree gnat_raise_decls_ext[(int) LAST_REASON_CODE + 1]; #define parent_name_id gnat_std_decls[(int) ADT_parent_name_id] #define not_handled_by_others_name_id \ gnat_std_decls[(int) ADT_not_handled_by_others_name_id] -#define jmpbuf_type gnat_std_decls[(int) ADT_jmpbuf_type] -#define jmpbuf_ptr_type gnat_std_decls[(int) ADT_jmpbuf_ptr_type] -#define get_jmpbuf_decl gnat_std_decls[(int) ADT_get_jmpbuf_decl] -#define set_jmpbuf_decl gnat_std_decls[(int) ADT_set_jmpbuf_decl] -#define get_excptr_decl gnat_std_decls[(int) ADT_get_excptr_decl] -#define not_handled_by_others_decl \ - gnat_std_decls[(int) ADT_not_handled_by_others_decl] -#define setjmp_decl gnat_std_decls[(int) ADT_setjmp_decl] -#define update_setjmp_buf_decl gnat_std_decls[(int) ADT_update_setjmp_buf_decl] -#define raise_nodefer_decl gnat_std_decls[(int) ADT_raise_nodefer_decl] #define reraise_zcx_decl gnat_std_decls[(int) ADT_reraise_zcx_decl] #define set_exception_parameter_decl \ gnat_std_decls[(int) ADT_set_exception_parameter_decl] #define begin_handler_decl gnat_std_decls[(int) ADT_begin_handler_decl] +#define end_handler_decl gnat_std_decls[(int) ADT_end_handler_decl] +#define unhandled_except_decl gnat_std_decls[(int) ADT_unhandled_except_decl] #define others_decl gnat_std_decls[(int) ADT_others_decl] #define all_others_decl gnat_std_decls[(int) ADT_all_others_decl] #define unhandled_others_decl gnat_std_decls[(int) ADT_unhandled_others_decl] -#define end_handler_decl gnat_std_decls[(int) ADT_end_handler_decl] -#define unhandled_except_decl gnat_std_decls[(int) ADT_unhandled_except_decl] /* Routines expected by the gcc back-end. They must have exactly the same prototype and names as below. */ @@ -504,12 +483,6 @@ extern void gnat_zaplevel (void); and point FNDECL to this BLOCK. */ extern void set_current_block_context (tree fndecl); -/* Set the jmpbuf_decl for the current binding level to DECL. */ -extern void set_block_jmpbuf_decl (tree decl); - -/* Get the setjmp_decl, if any, for the current binding level. */ -extern tree get_block_jmpbuf_decl (void); - /* Record DECL as belonging to the current lexical scope and use GNAT_NODE for location information and flag propagation. */ extern void gnat_pushdecl (tree decl, Node_Id gnat_node); @@ -547,7 +520,7 @@ extern int gnat_types_compatible_p (tree t1, tree t2); extern bool gnat_useless_type_conversion (tree expr); /* Return true if T, a {FUNCTION,METHOD}_TYPE, has the specified flags. */ -extern bool fntype_same_flags_p (const_tree, tree, bool, bool, bool); +extern bool fntype_same_flags_p (const_tree, tree, bool, bool); /* Create an expression whose value is that of EXPR, converted to type TYPE. The TREE_TYPE of the value diff --git a/gcc/ada/gcc-interface/lang-specs.h b/gcc/ada/gcc-interface/lang-specs.h index db1917b..6c260a0 100644 --- a/gcc/ada/gcc-interface/lang-specs.h +++ b/gcc/ada/gcc-interface/lang-specs.h @@ -6,7 +6,7 @@ * * * C Header File * * * - * Copyright (C) 1992-2021, Free Software Foundation, Inc. * + * Copyright (C) 1992-2022, 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- * diff --git a/gcc/ada/gcc-interface/misc.cc b/gcc/ada/gcc-interface/misc.cc index 2caa83f..f0ca197 100644 --- a/gcc/ada/gcc-interface/misc.cc +++ b/gcc/ada/gcc-interface/misc.cc @@ -684,7 +684,6 @@ gnat_type_hash_eq (const_tree t1, const_tree t2) { gcc_assert (FUNC_OR_METHOD_TYPE_P (t1) && TREE_CODE (t1) == TREE_CODE (t2)); return fntype_same_flags_p (t1, TYPE_CI_CO_LIST (t2), - TYPE_RETURN_UNCONSTRAINED_P (t2), TYPE_RETURN_BY_DIRECT_REF_P (t2), TREE_ADDRESSABLE (t2)); } @@ -1293,6 +1292,15 @@ gnat_eh_personality (void) return gnat_eh_personality_decl; } +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +static const char * +gnat_get_sarif_source_language (const char *) +{ + return "ada"; +} + /* Initialize language-specific bits of tree_contains_struct. */ static void @@ -1415,6 +1423,8 @@ get_lang_specific (tree node) #define LANG_HOOKS_DEEP_UNSHARING true #undef LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS #define LANG_HOOKS_CUSTOM_FUNCTION_DESCRIPTORS true +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE gnat_get_sarif_source_language struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc index e80200e..f0602b8 100644 --- a/gcc/ada/gcc-interface/trans.cc +++ b/gcc/ada/gcc-interface/trans.cc @@ -467,71 +467,6 @@ gigi (Node_Id gnat_root, /* Make the types and functions used for exception processing. */ except_type_node = gnat_to_gnu_type (Base_Type (standard_exception_type)); - for (t = TYPE_FIELDS (except_type_node); t; t = DECL_CHAIN (t)) - if (DECL_NAME (t) == not_handled_by_others_name_id) - { - not_handled_by_others_decl = t; - break; - } - gcc_assert (DECL_P (not_handled_by_others_decl)); - - jmpbuf_type - = build_array_type (gnat_type_for_mode (Pmode, 0), - build_index_type (size_int (5))); - record_builtin_type ("JMPBUF_T", jmpbuf_type, true); - jmpbuf_ptr_type = build_pointer_type (jmpbuf_type); - - /* Functions to get and set the jumpbuf pointer for the current thread. */ - get_jmpbuf_decl - = create_subprog_decl - (get_identifier ("system__soft_links__get_jmpbuf_address_soft"), - NULL_TREE, build_function_type_list (jmpbuf_ptr_type, NULL_TREE), - NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); - - set_jmpbuf_decl - = create_subprog_decl - (get_identifier ("system__soft_links__set_jmpbuf_address_soft"), - NULL_TREE, build_function_type_list (void_type_node, jmpbuf_ptr_type, - NULL_TREE), - NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); - - get_excptr_decl - = create_subprog_decl - (get_identifier ("system__soft_links__get_gnat_exception"), NULL_TREE, - build_function_type_list (build_pointer_type (except_type_node), - NULL_TREE), - NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); - - /* setjmp returns an integer and has one operand, which is a pointer to - a jmpbuf. */ - setjmp_decl - = create_subprog_decl - (get_identifier ("__builtin_setjmp"), NULL_TREE, - build_function_type_list (integer_type_node, jmpbuf_ptr_type, - NULL_TREE), - NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); - set_decl_built_in_function (setjmp_decl, BUILT_IN_NORMAL, BUILT_IN_SETJMP); - - /* update_setjmp_buf updates a setjmp buffer from the current stack pointer - address. */ - update_setjmp_buf_decl - = create_subprog_decl - (get_identifier ("__builtin_update_setjmp_buf"), NULL_TREE, - build_function_type_list (void_type_node, jmpbuf_ptr_type, NULL_TREE), - NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); - set_decl_built_in_function (update_setjmp_buf_decl, BUILT_IN_NORMAL, - BUILT_IN_UPDATE_SETJMP_BUF); - - /* Indicate that it never returns. */ - ftype = build_function_type_list (void_type_node, - build_pointer_type (except_type_node), - NULL_TREE); - ftype = build_qualified_type (ftype, TYPE_QUAL_VOLATILE); - raise_nodefer_decl - = create_subprog_decl - (get_identifier ("__gnat_raise_nodefer_with_msg"), NULL_TREE, ftype, - NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); - set_exception_parameter_decl = create_subprog_decl (get_identifier ("__gnat_set_exception_parameter"), NULL_TREE, @@ -600,8 +535,7 @@ gigi (Node_Id gnat_root, NULL, Empty); /* If in no exception handlers mode, all raise statements are redirected to - __gnat_last_chance_handler. No need to redefine raise_nodefer_decl since - this procedure will never be called in this mode. */ + __gnat_last_chance_handler. */ if (No_Exception_Handlers_Set ()) { /* Indicate that it never returns. */ @@ -1220,10 +1154,13 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) gnat_result_type = Etype (gnat_node); } - /* Expand the type of this identifier first, in case it is an enumeral - literal, which only get made when the type is expanded. There is no - order-of-elaboration issue here. */ - gnu_result_type = get_unpadded_type (gnat_result_type); + /* Expand the type of this identifier first if it is needed, in case it is an + enumeral literal, which only get made when the type is expanded. There is + no order-of-elaboration issue here. */ + if (Is_Subprogram (gnat_entity)) + gnu_result_type = NULL_TREE; + else + gnu_result_type = get_unpadded_type (gnat_result_type); /* If this is a non-imported elementary constant with an address clause, retrieve the value instead of a pointer to be dereferenced unless @@ -3725,7 +3662,7 @@ finalize_nrv (tree fndecl, bitmap nrv, vec<tree, va_gc> *other, Node_Id gnat_ret data.result = DECL_RESULT (fndecl); data.gnat_ret = gnat_ret; data.visited = new hash_set<tree>; - if (TYPE_RETURN_UNCONSTRAINED_P (TREE_TYPE (fndecl))) + if (TYPE_RETURN_BY_DIRECT_REF_P (TREE_TYPE (fndecl))) func = finalize_nrv_unc_r; else func = finalize_nrv_r; @@ -3902,6 +3839,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) /* Try to create a bona-fide thunk and hand it over to the middle-end. */ if (Is_Thunk (gnat_subprog) + && !Is_Secondary_Stack_Thunk (gnat_subprog) && maybe_make_gnu_thunk (gnat_subprog, gnu_subprog)) return; @@ -5252,10 +5190,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, gnu_result_type = TREE_TYPE (gnu_call); } - /* If the function returns an unconstrained array or by direct reference, - we have to dereference the pointer. */ - if (TYPE_RETURN_UNCONSTRAINED_P (gnu_subprog_type) - || TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type)) + /* If the function returns by direct reference, we have to dereference + the pointer. */ + if (TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type)) gnu_call = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_call); if (gnu_target) @@ -7439,52 +7376,58 @@ gnat_to_gnu (Node_Id gnat_node) gnu_ret_val = TREE_OPERAND (gnu_ret_val, 0); /* If the function returns by direct reference, return a pointer - to the return value. */ - if (TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type) - || By_Ref (gnat_node)) - gnu_ret_val = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_ret_val); - - /* Otherwise, if it returns an unconstrained array, we have to - allocate a new version of the result and return it. */ - else if (TYPE_RETURN_UNCONSTRAINED_P (gnu_subprog_type)) + to the return value, possibly after allocating it. */ + if (TYPE_RETURN_BY_DIRECT_REF_P (gnu_subprog_type)) { - gnu_ret_val = maybe_unconstrained_array (gnu_ret_val); - - /* And find out whether this is a candidate for Named Return - Value. If so, record it. */ - if (optimize - && !optimize_debug - && !TYPE_CI_CO_LIST (gnu_subprog_type)) + if (Present (Storage_Pool (gnat_node))) { - tree ret_val = gnu_ret_val; - - /* Strip useless conversions around the return value. */ - if (gnat_useless_type_conversion (ret_val)) - ret_val = TREE_OPERAND (ret_val, 0); - - /* Strip unpadding around the return value. */ - if (TREE_CODE (ret_val) == COMPONENT_REF - && TYPE_IS_PADDING_P - (TREE_TYPE (TREE_OPERAND (ret_val, 0)))) - ret_val = TREE_OPERAND (ret_val, 0); - - /* Now apply the test to the return value. */ - if (return_value_ok_for_nrv_p (NULL_TREE, ret_val)) + gnu_ret_val = maybe_unconstrained_array (gnu_ret_val); + + /* And find out whether it is a candidate for Named Return + Value. If so, record it. Note that we disable this NRV + optimization when we're preserving the control flow as + it entails hoisting the allocation done below. */ + if (optimize + && !optimize_debug + && !TYPE_CI_CO_LIST (gnu_subprog_type)) { - if (!f_named_ret_val) - f_named_ret_val = BITMAP_GGC_ALLOC (); - bitmap_set_bit (f_named_ret_val, DECL_UID (ret_val)); - if (!f_gnat_ret) - f_gnat_ret = gnat_node; + tree ret_val = gnu_ret_val; + + /* Strip conversions around the return value. */ + if (gnat_useless_type_conversion (ret_val)) + ret_val = TREE_OPERAND (ret_val, 0); + + /* Strip unpadding around the return value. */ + if (TREE_CODE (ret_val) == COMPONENT_REF + && TYPE_IS_PADDING_P + (TREE_TYPE (TREE_OPERAND (ret_val, 0)))) + ret_val = TREE_OPERAND (ret_val, 0); + + /* Now apply the test to the return value. */ + if (return_value_ok_for_nrv_p (NULL_TREE, ret_val)) + { + if (!f_named_ret_val) + f_named_ret_val = BITMAP_GGC_ALLOC (); + bitmap_set_bit (f_named_ret_val, + DECL_UID (ret_val)); + if (!f_gnat_ret) + f_gnat_ret = gnat_node; + } } + + gnu_ret_val + = build_allocator (TREE_TYPE (gnu_ret_val), + gnu_ret_val, + TREE_TYPE (gnu_ret_obj), + Procedure_To_Call (gnat_node), + Storage_Pool (gnat_node), + gnat_node, + false); } - gnu_ret_val = build_allocator (TREE_TYPE (gnu_ret_val), - gnu_ret_val, - TREE_TYPE (gnu_ret_obj), - Procedure_To_Call (gnat_node), - Storage_Pool (gnat_node), - gnat_node, false); + else + gnu_ret_val + = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_ret_val); } /* Otherwise, if it returns by invisible reference, dereference @@ -10670,7 +10613,8 @@ make_covariant_thunk (Entity_Id gnat_thunk, tree gnu_thunk) static bool maybe_make_gnu_thunk (Entity_Id gnat_thunk, tree gnu_thunk) { - const Entity_Id gnat_target = Thunk_Entity (gnat_thunk); + /* We use the Thunk_Target to compute the properties of the thunk. */ + const Entity_Id gnat_target = Thunk_Target (gnat_thunk); /* Check that the first formal of the target is the only controlling one. */ Entity_Id gnat_formal = First_Formal (gnat_target); @@ -10738,7 +10682,9 @@ maybe_make_gnu_thunk (Entity_Id gnat_thunk, tree gnu_thunk) indirect_offset = (HOST_WIDE_INT) (POINTER_SIZE / BITS_PER_UNIT); } - tree gnu_target = gnat_to_gnu_entity (gnat_target, NULL_TREE, false); + /* But we generate a call to the Thunk_Entity in the thunk. */ + tree gnu_target + = gnat_to_gnu_entity (Thunk_Entity (gnat_thunk), NULL_TREE, false); /* If the target is local, then thunk and target must have the same context because cgraph_node::expand_thunk can only forward the static chain. */ diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index c583aca..6111311 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -6,7 +6,7 @@ * * * C Implementation File * * * - * Copyright (C) 1992-2021, Free Software Foundation, Inc. * + * Copyright (C) 1992-2022, 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- * @@ -264,9 +264,6 @@ struct GTY((chain_next ("%h.chain"))) gnat_binding_level { struct gnat_binding_level *chain; /* The BLOCK node for this level. */ tree block; - /* If nonzero, the setjmp buffer that needs to be updated for any - variable-sized definition within this context. */ - tree jmpbuf_decl; }; /* The binding level currently in effect. */ @@ -599,7 +596,6 @@ gnat_pushlevel (void) /* Add this level to the front of the chain (stack) of active levels. */ newlevel->chain = current_binding_level; - newlevel->jmpbuf_decl = NULL_TREE; current_binding_level = newlevel; } @@ -614,22 +610,6 @@ set_current_block_context (tree fndecl) set_block_for_group (current_binding_level->block); } -/* Set the jmpbuf_decl for the current binding level to DECL. */ - -void -set_block_jmpbuf_decl (tree decl) -{ - current_binding_level->jmpbuf_decl = decl; -} - -/* Get the jmpbuf_decl, if any, for the current binding level. */ - -tree -get_block_jmpbuf_decl (void) -{ - return current_binding_level->jmpbuf_decl; -} - /* Exit a binding level. Set any BLOCK into the current code group. */ void @@ -3841,11 +3821,10 @@ gnat_useless_type_conversion (tree expr) /* Return true if T, a {FUNCTION,METHOD}_TYPE, has the specified flags. */ bool -fntype_same_flags_p (const_tree t, tree cico_list, bool return_unconstrained_p, - bool return_by_direct_ref_p, bool return_by_invisi_ref_p) +fntype_same_flags_p (const_tree t, tree cico_list, bool return_by_direct_ref_p, + bool return_by_invisi_ref_p) { return TYPE_CI_CO_LIST (t) == cico_list - && TYPE_RETURN_UNCONSTRAINED_P (t) == return_unconstrained_p && TYPE_RETURN_BY_DIRECT_REF_P (t) == return_by_direct_ref_p && TREE_ADDRESSABLE (t) == return_by_invisi_ref_p; } diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads index e188a6d..c6bcb71 100644 --- a/gcc/ada/gen_il-fields.ads +++ b/gcc/ada/gen_il-fields.ads @@ -88,7 +88,6 @@ package Gen_IL.Fields is Body_Required, Body_To_Inline, Box_Present, - By_Ref, Char_Literal_Value, Chars, Check_Address_Alignment, diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb index dd730f4..97c16bc 100644 --- a/gcc/ada/gen_il-gen-gen_nodes.adb +++ b/gcc/ada/gen_il-gen-gen_nodes.adb @@ -1059,7 +1059,6 @@ begin -- Gen_IL.Gen.Gen_Nodes Cc (N_Simple_Return_Statement, N_Statement_Other_Than_Procedure_Call, (Sy (Expression, Node_Id, Default_Empty), - Sm (By_Ref, Flag), Sm (Comes_From_Extended_Return_Statement, Flag), Sm (Procedure_To_Call, Node_Id), Sm (Return_Statement_Entity, Node_Id), @@ -1068,7 +1067,6 @@ begin -- Gen_IL.Gen.Gen_Nodes Cc (N_Extended_Return_Statement, N_Statement_Other_Than_Procedure_Call, (Sy (Return_Object_Declarations, List_Id), Sy (Handled_Statement_Sequence, Node_Id, Default_Empty), - Sm (By_Ref, Flag), Sm (Procedure_To_Call, Node_Id), Sm (Return_Statement_Entity, Node_Id), Sm (Storage_Pool, Node_Id))); diff --git a/gcc/ada/ghost.adb b/gcc/ada/ghost.adb index 962941d..25b9a28 100644 --- a/gcc/ada/ghost.adb +++ b/gcc/ada/ghost.adb @@ -365,6 +365,17 @@ package body Ghost is if Is_Ghost_Pragma (Prag) then return True; + -- A pragma may not be analyzed, so that its Ghost status is + -- not determined yet, but it is guaranteed to be Ghost when + -- referencing a Ghost entity. + + elsif Prag_Nam in Name_Annotate + | Name_Compile_Time_Error + | Name_Compile_Time_Warning + | Name_Unreferenced + then + return True; + -- An assertion expression pragma is Ghost when it contains a -- reference to a Ghost entity (SPARK RM 6.9(10)), except for -- predicate pragmas (SPARK RM 6.9(11)). @@ -444,14 +455,6 @@ package body Ghost is if Ghost_Mode > None then return True; - -- A Ghost type may be referenced in a use_type clause - -- (SPARK RM 6.9.10). - - elsif Present (Parent (Context)) - and then Nkind (Parent (Context)) = N_Use_Type_Clause - then - return True; - -- Routine Expand_Record_Extension creates a parent subtype without -- inserting it into the tree. There is no good way of recognizing -- this special case as there is no parent. Try to approximate the @@ -482,6 +485,46 @@ package body Ghost is then return True; + -- A Ghost type may be referenced in a use or use_type clause + -- (SPARK RM 6.9(10)). + + elsif Present (Parent (Par)) + and then Nkind (Parent (Par)) in N_Use_Package_Clause + | N_Use_Type_Clause + then + return True; + + -- The context is an attribute definition clause for a Ghost + -- entity. + + elsif Nkind (Parent (Par)) = N_Attribute_Definition_Clause + and then Par = Name (Parent (Par)) + then + return True; + + -- The context is the instantiation or renaming of a Ghost + -- entity. + + elsif Nkind (Parent (Par)) in N_Generic_Instantiation + | N_Renaming_Declaration + | N_Generic_Renaming_Declaration + and then Par = Name (Parent (Par)) + then + return True; + + -- In the context of an instantiation, accept currently Ghost + -- arguments for formal subprograms, as SPARK does not provide + -- a way to distinguish Ghost formal parameters from non-Ghost + -- ones. Illegal use of such arguments in a non-Ghost context + -- will lead to errors inside the instantiation. + + elsif Nkind (Parent (Par)) = N_Generic_Association + and then (Nkind (Par) in N_Has_Entity + and then Present (Entity (Par)) + and then Is_Subprogram (Entity (Par))) + then + return True; + elsif Is_OK_Declaration (Par) then return True; @@ -593,6 +636,13 @@ package body Ghost is return; end if; + -- When assertions are enabled, compiler generates code for ghost + -- entities, that is not subject to Ghost policy. + + if not Comes_From_Source (Ghost_Ref) then + return; + end if; + -- Once it has been established that the reference to the Ghost entity -- is within a suitable context, ensure that the policy at the point of -- declaration and at the point of use match. diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index 1fa93a3..a7077e0 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -28878,6 +28878,9 @@ RM References: H.04 (8/1) This chapter describes Ada extensions aimed at security hardening that are provided by GNAT. +The features in this chapter are currently experimental and subject to +change. + @c Register Scrubbing: @menu diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index 1664c49..a2a2990 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 , Apr 22, 2022 +GNAT User's Guide for Native Platforms , May 24, 2022 AdaCore @@ -8552,7 +8552,8 @@ dynamically allocated objects. Makes GNAT emit warning and error messages as JSON. Inhibits printing of text warning and errors messages except if @code{-gnatv} or -@code{-gnatl} are present. +@code{-gnatl} are present. Uses absolute file paths when used along +@code{-gnatef}. @end table @geindex -fdump-scos (gcc) @@ -9037,7 +9038,8 @@ produced at run time. @item @code{-gnatef} -Display full source path name in brief error messages. +Display full source path name in brief error messages and absolute paths in +@code{-fdiagnostics-format=json}’s output. @end table @geindex -gnateF (gcc) @@ -29247,8 +29249,8 @@ to permit their use in free software. @printindex ge -@anchor{cf}@w{ } @anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ } +@anchor{cf}@w{ } @c %**end of body @bye diff --git a/gcc/ada/gnatbind.adb b/gcc/ada/gnatbind.adb index 4c50e61..475702a 100644 --- a/gcc/ada/gnatbind.adb +++ b/gcc/ada/gnatbind.adb @@ -50,6 +50,7 @@ with Switch; use Switch; with Switch.B; use Switch.B; with Targparm; use Targparm; with Types; use Types; +with Uintp; with System.Case_Util; use System.Case_Util; with System.Response_File; @@ -617,6 +618,7 @@ begin -- is in some cases important. Csets.Initialize; + Uintp.Initialize; Snames.Initialize; -- Scan the switches and arguments. Note that Snames must already be diff --git a/gcc/ada/gnatls.adb b/gcc/ada/gnatls.adb index 4b6ba03..9b62f71 100644 --- a/gcc/ada/gnatls.adb +++ b/gcc/ada/gnatls.adb @@ -44,6 +44,7 @@ with Snames; with Stringt; with Switch; use Switch; with Types; use Types; +with Uintp; with GNAT.Case_Util; use GNAT.Case_Util; with GNAT.Command_Line; use GNAT.Command_Line; @@ -2023,6 +2024,7 @@ begin -- Initialize standard packages Csets.Initialize; + Uintp.Initialize; Snames.Initialize; Stringt.Initialize; diff --git a/gcc/ada/gprep.adb b/gcc/ada/gprep.adb index 36ec1d8..58ae104 100644 --- a/gcc/ada/gprep.adb +++ b/gcc/ada/gprep.adb @@ -37,6 +37,7 @@ with Snames; with Stringt; use Stringt; with Switch; use Switch; with Types; use Types; +with Uintp; with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; @@ -169,6 +170,7 @@ package body GPrep is -- Do some initializations (order is important here) Csets.Initialize; + Uintp.Initialize; Snames.Initialize; Stringt.Initialize; Prep.Initialize; diff --git a/gcc/ada/init.c b/gcc/ada/init.c index 89f16a1..cfae740 100644 --- a/gcc/ada/init.c +++ b/gcc/ada/init.c @@ -2560,6 +2560,39 @@ __gnat_install_handler (void) #include <errno.h> #include "sigtramp.h" +#if defined (__ARMEL__) && !defined (__aarch64__) + +/* ARM-QNX case with arm unwinding exceptions */ +#define HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE + +#include <ucontext.h> +#include <arm/cpu.h> +#include <stdint.h> + +void +__gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, + void *sc ATTRIBUTE_UNUSED) +{ + /* In case of ARM exceptions, the registers context have the PC pointing + to the instruction that raised the signal. However the unwinder expects + the instruction to be in the range [PC+2,PC+3]. */ + uintptr_t *pc_addr; + mcontext_t *mcontext = &((ucontext_t *) sc)->uc_mcontext; + pc_addr = (uintptr_t *)&mcontext->cpu.gpr [ARM_REG_PC]; + + /* ARM Bump has to be an even number because of odd/even architecture. */ + *pc_addr += 2; +#ifdef __thumb2__ + /* For thumb, the return address must have the low order bit set, otherwise + the unwinder will reset to "arm" mode upon return. As long as the + compilation unit containing the landing pad is compiled with the same + mode (arm vs thumb) as the signaling compilation unit, this works. */ + if (mcontext->cpu.spsr & ARM_CPSR_T) + *pc_addr += 1; +#endif +} +#endif /* ARMEL */ + void __gnat_map_signal (int sig, siginfo_t *si ATTRIBUTE_UNUSED, @@ -2597,6 +2630,13 @@ __gnat_map_signal (int sig, static void __gnat_error_handler (int sig, siginfo_t *si, void *ucontext) { +#ifdef HAVE_GNAT_ADJUST_CONTEXT_FOR_RAISE + /* We need to sometimes to adjust the PC in case of signals so that it + doesn't reference the exception that actually raised the signal but the + instruction before it. */ + __gnat_adjust_context_for_raise (sig, ucontext); +#endif + __gnat_sigtramp (sig, (void *) si, (void *) ucontext, (__sigtramphandler_t *)&__gnat_map_signal); } diff --git a/gcc/ada/libgnat/a-cfdlli.adb b/gcc/ada/libgnat/a-cfdlli.adb index 383d031..bbb8fd4 100644 --- a/gcc/ada/libgnat/a-cfdlli.adb +++ b/gcc/ada/libgnat/a-cfdlli.adb @@ -29,9 +29,17 @@ with Ada.Containers.Stable_Sorting; use Ada.Containers.Stable_Sorting; with System; use type System.Address; +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; + package body Ada.Containers.Formal_Doubly_Linked_Lists with SPARK_Mode => Off is + -- Convert Count_Type to Big_Interger + + package Conversions is new Signed_Conversions (Int => Count_Type); + use Conversions; + ----------------------- -- Local Subprograms -- ----------------------- @@ -68,9 +76,9 @@ is end if; LI := Left.First; - RI := Left.First; + RI := Right.First; while LI /= 0 loop - if Left.Nodes (LI).Element /= Right.Nodes (LI).Element then + if Left.Nodes (LI).Element /= Right.Nodes (RI).Element then return False; end if; @@ -809,7 +817,7 @@ is while Position /= 0 loop R := P.Add (R, (Node => Position), I); - pragma Assert (P.Length (R) = I); + pragma Assert (P.Length (R) = To_Big_Integer (I)); Position := Container.Nodes (Position).Next; I := I + 1; end loop; diff --git a/gcc/ada/libgnat/a-cfhama.adb b/gcc/ada/libgnat/a-cfhama.adb index 0b60a01..bdf2c61 100644 --- a/gcc/ada/libgnat/a-cfhama.adb +++ b/gcc/ada/libgnat/a-cfhama.adb @@ -33,6 +33,9 @@ pragma Elaborate_All (Ada.Containers.Hash_Tables.Generic_Formal_Keys); with Ada.Containers.Prime_Numbers; use Ada.Containers.Prime_Numbers; +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; + with System; use type System.Address; package body Ada.Containers.Formal_Hashed_Maps with @@ -71,6 +74,13 @@ is function Vet (Container : Map; Position : Cursor) return Boolean with Inline; + -- Convert Count_Type to Big_Interger + + package Conversions is new Signed_Conversions (Int => Count_Type); + + function Big (J : Count_Type) return Big_Integer renames + Conversions.To_Big_Integer; + -------------------------- -- Local Instantiations -- -------------------------- @@ -526,7 +536,7 @@ is while Position /= 0 loop R := P.Add (R, (Node => Position), I); - pragma Assert (P.Length (R) = I); + pragma Assert (P.Length (R) = Big (I)); Position := HT_Ops.Next (Container.Content, Position); I := I + 1; end loop; diff --git a/gcc/ada/libgnat/a-cfhase.adb b/gcc/ada/libgnat/a-cfhase.adb index 544ad2b..34afa55 100644 --- a/gcc/ada/libgnat/a-cfhase.adb +++ b/gcc/ada/libgnat/a-cfhase.adb @@ -753,7 +753,7 @@ is while Position /= 0 loop R := P.Add (R, (Node => Position), I); - pragma Assert (P.Length (R) = I); + pragma Assert (P.Length (R) = Big (I)); Position := HT_Ops.Next (Container.Content, Position); I := I + 1; end loop; diff --git a/gcc/ada/libgnat/a-cfhase.ads b/gcc/ada/libgnat/a-cfhase.ads index 1a40118..80ce948 100644 --- a/gcc/ada/libgnat/a-cfhase.ads +++ b/gcc/ada/libgnat/a-cfhase.ads @@ -48,6 +48,8 @@ with Ada.Containers.Functional_Maps; with Ada.Containers.Functional_Sets; with Ada.Containers.Functional_Vectors; +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; private with Ada.Containers.Hash_Tables; generic @@ -70,6 +72,13 @@ is pragma Assertion_Policy (Contract_Cases => Ignore); pragma Annotate (CodePeer, Skip_Analysis); + -- Convert Count_Type to Big_Interger. + + package Conversions is new Signed_Conversions (Int => Count_Type); + + function Big (J : Count_Type) return Big_Integer renames + Conversions.To_Big_Integer; + type Set (Capacity : Count_Type; Modulus : Hash_Type) is private with Iterable => (First => First, Next => Next, @@ -261,7 +270,7 @@ is Ghost, Global => null, - Post => M.Length (Model'Result) = Length (Container); + Post => M.Length (Model'Result) = Big (Length (Container)); function Elements (Container : Set) return E.Sequence with -- The Elements sequence represents the underlying list structure of @@ -859,9 +868,9 @@ is Length (Source) - Length (Target and Source) <= Target.Capacity - Length (Target), Post => - Length (Target) = Length (Target)'Old + Big (Length (Target)) = Big (Length (Target)'Old) - M.Num_Overlaps (Model (Target)'Old, Model (Source)) - + Length (Source) + + Big (Length (Source)) -- Elements already in Target are still in Target @@ -907,9 +916,9 @@ is Global => null, Pre => Length (Left) <= Count_Type'Last - Length (Right), Post => - Length (Union'Result) = Length (Left) + Big (Length (Union'Result)) = Big (Length (Left)) - M.Num_Overlaps (Model (Left), Model (Right)) - + Length (Right) + + Big (Length (Right)) -- Elements of Left and Right are in the result of Union @@ -946,7 +955,7 @@ is procedure Intersection (Target : in out Set; Source : Set) with Global => null, Post => - Length (Target) = + Big (Length (Target)) = M.Num_Overlaps (Model (Target)'Old, Model (Source)) -- Elements of Target were already in Target @@ -982,7 +991,7 @@ is function Intersection (Left, Right : Set) return Set with Global => null, Post => - Length (Intersection'Result) = + Big (Length (Intersection'Result)) = M.Num_Overlaps (Model (Left), Model (Right)) -- Elements in the result of Intersection are in Left and Right @@ -1012,7 +1021,7 @@ is procedure Difference (Target : in out Set; Source : Set) with Global => null, Post => - Length (Target) = Length (Target)'Old - + Big (Length (Target)) = Big (Length (Target)'Old) - M.Num_Overlaps (Model (Target)'Old, Model (Source)) -- Elements of Target were already in Target @@ -1048,7 +1057,7 @@ is function Difference (Left, Right : Set) return Set with Global => null, Post => - Length (Difference'Result) = Length (Left) - + Big (Length (Difference'Result)) = Big (Length (Left)) - M.Num_Overlaps (Model (Left), Model (Right)) -- Elements of the result of Difference are in Left @@ -1085,9 +1094,9 @@ is Length (Source) - Length (Target and Source) <= Target.Capacity - Length (Target) + Length (Target and Source), Post => - Length (Target) = Length (Target)'Old - + Big (Length (Target)) = Big (Length (Target)'Old) - 2 * M.Num_Overlaps (Model (Target)'Old, Model (Source)) + - Length (Source) + Big (Length (Source)) -- Elements of the difference were not both in Source and in Target @@ -1125,9 +1134,9 @@ is Global => null, Pre => Length (Left) <= Count_Type'Last - Length (Right), Post => - Length (Symmetric_Difference'Result) = Length (Left) - + Big (Length (Symmetric_Difference'Result)) = Big (Length (Left)) - 2 * M.Num_Overlaps (Model (Left), Model (Right)) + - Length (Right) + Big (Length (Right)) -- Elements of the difference were not both in Left and Right diff --git a/gcc/ada/libgnat/a-cfinve.adb b/gcc/ada/libgnat/a-cfinve.adb index 17b57cb..a55786d 100644 --- a/gcc/ada/libgnat/a-cfinve.adb +++ b/gcc/ada/libgnat/a-cfinve.adb @@ -432,7 +432,7 @@ is function Element (Container : Vector; - Index : Index_Type) return Element_Type + Index : Extended_Index) return Element_Type is begin if Index > Container.Last then diff --git a/gcc/ada/libgnat/a-cfinve.ads b/gcc/ada/libgnat/a-cfinve.ads index ec6af99..b5fa29b 100644 --- a/gcc/ada/libgnat/a-cfinve.ads +++ b/gcc/ada/libgnat/a-cfinve.ads @@ -284,7 +284,7 @@ is function Element (Container : Vector; - Index : Index_Type) return Element_Type + Index : Extended_Index) return Element_Type with Global => null, Pre => Index in First_Index (Container) .. Last_Index (Container), diff --git a/gcc/ada/libgnat/a-cforma.adb b/gcc/ada/libgnat/a-cforma.adb index 79f25f8..38d15e7 100644 --- a/gcc/ada/libgnat/a-cforma.adb +++ b/gcc/ada/libgnat/a-cforma.adb @@ -32,12 +32,22 @@ pragma Elaborate_All with Ada.Containers.Red_Black_Trees.Generic_Bounded_Keys; pragma Elaborate_All (Ada.Containers.Red_Black_Trees.Generic_Bounded_Keys); +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; + with System; use type System.Address; package body Ada.Containers.Formal_Ordered_Maps with SPARK_Mode => Off is + -- Convert Count_Type to Big_Interger + + package Conversions is new Signed_Conversions (Int => Count_Type); + + function Big (J : Count_Type) return Big_Integer renames + Conversions.To_Big_Integer; + ----------------------------- -- Node Access Subprograms -- ----------------------------- @@ -745,7 +755,7 @@ is while Position /= 0 loop R := P.Add (R, (Node => Position), I); - pragma Assert (P.Length (R) = I); + pragma Assert (P.Length (R) = Big (I)); Position := Tree_Operations.Next (Container.Content, Position); I := I + 1; end loop; diff --git a/gcc/ada/libgnat/a-cforse.adb b/gcc/ada/libgnat/a-cforse.adb index 3b64511..e5cddde 100644 --- a/gcc/ada/libgnat/a-cforse.adb +++ b/gcc/ada/libgnat/a-cforse.adb @@ -943,7 +943,7 @@ is while Position /= 0 loop R := P.Add (R, (Node => Position), I); - pragma Assert (P.Length (R) = I); + pragma Assert (P.Length (R) = Big (I)); Position := Tree_Operations.Next (Container.Content, Position); I := I + 1; end loop; diff --git a/gcc/ada/libgnat/a-cforse.ads b/gcc/ada/libgnat/a-cforse.ads index a736b48..f6a033f 100644 --- a/gcc/ada/libgnat/a-cforse.ads +++ b/gcc/ada/libgnat/a-cforse.ads @@ -49,6 +49,8 @@ with Ada.Containers.Functional_Maps; with Ada.Containers.Functional_Sets; with Ada.Containers.Functional_Vectors; +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; private with Ada.Containers.Red_Black_Trees; generic @@ -67,6 +69,13 @@ is pragma Assertion_Policy (Contract_Cases => Ignore); pragma Annotate (CodePeer, Skip_Analysis); + -- Convert Count_Type to Big_Interger + + package Conversions is new Signed_Conversions (Int => Count_Type); + + function Big (J : Count_Type) return Big_Integer renames + Conversions.To_Big_Integer; + function Equivalent_Elements (Left, Right : Element_Type) return Boolean with Global => null, @@ -341,7 +350,7 @@ is Ghost, Global => null, - Post => M.Length (Model'Result) = Length (Container); + Post => M.Length (Model'Result) = Big (Length (Container)); function Elements (Container : Set) return E.Sequence with -- The Elements sequence represents the underlying list structure of @@ -990,9 +999,9 @@ is Length (Source) - Length (Target and Source) <= Target.Capacity - Length (Target), Post => - Length (Target) = Length (Target)'Old + Big (Length (Target)) = Big (Length (Target)'Old) - M.Num_Overlaps (Model (Target)'Old, Model (Source)) - + Length (Source) + + Big (Length (Source)) -- Elements already in Target are still in Target @@ -1038,9 +1047,9 @@ is Global => null, Pre => Length (Left) <= Count_Type'Last - Length (Right), Post => - Length (Union'Result) = Length (Left) + Big (Length (Union'Result)) = Big (Length (Left)) - M.Num_Overlaps (Model (Left), Model (Right)) - + Length (Right) + + Big (Length (Right)) -- Elements of Left and Right are in the result of Union @@ -1076,7 +1085,7 @@ is procedure Intersection (Target : in out Set; Source : Set) with Global => null, Post => - Length (Target) = + Big (Length (Target)) = M.Num_Overlaps (Model (Target)'Old, Model (Source)) -- Elements of Target were already in Target @@ -1111,7 +1120,7 @@ is function Intersection (Left, Right : Set) return Set with Global => null, Post => - Length (Intersection'Result) = + Big (Length (Intersection'Result)) = M.Num_Overlaps (Model (Left), Model (Right)) -- Elements in the result of Intersection are in Left and Right @@ -1139,7 +1148,7 @@ is procedure Difference (Target : in out Set; Source : Set) with Global => null, Post => - Length (Target) = Length (Target)'Old - + Big (Length (Target)) = Big (Length (Target)'Old) - M.Num_Overlaps (Model (Target)'Old, Model (Source)) -- Elements of Target were already in Target @@ -1174,7 +1183,7 @@ is function Difference (Left, Right : Set) return Set with Global => null, Post => - Length (Difference'Result) = Length (Left) - + Big (Length (Difference'Result)) = Big (Length (Left)) - M.Num_Overlaps (Model (Left), Model (Right)) -- Elements of the result of Difference are in Left @@ -1209,9 +1218,9 @@ is Length (Source) - Length (Target and Source) <= Target.Capacity - Length (Target) + Length (Target and Source), Post => - Length (Target) = Length (Target)'Old - + Big (Length (Target)) = Big (Length (Target)'Old) - 2 * M.Num_Overlaps (Model (Target)'Old, Model (Source)) + - Length (Source) + Big (Length (Source)) -- Elements of the difference were not both in Source and in Target @@ -1248,9 +1257,9 @@ is Global => null, Pre => Length (Left) <= Count_Type'Last - Length (Right), Post => - Length (Symmetric_Difference'Result) = Length (Left) - + Big (Length (Symmetric_Difference'Result)) = Big (Length (Left)) - 2 * M.Num_Overlaps (Model (Left), Model (Right)) + - Length (Right) + Big (Length (Right)) -- Elements of the difference were not both in Left and Right diff --git a/gcc/ada/libgnat/a-cofove.adb b/gcc/ada/libgnat/a-cofove.adb index 5f10f57..c921184 100644 --- a/gcc/ada/libgnat/a-cofove.adb +++ b/gcc/ada/libgnat/a-cofove.adb @@ -370,7 +370,7 @@ is function Element (Container : Vector; - Index : Index_Type) return Element_Type + Index : Extended_Index) return Element_Type is begin if Index > Container.Last then diff --git a/gcc/ada/libgnat/a-cofove.ads b/gcc/ada/libgnat/a-cofove.ads index edf9532..cba10a6 100644 --- a/gcc/ada/libgnat/a-cofove.ads +++ b/gcc/ada/libgnat/a-cofove.ads @@ -263,7 +263,7 @@ is function Element (Container : Vector; - Index : Index_Type) return Element_Type + Index : Extended_Index) return Element_Type with Global => null, Pre => Index in First_Index (Container) .. Last_Index (Container), diff --git a/gcc/ada/libgnat/a-cofuba.adb b/gcc/ada/libgnat/a-cofuba.adb index 77c0301..68cf2ae 100644 --- a/gcc/ada/libgnat/a-cofuba.adb +++ b/gcc/ada/libgnat/a-cofuba.adb @@ -52,6 +52,24 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is -- Resize the underlying array if needed so that it can contain one more -- element. + function Elements (C : Container) return Element_Array_Access is + (C.Controlled_Base.Base.Elements) + with + Global => null, + Pre => + C.Controlled_Base.Base /= null + and then C.Controlled_Base.Base.Elements /= null; + + function Get + (C_E : Element_Array_Access; + I : Count_Type) + return Element_Access + is + (C_E (I).Ref.E_Access) + with + Global => null, + Pre => C_E /= null and then C_E (I).Ref /= null; + --------- -- "=" -- --------- @@ -61,9 +79,8 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is if C1.Length /= C2.Length then return False; end if; - for I in 1 .. C1.Length loop - if C1.Base.Elements (I).all /= C2.Base.Elements (I).all then + if Get (Elements (C1), I).all /= Get (Elements (C2), I).all then return False; end if; end loop; @@ -78,7 +95,7 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is function "<=" (C1 : Container; C2 : Container) return Boolean is begin for I in 1 .. C1.Length loop - if Find (C2, C1.Base.Elements (I)) = 0 then + if Find (C2, Get (Elements (C1), I)) = 0 then return False; end if; end loop; @@ -95,50 +112,138 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is I : Index_Type; E : Element_Type) return Container is + C_B : Array_Base_Access renames C.Controlled_Base.Base; begin - if To_Count (I) = C.Length + 1 and then C.Length = C.Base.Max_Length then - Resize (C.Base); - C.Base.Max_Length := C.Base.Max_Length + 1; - C.Base.Elements (C.Base.Max_Length) := new Element_Type'(E); + if To_Count (I) = C.Length + 1 and then C.Length = C_B.Max_Length then + Resize (C_B); + C_B.Max_Length := C_B.Max_Length + 1; + C_B.Elements (C_B.Max_Length) := Element_Init (E); - return Container'(Length => C.Base.Max_Length, Base => C.Base); + return Container'(Length => C_B.Max_Length, + Controlled_Base => C.Controlled_Base); else declare - A : constant Array_Base_Access := Content_Init (C.Length); + A : constant Array_Base_Controlled_Access := + Content_Init (C.Length); P : Count_Type := 0; begin - A.Max_Length := C.Length + 1; + A.Base.Max_Length := C.Length + 1; for J in 1 .. C.Length + 1 loop if J /= To_Count (I) then P := P + 1; - A.Elements (J) := C.Base.Elements (P); + A.Base.Elements (J) := C_B.Elements (P); else - A.Elements (J) := new Element_Type'(E); + A.Base.Elements (J) := Element_Init (E); end if; end loop; - return Container'(Length => A.Max_Length, - Base => A); + return Container'(Length => A.Base.Max_Length, + Controlled_Base => A); end; end if; end Add; + ------------ + -- Adjust -- + ------------ + + procedure Adjust (Controlled_Base : in out Array_Base_Controlled_Access) is + C_B : Array_Base_Access renames Controlled_Base.Base; + begin + if C_B /= null then + C_B.Reference_Count := C_B.Reference_Count + 1; + end if; + end Adjust; + + procedure Adjust (Ctrl_E : in out Controlled_Element_Access) is + begin + if Ctrl_E.Ref /= null then + Ctrl_E.Ref.Reference_Count := Ctrl_E.Ref.Reference_Count + 1; + end if; + end Adjust; + ------------------ -- Content_Init -- ------------------ - function Content_Init (L : Count_Type := 0) return Array_Base_Access + function Content_Init + (L : Count_Type := 0) return Array_Base_Controlled_Access is Max_Init : constant Count_Type := 100; Size : constant Count_Type := (if L < Count_Type'Last - Max_Init then L + Max_Init else Count_Type'Last); + + -- The Access in the array will be initialized to null + Elements : constant Element_Array_Access := new Element_Array'(1 .. Size => <>); + B : constant Array_Base_Access := + new Array_Base'(Reference_Count => 1, + Max_Length => 0, + Elements => Elements); begin - return new Array_Base'(Max_Length => 0, Elements => Elements); + return (Ada.Finalization.Controlled with Base => B); end Content_Init; + ------------------ + -- Element_Init -- + ------------------ + + function Element_Init (E : Element_Type) return Controlled_Element_Access + is + Refcounted_E : constant Refcounted_Element_Access := + new Refcounted_Element'(Reference_Count => 1, + E_Access => new Element_Type'(E)); + begin + return (Ada.Finalization.Controlled with Ref => Refcounted_E); + end Element_Init; + + -------------- + -- Finalize -- + -------------- + + procedure Finalize (Controlled_Base : in out Array_Base_Controlled_Access) + is + procedure Unchecked_Free_Base is new Ada.Unchecked_Deallocation + (Object => Array_Base, + Name => Array_Base_Access); + procedure Unchecked_Free_Array is new Ada.Unchecked_Deallocation + (Object => Element_Array, + Name => Element_Array_Access); + + C_B : Array_Base_Access renames Controlled_Base.Base; + begin + if C_B /= null then + C_B.Reference_Count := C_B.Reference_Count - 1; + if C_B.Reference_Count = 0 then + Unchecked_Free_Array (Controlled_Base.Base.Elements); + Unchecked_Free_Base (Controlled_Base.Base); + end if; + C_B := null; + end if; + end Finalize; + + procedure Finalize (Ctrl_E : in out Controlled_Element_Access) is + procedure Unchecked_Free_Ref is new Ada.Unchecked_Deallocation + (Object => Refcounted_Element, + Name => Refcounted_Element_Access); + + procedure Unchecked_Free_Element is new Ada.Unchecked_Deallocation + (Object => Element_Type, + Name => Element_Access); + + begin + if Ctrl_E.Ref /= null then + Ctrl_E.Ref.Reference_Count := Ctrl_E.Ref.Reference_Count - 1; + if Ctrl_E.Ref.Reference_Count = 0 then + Unchecked_Free_Element (Ctrl_E.Ref.E_Access); + Unchecked_Free_Ref (Ctrl_E.Ref); + end if; + Ctrl_E.Ref := null; + end if; + end Finalize; + ---------- -- Find -- ---------- @@ -146,7 +251,7 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is function Find (C : Container; E : access Element_Type) return Count_Type is begin for I in 1 .. C.Length loop - if C.Base.Elements (I).all = E.all then + if Get (Elements (C), I).all = E.all then return I; end if; end loop; @@ -162,7 +267,7 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is --------- function Get (C : Container; I : Index_Type) return Element_Type is - (C.Base.Elements (To_Count (I)).all); + (Get (Elements (C), To_Count (I)).all); ------------------ -- Intersection -- @@ -170,19 +275,19 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is function Intersection (C1 : Container; C2 : Container) return Container is L : constant Count_Type := Num_Overlaps (C1, C2); - A : constant Array_Base_Access := Content_Init (L); + A : constant Array_Base_Controlled_Access := Content_Init (L); P : Count_Type := 0; begin - A.Max_Length := L; + A.Base.Max_Length := L; for I in 1 .. C1.Length loop - if Find (C2, C1.Base.Elements (I)) > 0 then + if Find (C2, Get (Elements (C1), I)) > 0 then P := P + 1; - A.Elements (P) := C1.Base.Elements (I); + A.Base.Elements (P) := Elements (C1) (I); end if; end loop; - return Container'(Length => P, Base => A); + return Container'(Length => P, Controlled_Base => A); end Intersection; ------------ @@ -199,7 +304,7 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is begin for I in 1 .. C1.Length loop - if Find (C2, C1.Base.Elements (I)) > 0 then + if Find (C2, Get (Elements (C1), I)) > 0 then P := P + 1; end if; end loop; @@ -214,21 +319,23 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is function Remove (C : Container; I : Index_Type) return Container is begin if To_Count (I) = C.Length then - return Container'(Length => C.Length - 1, Base => C.Base); + return Container'(Length => C.Length - 1, + Controlled_Base => C.Controlled_Base); else declare - A : constant Array_Base_Access := Content_Init (C.Length - 1); + A : constant Array_Base_Controlled_Access + := Content_Init (C.Length - 1); P : Count_Type := 0; begin - A.Max_Length := C.Length - 1; + A.Base.Max_Length := C.Length - 1; for J in 1 .. C.Length loop if J /= To_Count (I) then P := P + 1; - A.Elements (P) := C.Base.Elements (J); + A.Base.Elements (P) := Elements (C) (J); end if; end loop; - return Container'(Length => C.Length - 1, Base => A); + return Container'(Length => C.Length - 1, Controlled_Base => A); end; end if; end Remove; @@ -277,13 +384,14 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is E : Element_Type) return Container is Result : constant Container := - Container'(Length => C.Length, - Base => Content_Init (C.Length)); + Container'(Length => C.Length, + Controlled_Base => Content_Init (C.Length)); + R_Base : Array_Base_Access renames Result.Controlled_Base.Base; begin - Result.Base.Max_Length := C.Length; - Result.Base.Elements (1 .. C.Length) := C.Base.Elements (1 .. C.Length); - Result.Base.Elements (To_Count (I)) := new Element_Type'(E); + R_Base.Max_Length := C.Length; + R_Base.Elements (1 .. C.Length) := Elements (C) (1 .. C.Length); + R_Base.Elements (To_Count (I)) := Element_Init (E); return Result; end Set; @@ -305,20 +413,19 @@ package body Ada.Containers.Functional_Base with SPARK_Mode => Off is declare L : constant Count_Type := Length (C1) - N + Length (C2); - A : constant Array_Base_Access := Content_Init (L); + A : constant Array_Base_Controlled_Access := Content_Init (L); P : Count_Type := Length (C1); - begin - A.Max_Length := L; - A.Elements (1 .. C1.Length) := C1.Base.Elements (1 .. C1.Length); + A.Base.Max_Length := L; + A.Base.Elements (1 .. C1.Length) := Elements (C1) (1 .. C1.Length); for I in 1 .. C2.Length loop - if Find (C1, C2.Base.Elements (I)) = 0 then + if Find (C1, Get (Elements (C2), I)) = 0 then P := P + 1; - A.Elements (P) := C2.Base.Elements (I); + A.Base.Elements (P) := Elements (C2) (I); end if; end loop; - return Container'(Length => L, Base => A); + return Container'(Length => L, Controlled_Base => A); end; end Union; diff --git a/gcc/ada/libgnat/a-cofuba.ads b/gcc/ada/libgnat/a-cofuba.ads index eacf845..8a99a43 100644 --- a/gcc/ada/libgnat/a-cofuba.ads +++ b/gcc/ada/libgnat/a-cofuba.ads @@ -34,6 +34,10 @@ pragma Ada_2012; +-- To allow reference counting on the base container + +private with Ada.Finalization; + private generic type Index_Type is (<>); -- To avoid Constraint_Error being raised at run time, Index_Type'Base @@ -98,33 +102,97 @@ package Ada.Containers.Functional_Base with SPARK_Mode => Off is private + -- Theoretically, each operation on a functional container implies the + -- creation of a new container i.e. the copy of the array itself and all + -- the elements in it. In the implementation, most of these copies are + -- avoided by sharing between the containers. + -- + -- A container stores its last used index. So, when adding an + -- element at the end of the container, the exact same array can be reused. + -- As a functionnal container cannot be modifed once created, there is no + -- risk of unwanted modifications. + -- + -- _1_2_3_ + -- S : end => [1, 2, 3] + -- | + -- |1|2|3|4|.|.| + -- | + -- Add (S, 4, 4) : end => [1, 2, 3, 4] + -- + -- The elements are also shared between containers as much as possible. For + -- example, when something is added in the middle, the array is changed but + -- the elementes are reused. + -- + -- _1_2_3_4_ + -- S : |1|2|3|4| => [1, 2, 3, 4] + -- | \ \ \ + -- Add (S, 2, 5) : |1|5|2|3|4| => [1, 5, 2, 3, 4] + -- + -- To make this sharing possible, both the elements and the arrays are + -- stored inside dynamically allocated access types which shall be + -- deallocated when they are no longer used. The memory is managed using + -- reference counting both at the array and at the element level. + subtype Positive_Count_Type is Count_Type range 1 .. Count_Type'Last; + type Reference_Count_Type is new Natural; + type Element_Access is access all Element_Type; + type Refcounted_Element is record + Reference_Count : Reference_Count_Type; + E_Access : Element_Access; + end record; + + type Refcounted_Element_Access is access Refcounted_Element; + + type Controlled_Element_Access is new Ada.Finalization.Controlled + with record + Ref : Refcounted_Element_Access := null; + end record; + + function Element_Init (E : Element_Type) return Controlled_Element_Access; + -- Use to initialize a refcounted element + type Element_Array is - array (Positive_Count_Type range <>) of Element_Access; + array (Positive_Count_Type range <>) of Controlled_Element_Access; type Element_Array_Access_Base is access Element_Array; - subtype Element_Array_Access is not null Element_Array_Access_Base; - - Empty_Element_Array_Access : constant Element_Array_Access := - new Element_Array'(1 .. 0 => null); + subtype Element_Array_Access is Element_Array_Access_Base; type Array_Base is record - Max_Length : Count_Type; - Elements : Element_Array_Access; + Reference_Count : Reference_Count_Type; + Max_Length : Count_Type; + Elements : Element_Array_Access; + end record; + + type Array_Base_Access is access Array_Base; + + type Array_Base_Controlled_Access is new Ada.Finalization.Controlled + with record + Base : Array_Base_Access; end record; - type Array_Base_Access is not null access Array_Base; + overriding procedure Adjust + (Controlled_Base : in out Array_Base_Controlled_Access); + + overriding procedure Finalize + (Controlled_Base : in out Array_Base_Controlled_Access); + + overriding procedure Adjust + (Ctrl_E : in out Controlled_Element_Access); + + overriding procedure Finalize + (Ctrl_E : in out Controlled_Element_Access); - function Content_Init (L : Count_Type := 0) return Array_Base_Access; + function Content_Init (L : Count_Type := 0) + return Array_Base_Controlled_Access; -- Used to initialize the content of an array base with length L type Container is record - Length : Count_Type := 0; - Base : Array_Base_Access := Content_Init; + Length : Count_Type := 0; + Controlled_Base : Array_Base_Controlled_Access := Content_Init; end record; end Ada.Containers.Functional_Base; diff --git a/gcc/ada/libgnat/a-cofuma.adb b/gcc/ada/libgnat/a-cofuma.adb index 0fcdbdc..f83b4d8 100644 --- a/gcc/ada/libgnat/a-cofuma.adb +++ b/gcc/ada/libgnat/a-cofuma.adb @@ -34,6 +34,9 @@ package body Ada.Containers.Functional_Maps with SPARK_Mode => Off is use Key_Containers; use Element_Containers; + package Conversions is new Signed_Conversions (Int => Count_Type); + use Conversions; + --------- -- "=" -- --------- @@ -245,9 +248,9 @@ package body Ada.Containers.Functional_Maps with SPARK_Mode => Off is -- Length -- ------------ - function Length (Container : Map) return Count_Type is + function Length (Container : Map) return Big_Natural is begin - return Length (Container.Elements); + return To_Big_Integer (Length (Container.Elements)); end Length; ------------ diff --git a/gcc/ada/libgnat/a-cofuma.ads b/gcc/ada/libgnat/a-cofuma.ads index f240e1e..d01c4b4 100644 --- a/gcc/ada/libgnat/a-cofuma.ads +++ b/gcc/ada/libgnat/a-cofuma.ads @@ -32,6 +32,9 @@ pragma Ada_2012; private with Ada.Containers.Functional_Base; +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; + generic type Key_Type (<>) is private; type Element_Type (<>) is private; @@ -97,7 +100,7 @@ package Ada.Containers.Functional_Maps with SPARK_Mode is (Equivalent_Keys (K, Key) = (Witness (Container, Key) = Witness (Container, K))))); - function Length (Container : Map) return Count_Type with + function Length (Container : Map) return Big_Natural with Global => null; -- Return the number of mappings in Container @@ -233,9 +236,7 @@ package Ada.Containers.Functional_Maps with SPARK_Mode is with Global => null, - Pre => - not Has_Key (Container, New_Key) - and Length (Container) < Count_Type'Last, + Pre => not Has_Key (Container, New_Key), Post => Length (Container) + 1 = Length (Add'Result) and Has_Key (Add'Result, New_Key) diff --git a/gcc/ada/libgnat/a-cofuse.adb b/gcc/ada/libgnat/a-cofuse.adb index 77adb1d..bbb3f7e 100644 --- a/gcc/ada/libgnat/a-cofuse.adb +++ b/gcc/ada/libgnat/a-cofuse.adb @@ -34,6 +34,9 @@ pragma Ada_2012; package body Ada.Containers.Functional_Sets with SPARK_Mode => Off is use Containers; + package Conversions is new Signed_Conversions (Int => Count_Type); + use Conversions; + --------- -- "=" -- --------- @@ -135,8 +138,8 @@ package body Ada.Containers.Functional_Sets with SPARK_Mode => Off is -- Length -- ------------ - function Length (Container : Set) return Count_Type is - (Length (Container.Content)); + function Length (Container : Set) return Big_Natural is + (To_Big_Integer (Length (Container.Content))); ----------------- -- Not_In_Both -- @@ -161,8 +164,8 @@ package body Ada.Containers.Functional_Sets with SPARK_Mode => Off is -- Num_Overlaps -- ------------------ - function Num_Overlaps (Left : Set; Right : Set) return Count_Type is - (Num_Overlaps (Left.Content, Right.Content)); + function Num_Overlaps (Left : Set; Right : Set) return Big_Natural is + (To_Big_Integer (Num_Overlaps (Left.Content, Right.Content))); ------------ -- Remove -- diff --git a/gcc/ada/libgnat/a-cofuse.ads b/gcc/ada/libgnat/a-cofuse.ads index 6cd340b..29f1e9f 100644 --- a/gcc/ada/libgnat/a-cofuse.ads +++ b/gcc/ada/libgnat/a-cofuse.ads @@ -32,6 +32,9 @@ pragma Ada_2012; private with Ada.Containers.Functional_Base; +with Ada.Numerics.Big_Numbers.Big_Integers; +use Ada.Numerics.Big_Numbers.Big_Integers; + generic type Element_Type (<>) is private; @@ -79,7 +82,7 @@ package Ada.Containers.Functional_Sets with SPARK_Mode is (if (for some E of Container => Equivalent_Elements (E, Item)) then Contains'Result)); - function Length (Container : Set) return Count_Type with + function Length (Container : Set) return Big_Natural with Global => null; -- Return the number of elements in Container @@ -183,7 +186,7 @@ package Ada.Containers.Functional_Sets with SPARK_Mode is No_Overlap'Result = (for all Item of Left => not Contains (Right, Item)); - function Num_Overlaps (Left : Set; Right : Set) return Count_Type with + function Num_Overlaps (Left : Set; Right : Set) return Big_Natural with -- Number of elements that are both in Left and Right Global => null, @@ -206,9 +209,7 @@ package Ada.Containers.Functional_Sets with SPARK_Mode is -- Return a new set containing all the elements of Container plus E Global => null, - Pre => - not Contains (Container, Item) - and Length (Container) < Count_Type'Last, + Pre => not Contains (Container, Item), Post => Length (Add'Result) = Length (Container) + 1 and Contains (Add'Result, Item) @@ -245,9 +246,6 @@ package Ada.Containers.Functional_Sets with SPARK_Mode is -- Returns the union of Left and Right Global => null, - Pre => - Length (Left) - Num_Overlaps (Left, Right) <= - Count_Type'Last - Length (Right), Post => Length (Union'Result) = Length (Left) - Num_Overlaps (Left, Right) + Length (Right) diff --git a/gcc/ada/libgnat/g-dyntab.ads b/gcc/ada/libgnat/g-dyntab.ads index 7cad735..1cf4877 100644 --- a/gcc/ada/libgnat/g-dyntab.ads +++ b/gcc/ada/libgnat/g-dyntab.ads @@ -82,10 +82,6 @@ package GNAT.Dynamic_Tables is -- freely (expensive reallocation occurs only at major granularity -- chunks controlled by the allocation parameters). - -- Note: we do not make the table components aliased, since this would - -- restrict the use of table for discriminated types. If it is necessary - -- to take the access of a table element, use Unrestricted_Access. - -- WARNING: On HPPA, the virtual addressing approach used in this unit is -- incompatible with the indexing instructions on the HPPA. So when using -- this unit, compile your application with -mdisable-indexing. @@ -120,9 +116,10 @@ package GNAT.Dynamic_Tables is -- freely (expensive reallocation occurs only at major granularity -- chunks controlled by the allocation parameters). - -- Note: we do not make the table components aliased, since this would - -- restrict the use of table for discriminated types. If it is necessary - -- to take the access of a table element, use Unrestricted_Access. + -- Note: For backward compatibility we do not make the table components + -- aliased, since for Ada 95 this would have restricted the use of tables + -- for discriminated types. If it is necessary to take the access of a + -- table element, use Unrestricted_Access. type Table_Type is array (Valid_Table_Index_Type range <>) of Table_Component_Type; diff --git a/gcc/ada/libgnat/i-cstrin.adb b/gcc/ada/libgnat/i-cstrin.adb index e2f0f21..67cceb2 100644 --- a/gcc/ada/libgnat/i-cstrin.adb +++ b/gcc/ada/libgnat/i-cstrin.adb @@ -34,7 +34,9 @@ with System.Storage_Elements; use System.Storage_Elements; with Ada.Unchecked_Conversion; -package body Interfaces.C.Strings is +package body Interfaces.C.Strings with + SPARK_Mode => Off +is -- Note that the type chars_ptr has a pragma No_Strict_Aliasing in the -- spec, to prevent any assumptions about aliasing for values of this type, diff --git a/gcc/ada/libgnat/i-cstrin.ads b/gcc/ada/libgnat/i-cstrin.ads index 5c1b259..12fa301 100644 --- a/gcc/ada/libgnat/i-cstrin.ads +++ b/gcc/ada/libgnat/i-cstrin.ads @@ -33,7 +33,19 @@ -- -- ------------------------------------------------------------------------------ -package Interfaces.C.Strings is +-- 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. These preconditions +-- protect from Dereference_Error and Update_Error, but not from +-- Storage_Error. + +pragma Assertion_Policy (Pre => Ignore); + +package Interfaces.C.Strings with + SPARK_Mode => On, + Abstract_State => (C_Memory), + Initializes => (C_Memory) +is pragma Preelaborate; type char_array_access is access all char_array; @@ -53,47 +65,85 @@ package Interfaces.C.Strings is function To_Chars_Ptr (Item : char_array_access; - Nul_Check : Boolean := False) return chars_ptr; - - function New_Char_Array (Chars : char_array) return chars_ptr; - - function New_String (Str : String) return chars_ptr; - - procedure Free (Item : in out chars_ptr); + Nul_Check : Boolean := False) return chars_ptr + with + SPARK_Mode => Off; + + function New_Char_Array (Chars : char_array) return chars_ptr with + Volatile_Function, + Post => New_Char_Array'Result /= Null_Ptr, + Global => (Input => C_Memory); + + function New_String (Str : String) return chars_ptr with + Volatile_Function, + Post => New_String'Result /= Null_Ptr, + Global => (Input => C_Memory); + + procedure Free (Item : in out chars_ptr) with + SPARK_Mode => Off; -- When deallocation is prohibited (eg: cert runtimes) this routine -- will raise Program_Error Dereference_Error : exception; - function Value (Item : chars_ptr) return char_array; + function Value (Item : chars_ptr) return char_array with + Pre => Item /= Null_Ptr, + Global => (Input => C_Memory); function Value (Item : chars_ptr; - Length : size_t) return char_array; + Length : size_t) return char_array + with + Pre => Item /= Null_Ptr, + Global => (Input => C_Memory); - function Value (Item : chars_ptr) return String; + function Value (Item : chars_ptr) return String with + Pre => Item /= Null_Ptr, + Global => (Input => C_Memory); function Value (Item : chars_ptr; - Length : size_t) return String; + Length : size_t) return String + with + Pre => Item /= Null_Ptr, + Global => (Input => C_Memory); - function Strlen (Item : chars_ptr) return size_t; + function Strlen (Item : chars_ptr) return size_t with + Pre => Item /= Null_Ptr, + Global => (Input => C_Memory); procedure Update (Item : chars_ptr; Offset : size_t; Chars : char_array; - Check : Boolean := True); + Check : Boolean := True) + with + Pre => + Item /= Null_Ptr + and then + (if Check then + Strlen (Item) <= size_t'Last - Offset + and then Strlen (Item) + Offset <= Chars'Length), + Global => (In_Out => C_Memory); procedure Update (Item : chars_ptr; Offset : size_t; Str : String; - Check : Boolean := True); + Check : Boolean := True) + with + Pre => + Item /= Null_Ptr + and then + (if Check then + Strlen (Item) <= size_t'Last - Offset + and then Strlen (Item) + Offset <= Str'Length), + Global => (In_Out => C_Memory); Update_Error : exception; private + pragma SPARK_Mode (Off); type chars_ptr is access all Character; for chars_ptr'Size use System.Parameters.ptr_bits; diff --git a/gcc/ada/libgnat/s-aridou.adb b/gcc/ada/libgnat/s-aridou.adb index 259c0ac..880a899 100644 --- a/gcc/ada/libgnat/s-aridou.adb +++ b/gcc/ada/libgnat/s-aridou.adb @@ -162,7 +162,7 @@ is function To_Neg_Int (A : Double_Uns) return Double_Int with - Annotate => (GNATprove, Terminating), + Annotate => (GNATprove, Always_Return), Pre => In_Double_Int_Range (-Big (A)), Post => Big (To_Neg_Int'Result) = -Big (A); -- Convert to negative integer equivalent. If the input is in the range @@ -172,7 +172,7 @@ is function To_Pos_Int (A : Double_Uns) return Double_Int with - Annotate => (GNATprove, Terminating), + Annotate => (GNATprove, Always_Return), Pre => In_Double_Int_Range (Big (A)), Post => Big (To_Pos_Int'Result) = Big (A); -- Convert to positive integer equivalent. If the input is in the range diff --git a/gcc/ada/libgnat/s-arit32.adb b/gcc/ada/libgnat/s-arit32.adb index 3d500ac..6dac572 100644 --- a/gcc/ada/libgnat/s-arit32.adb +++ b/gcc/ada/libgnat/s-arit32.adb @@ -104,7 +104,7 @@ is function To_Neg_Int (A : Uns32) return Int32 with - Annotate => (GNATprove, Terminating), + Annotate => (GNATprove, Always_Return), Pre => In_Int32_Range (-Big (A)), Post => Big (To_Neg_Int'Result) = -Big (A); -- Convert to negative integer equivalent. If the input is in the range @@ -114,7 +114,7 @@ is function To_Pos_Int (A : Uns32) return Int32 with - Annotate => (GNATprove, Terminating), + Annotate => (GNATprove, Always_Return), Pre => In_Int32_Range (Big (A)), Post => Big (To_Pos_Int'Result) = Big (A); -- Convert to positive integer equivalent. If the input is in the range diff --git a/gcc/ada/libgnat/s-atacco.ads b/gcc/ada/libgnat/s-atacco.ads index 736210d..b3559ff 100644 --- a/gcc/ada/libgnat/s-atacco.ads +++ b/gcc/ada/libgnat/s-atacco.ads @@ -54,8 +54,10 @@ package System.Address_To_Access_Conversions is -- optimizations that may cause unexpected results based on the assumption -- of no strict aliasing. - function To_Pointer (Value : Address) return Object_Pointer; - function To_Address (Value : Object_Pointer) return Address; + function To_Pointer (Value : Address) return Object_Pointer with + Global => null; + function To_Address (Value : Object_Pointer) return Address with + SPARK_Mode => Off; pragma Import (Intrinsic, To_Pointer); pragma Import (Intrinsic, To_Address); diff --git a/gcc/ada/libgnat/s-spcuop.ads b/gcc/ada/libgnat/s-spcuop.ads index 39a61c9..53db0ce 100644 --- a/gcc/ada/libgnat/s-spcuop.ads +++ b/gcc/ada/libgnat/s-spcuop.ads @@ -45,7 +45,7 @@ package System.SPARK.Cut_Operations with SPARK_Mode, Pure, - Annotate => (GNATprove, Terminating) + Annotate => (GNATprove, Always_Return) is function By (Consequence, Premise : Boolean) return Boolean with diff --git a/gcc/ada/libgnat/system-linux-arm.ads b/gcc/ada/libgnat/system-linux-arm.ads index 6f2cb24..996d407 100644 --- a/gcc/ada/libgnat/system-linux-arm.ads +++ b/gcc/ada/libgnat/system-linux-arm.ads @@ -70,7 +70,7 @@ package System is Storage_Unit : constant := 8; Word_Size : constant := Standard'Word_Size; - Memory_Size : constant := 2 ** Long_Integer'Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-qnx-arm.ads b/gcc/ada/libgnat/system-qnx-arm.ads index 5f4b90e..749384f 100644 --- a/gcc/ada/libgnat/system-qnx-arm.ads +++ b/gcc/ada/libgnat/system-qnx-arm.ads @@ -70,7 +70,7 @@ package System is Storage_Unit : constant := 8; Word_Size : constant := Standard'Word_Size; - Memory_Size : constant := 2 ** Long_Integer'Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-aarch64-rtp-smp.ads b/gcc/ada/libgnat/system-vxworks7-aarch64-rtp-smp.ads index 0556cbf..46b740e 100644 --- a/gcc/ada/libgnat/system-vxworks7-aarch64-rtp-smp.ads +++ b/gcc/ada/libgnat/system-vxworks7-aarch64-rtp-smp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 64; - Memory_Size : constant := 2 ** 64; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison @@ -151,6 +151,7 @@ private 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; diff --git a/gcc/ada/libgnat/system-vxworks7-aarch64.ads b/gcc/ada/libgnat/system-vxworks7-aarch64.ads index 8bf58b7..1aba15b 100644 --- a/gcc/ada/libgnat/system-vxworks7-aarch64.ads +++ b/gcc/ada/libgnat/system-vxworks7-aarch64.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 64; - Memory_Size : constant := 2 ** 64; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison @@ -148,6 +148,7 @@ private 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; diff --git a/gcc/ada/libgnat/system-vxworks7-arm-rtp-smp.ads b/gcc/ada/libgnat/system-vxworks7-arm-rtp-smp.ads index 1341b9d..e81348e 100644 --- a/gcc/ada/libgnat/system-vxworks7-arm-rtp-smp.ads +++ b/gcc/ada/libgnat/system-vxworks7-arm-rtp-smp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison @@ -148,6 +148,7 @@ private 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; diff --git a/gcc/ada/libgnat/system-vxworks7-arm.ads b/gcc/ada/libgnat/system-vxworks7-arm.ads index ae09b78..4ced0f1 100644 --- a/gcc/ada/libgnat/system-vxworks7-arm.ads +++ b/gcc/ada/libgnat/system-vxworks7-arm.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison @@ -146,6 +146,7 @@ private 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; diff --git a/gcc/ada/libgnat/system-vxworks7-e500-kernel.ads b/gcc/ada/libgnat/system-vxworks7-e500-kernel.ads index c7b2c97..fb271c3 100644 --- a/gcc/ada/libgnat/system-vxworks7-e500-kernel.ads +++ b/gcc/ada/libgnat/system-vxworks7-e500-kernel.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-e500-rtp-smp.ads b/gcc/ada/libgnat/system-vxworks7-e500-rtp-smp.ads index a9dbf97..b132f91 100644 --- a/gcc/ada/libgnat/system-vxworks7-e500-rtp-smp.ads +++ b/gcc/ada/libgnat/system-vxworks7-e500-rtp-smp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-e500-rtp.ads b/gcc/ada/libgnat/system-vxworks7-e500-rtp.ads index 83e44cb..9ca14b5 100644 --- a/gcc/ada/libgnat/system-vxworks7-e500-rtp.ads +++ b/gcc/ada/libgnat/system-vxworks7-e500-rtp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-ppc-kernel.ads b/gcc/ada/libgnat/system-vxworks7-ppc-kernel.ads index e7dfc29..bddf951 100644 --- a/gcc/ada/libgnat/system-vxworks7-ppc-kernel.ads +++ b/gcc/ada/libgnat/system-vxworks7-ppc-kernel.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-ppc-rtp-smp.ads b/gcc/ada/libgnat/system-vxworks7-ppc-rtp-smp.ads index 146a87b..3ead193 100644 --- a/gcc/ada/libgnat/system-vxworks7-ppc-rtp-smp.ads +++ b/gcc/ada/libgnat/system-vxworks7-ppc-rtp-smp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-ppc-rtp.ads b/gcc/ada/libgnat/system-vxworks7-ppc-rtp.ads index 0e448d4..457e641 100644 --- a/gcc/ada/libgnat/system-vxworks7-ppc-rtp.ads +++ b/gcc/ada/libgnat/system-vxworks7-ppc-rtp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-ppc64-kernel.ads b/gcc/ada/libgnat/system-vxworks7-ppc64-kernel.ads index 70c1e7c..a1a983b 100644 --- a/gcc/ada/libgnat/system-vxworks7-ppc64-kernel.ads +++ b/gcc/ada/libgnat/system-vxworks7-ppc64-kernel.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 64; - Memory_Size : constant := 2 ** 64; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-ppc64-rtp-smp.ads b/gcc/ada/libgnat/system-vxworks7-ppc64-rtp-smp.ads index bb42c6a1..afdd820 100644 --- a/gcc/ada/libgnat/system-vxworks7-ppc64-rtp-smp.ads +++ b/gcc/ada/libgnat/system-vxworks7-ppc64-rtp-smp.ads @@ -71,8 +71,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 64; - Memory_Size : constant := 2 ** 64; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-x86-kernel.ads b/gcc/ada/libgnat/system-vxworks7-x86-kernel.ads index f7be01d..42ae983 100644 --- a/gcc/ada/libgnat/system-vxworks7-x86-kernel.ads +++ b/gcc/ada/libgnat/system-vxworks7-x86-kernel.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-x86-rtp-smp.ads b/gcc/ada/libgnat/system-vxworks7-x86-rtp-smp.ads index 05cadbc..47dd3ae 100644 --- a/gcc/ada/libgnat/system-vxworks7-x86-rtp-smp.ads +++ b/gcc/ada/libgnat/system-vxworks7-x86-rtp-smp.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-x86-rtp.ads b/gcc/ada/libgnat/system-vxworks7-x86-rtp.ads index aebbfd7..7ef6764 100644 --- a/gcc/ada/libgnat/system-vxworks7-x86-rtp.ads +++ b/gcc/ada/libgnat/system-vxworks7-x86-rtp.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 32; - Memory_Size : constant := 2 ** 32; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/libgnat/system-vxworks7-x86_64-kernel.ads b/gcc/ada/libgnat/system-vxworks7-x86_64-kernel.ads index ed9850f..7931241 100644 --- a/gcc/ada/libgnat/system-vxworks7-x86_64-kernel.ads +++ b/gcc/ada/libgnat/system-vxworks7-x86_64-kernel.ads @@ -69,8 +69,8 @@ package System is Null_Address : constant Address; Storage_Unit : constant := 8; - Word_Size : constant := 64; - Memory_Size : constant := 2 ** 64; + Word_Size : constant := Standard'Word_Size; + Memory_Size : constant := 2 ** Word_Size; -- Address comparison diff --git a/gcc/ada/make.adb b/gcc/ada/make.adb index bbabd76..3ed4656 100644 --- a/gcc/ada/make.adb +++ b/gcc/ada/make.adb @@ -44,6 +44,7 @@ with SFN_Scan; with Sinput; with Snames; with Stringt; +with Uintp; pragma Warnings (Off); with System.HTable; @@ -3676,6 +3677,7 @@ package body Make is Linker_Switches.Init; Csets.Initialize; + Uintp.Initialize; Snames.Initialize; Stringt.Initialize; diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads index c2abbce..0490895 100644 --- a/gcc/ada/opt.ads +++ b/gcc/ada/opt.ads @@ -186,12 +186,9 @@ package Opt is Assume_No_Invalid_Values : Boolean := False; -- GNAT Normally, in accordance with (RM 13.9.1 (9-11)) the front end -- assumes that values could have invalid representations, unless it can - -- clearly prove that the values are valid. If this switch is set (by + -- prove that the values are valid. If this switch is set (by -gnatB or -- pragma Assume_No_Invalid_Values (On)), then the compiler assumes values - -- are valid and in range of their representations. This feature is now - -- fully enabled in the compiler. - - -- WARNING: There is a matching C declaration of this variable in fe.h + -- are valid and in range of their representations. Back_Annotate_Rep_Info : Boolean := False; -- GNAT diff --git a/gcc/ada/par-ch3.adb b/gcc/ada/par-ch3.adb index 2359b8c..557a9cb 100644 --- a/gcc/ada/par-ch3.adb +++ b/gcc/ada/par-ch3.adb @@ -3180,7 +3180,8 @@ package body Ch3 is Scan; if Token = Tok_Access then - Error_Msg_SC ("CONSTANT must appear after ACCESS"); + Error_Msg_SC -- CODEFIX + ("ACCESS must come before CONSTANT"); Set_Discriminant_Type (Specification_Node, P_Access_Definition (Not_Null_Present)); @@ -3462,8 +3463,42 @@ package body Ch3 is -- Error recovery: can raise Error_Resync function P_Record_Definition return Node_Id is + + procedure Catch_Out_Of_Order_Keywords (Keyword : String); + -- Catch ouf-of-order keywords in a record definition + + --------------------------------- + -- Catch_Out_Of_Order_Keywords -- + --------------------------------- + + procedure Catch_Out_Of_Order_Keywords (Keyword : String) is + begin + loop + if Token = Tok_Abstract then + Error_Msg_SC -- CODEFIX + ("ABSTRACT must come before " & Keyword); + Scan; -- past ABSTRACT + + elsif Token = Tok_Tagged then + Error_Msg_SC -- CODEFIX + ("TAGGED must come before " & Keyword); + Scan; -- past TAGGED + + elsif Token = Tok_Limited then + Error_Msg_SC -- CODEFIX + ("LIMITED must come before " & Keyword); + Scan; -- past LIMITED + + else + exit; + end if; + end loop; + end Catch_Out_Of_Order_Keywords; + Rec_Node : Node_Id; + -- Start of processing for P_Record_Definition + begin Inside_Record_Definition := True; Rec_Node := New_Node (N_Record_Definition, Token_Ptr); @@ -3472,8 +3507,11 @@ package body Ch3 is if Token = Tok_Null then Scan; -- past NULL + + Catch_Out_Of_Order_Keywords ("NULL"); T_Record; Set_Null_Present (Rec_Node, True); + Catch_Out_Of_Order_Keywords ("RECORD"); -- Catch incomplete declaration to prevent cascaded errors, see -- ACATS B393002 for an example. @@ -3501,6 +3539,7 @@ package body Ch3 is Scopes (Scope.Last).Junk := (Token /= Tok_Record); T_Record; + Catch_Out_Of_Order_Keywords ("RECORD"); Set_Component_List (Rec_Node, P_Component_List); diff --git a/gcc/ada/par-util.adb b/gcc/ada/par-util.adb index 2eabc58..3f1247a 100644 --- a/gcc/ada/par-util.adb +++ b/gcc/ada/par-util.adb @@ -462,7 +462,7 @@ package body Util is declare Tname : constant String := Token_Type'Image (Token); begin - Error_Msg_SC ("|extra " & Tname (5 .. Tname'Last) & "ignored"); + Error_Msg_SC ("|extra " & Tname (5 .. Tname'Last) & " ignored"); end; end if; diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads index 280e2bd..1270955 100644 --- a/gcc/ada/rtsfind.ads +++ b/gcc/ada/rtsfind.ads @@ -540,13 +540,11 @@ package Rtsfind is -- value is required syntactically, but no real entry is required or -- needed. Use of this value will cause a fatal error in an RTE call. - -- Note that under no circumstances can any of these entities be defined - -- more than once in a given package, i.e. no overloading is allowed for - -- any entity that is found using rtsfind. A fatal error is given if this - -- rule is violated. The one exception is for Save_Occurrence, where the - -- RM mandates the overloading. In this case, the compiler only uses the - -- procedure, not the function, and the procedure must come first so that - -- the compiler finds it and not the function. + -- It is normally not allowed to have more than one of these entities with + -- the same name in a given package. The one exception is Save_Occurrence, + -- where the RM mandates the overloading. In this case, the compiler uses + -- the procedure, not the function, and the procedure must come first so + -- that the compiler finds it and not the function. type RE_Id is ( diff --git a/gcc/ada/sem.ads b/gcc/ada/sem.ads index 5a07f06..fa3e9bf 100644 --- a/gcc/ada/sem.ads +++ b/gcc/ada/sem.ads @@ -327,8 +327,8 @@ package Sem is -- using pragma Check_Name), are handled as follows. If a suppress or -- unsuppress pragma is encountered for a given entity, then the flag -- Checks_May_Be_Suppressed is set in the entity and an entry is made in - -- either the Local_Entity_Suppress stack (case of pragma that appears in - -- other than a package spec), or in the Global_Entity_Suppress stack (case + -- either the local suppress stack (case of pragma that appears in + -- other than a package spec), or in the global suppress stack (case -- of pragma that appears in a package spec, which is by the rule of RM -- 11.5(7) applicable throughout the life of the entity). Similarly, a -- Suppress/Unsuppress pragma for a non-predefined check which does not @@ -340,7 +340,7 @@ package Sem is -- other point is that we have to make sure that we have proper nested -- interaction between such specific pragmas and locally applied general -- pragmas applying to all entities. This is achieved by including in the - -- Local_Entity_Suppress table dummy entries with an empty Entity field + -- local suppress stack dummy entries with an empty Entity field -- that are applicable to all entities. A similar search is needed for any -- non-predefined check even if no specific entity is involved. @@ -359,18 +359,18 @@ package Sem is -- applies, and gives the right result when such pragmas are used even -- in complex cases of nested Suppress and Unsuppress pragmas. - -- The Local_Entity_Suppress and Global_Entity_Suppress stacks are handled - -- using dynamic allocation and linked lists. We do not often use this - -- approach in the compiler (preferring to use extensible tables instead). - -- The reason we do it here is that scope stack entries save a pointer to - -- the current local stack top, which is also saved and restored on scope - -- exit. Furthermore for processing of generics we save pointers to the - -- top of the stack, so that the local stack is actually a tree of stacks - -- rather than a single stack, a structure that is easy to represent using - -- linked lists, but impossible to represent using a single table. Note - -- that because of the generic issue, we never release entries in these - -- stacks, but that's no big deal, since we are unlikely to have a huge - -- number of Suppress/Unsuppress entries in a single compilation. + -- The local and global suppress stacks are handled using dynamic + -- allocation and linked lists. We do not often use this approach in the + -- compiler (preferring to use extensible tables instead). The reason we do + -- it here is that scope stack entries save a pointer to the current local + -- stack top, which is also saved and restored on scope exit. Furthermore + -- for processing of generics we save pointers to the top of the stack, so + -- that the local stack is actually a tree of stacks rather than a single + -- stack, a structure that is easy to represent using linked lists, but + -- impossible to represent using a single table. Note that because of the + -- generic issue, we never release entries in these stacks, but that's no + -- big deal, since we are unlikely to have a huge number of + -- Suppress/Unsuppress entries in a single compilation. type Suppress_Stack_Entry; type Suppress_Stack_Entry_Ptr is access all Suppress_Stack_Entry; diff --git a/gcc/ada/sem_ch10.adb b/gcc/ada/sem_ch10.adb index 80a729f..9b9a9f1 100644 --- a/gcc/ada/sem_ch10.adb +++ b/gcc/ada/sem_ch10.adb @@ -31,6 +31,7 @@ with Einfo; use Einfo; with Einfo.Entities; use Einfo.Entities; with Einfo.Utils; use Einfo.Utils; with Errout; use Errout; +with Exp_Disp; use Exp_Disp; with Exp_Put_Image; with Exp_Util; use Exp_Util; with Elists; use Elists; @@ -946,16 +947,14 @@ package body Sem_Ch10 is -- Treat compilation unit pragmas that appear after the library unit - if Present (Pragmas_After (Aux_Decls_Node (N))) then - declare - Prag_Node : Node_Id := First (Pragmas_After (Aux_Decls_Node (N))); - begin - while Present (Prag_Node) loop - Analyze (Prag_Node); - Next (Prag_Node); - end loop; - end; - end if; + declare + Prag_Node : Node_Id := First (Pragmas_After (Aux_Decls_Node (N))); + begin + while Present (Prag_Node) loop + Analyze (Prag_Node); + Next (Prag_Node); + end loop; + end; -- Analyze the contract of a [generic] subprogram that acts as a -- compilation unit after all compilation pragmas have been analyzed. @@ -1002,6 +1001,22 @@ package body Sem_Ch10 is end if; end if; + -- Build dispatch tables of library-level tagged types only now because + -- the generation of distribution stubs above may create some of them. + + if Expander_Active and then Tagged_Type_Expansion then + case Nkind (Unit_Node) is + when N_Package_Declaration | N_Package_Body => + Build_Static_Dispatch_Tables (Unit_Node); + + when N_Package_Instantiation => + Build_Static_Dispatch_Tables (Instance_Spec (Unit_Node)); + + when others => + null; + end case; + end if; + -- Remove unit from visibility, so that environment is clean for the -- next compilation, which is either the main unit or some other unit -- in the context. @@ -3353,19 +3368,17 @@ package body Sem_Ch10 is -- Start of processing for Has_With_Clause begin - if Present (Context_Items (C_Unit)) then - Item := First (Context_Items (C_Unit)); - while Present (Item) loop - if Nkind (Item) = N_With_Clause - and then Limited_Present (Item) = Is_Limited - and then Named_Unit (Item) = Pack - then - return True; - end if; + Item := First (Context_Items (C_Unit)); + while Present (Item) loop + if Nkind (Item) = N_With_Clause + and then Limited_Present (Item) = Is_Limited + and then Named_Unit (Item) = Pack + then + return True; + end if; - Next (Item); - end loop; - end if; + Next (Item); + end loop; return False; end Has_With_Clause; diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb index fdc767e..0b8911b 100644 --- a/gcc/ada/sem_ch13.adb +++ b/gcc/ada/sem_ch13.adb @@ -33,6 +33,7 @@ with Einfo.Entities; use Einfo.Entities; with Einfo.Utils; use Einfo.Utils; with Elists; use Elists; with Errout; use Errout; +with Exp_Ch3; use Exp_Ch3; with Exp_Disp; use Exp_Disp; with Exp_Tss; use Exp_Tss; with Exp_Util; use Exp_Util; @@ -11754,13 +11755,11 @@ package body Sem_Ch13 is Nod1 : Node_Id; begin - if Present (Lst) then - Nod1 := First (Lst); - while Present (Nod1) loop - Check_Expr_Constants (Nod1); - Next (Nod1); - end loop; - end if; + Nod1 := First (Lst); + while Present (Nod1) loop + Check_Expr_Constants (Nod1); + Next (Nod1); + end loop; end Check_List_Constants; -- Start of processing for Check_Constant_Address_Clause @@ -13138,12 +13137,20 @@ package body Sem_Ch13 is end if; end; + -- Before we build a predicate function, ensure that discriminant + -- checking functions are available. The predicate function might + -- need to call these functions if the predicate references + -- any components declared in a variant part. + if Ekind (E) = E_Record_Type and then Has_Discriminants (E) then + Build_Or_Copy_Discr_Checking_Funcs (Parent (E)); + end if; + Build_Predicate_Function (E, N); end if; -- If type has delayed aspects, this is where we do the preanalysis at -- the freeze point, as part of the consistent visibility check. Note - -- that this must be done after calling Build_Predicate_Functions or + -- that this must be done after calling Build_Predicate_Function or -- Build_Invariant_Procedure since these subprograms fix occurrences of -- the subtype name in the saved expression so that they will not cause -- trouble in the preanalysis. diff --git a/gcc/ada/sem_ch2.adb b/gcc/ada/sem_ch2.adb index 4a45b597..6b84af4 100644 --- a/gcc/ada/sem_ch2.adb +++ b/gcc/ada/sem_ch2.adb @@ -26,6 +26,7 @@ with Atree; use Atree; with Einfo; use Einfo; with Einfo.Utils; use Einfo.Utils; +with Ghost; use Ghost; with Namet; use Namet; with Opt; use Opt; with Restrict; use Restrict; @@ -34,6 +35,7 @@ with Sem_Ch8; use Sem_Ch8; with Sem_Dim; use Sem_Dim; with Sinfo; use Sinfo; with Sinfo.Nodes; use Sinfo.Nodes; +with Sinfo.Utils; use Sinfo.Utils; with Stand; use Stand; with Uintp; use Uintp; @@ -77,6 +79,18 @@ package body Sem_Ch2 is Find_Direct_Name (N); end if; + -- A Ghost entity must appear in a specific context. Only do this + -- checking on non-overloaded expressions, as otherwise we need to + -- wait for resolution, and the checking is done in Resolve_Entity_Name. + + if Nkind (N) in N_Expanded_Name | N_Identifier + and then Present (Entity (N)) + and then Is_Ghost_Entity (Entity (N)) + and then not Is_Overloaded (N) + then + Check_Ghost_Context (Entity (N), N); + end if; + Analyze_Dimension (N); end Analyze_Identifier; diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index 34dac1d..2dbba15 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -725,16 +725,6 @@ package body Sem_Ch3 is -- sets the flags SSO_Set_Low_By_Default/SSO_Set_High_By_Default according -- to the setting of Opt.Default_SSO. - function Should_Build_Subtype (T : Entity_Id) return Boolean; - -- When analyzing components or object declarations, it is possible, in - -- some cases, to build subtypes for discriminated types. This is - -- worthwhile to avoid the backend allocating the maximum possible size for - -- objects of the type. - -- In particular, when T is limited, the discriminants and therefore the - -- size of an object of type T cannot change. Furthermore, if T is definite - -- with statically initialized defaulted discriminants, we are able and - -- want to build a constrained subtype of the right size. - procedure Signed_Integer_Type_Declaration (T : Entity_Id; Def : Node_Id); -- Create a new signed integer entity, and apply the constraint to obtain -- the required first named subtype of this type. @@ -876,9 +866,6 @@ package body Sem_Ch3 is Mutate_Ekind (Anon_Type, E_Anonymous_Access_Subprogram_Type); end if; - Set_Can_Use_Internal_Rep - (Anon_Type, not Always_Compatible_Rep_On_Target); - -- If the anonymous access is associated with a protected operation, -- create a reference to it after the enclosing protected definition -- because the itype will be used in the subsequent bodies. @@ -2217,7 +2204,7 @@ package body Sem_Ch3 is -- When possible, build the default subtype - if Should_Build_Subtype (T) then + if Build_Default_Subtype_OK (T) then declare Act_T : constant Entity_Id := Build_Default_Subtype (T, N); @@ -4818,7 +4805,7 @@ package body Sem_Ch3 is -- When possible, build the default subtype - elsif Should_Build_Subtype (T) then + elsif Build_Default_Subtype_OK (T) then if No (E) then Act_T := Build_Default_Subtype (T, N); else @@ -13538,6 +13525,7 @@ package body Sem_Ch3 is Set_Directly_Designated_Type (Def_Id, Desig_Subtype); Set_Depends_On_Private (Def_Id, Has_Private_Component (Def_Id)); Set_Is_Access_Constant (Def_Id, Is_Access_Constant (T)); + Set_Can_Never_Be_Null (Def_Id, Can_Never_Be_Null (T)); Conditional_Delay (Def_Id, T); @@ -22965,80 +22953,6 @@ package body Sem_Ch3 is end if; end Set_Stored_Constraint_From_Discriminant_Constraint; - -------------------------- - -- Should_Build_Subtype -- - -------------------------- - - function Should_Build_Subtype (T : Entity_Id) return Boolean is - - function Default_Discriminant_Values_Known_At_Compile_Time - (T : Entity_Id) return Boolean; - -- For an unconstrained type T, return False if the given type has a - -- discriminant with default value not known at compile time. Return - -- True otherwise. - - --------------------------------------------------------- - -- Default_Discriminant_Values_Known_At_Compile_Time -- - --------------------------------------------------------- - - function Default_Discriminant_Values_Known_At_Compile_Time - (T : Entity_Id) return Boolean - is - Discr : Entity_Id; - DDV : Node_Id; - - begin - - -- If the type has no discriminant, we know them all at compile time - - if not Has_Discriminants (T) then - return True; - end if; - - -- The type has discriminants, check that none of them has a default - -- value not known at compile time. - - Discr := First_Discriminant (T); - - while Present (Discr) loop - DDV := Discriminant_Default_Value (Discr); - - if Present (DDV) and then not Compile_Time_Known_Value (DDV) then - return False; - end if; - - Next_Discriminant (Discr); - end loop; - - return True; - end Default_Discriminant_Values_Known_At_Compile_Time; - - -- Start of processing for Should_Build_Subtype - - begin - - if Is_Constrained (T) then - - -- We won't build a new subtype if T is constrained - - return False; - end if; - - if not Default_Discriminant_Values_Known_At_Compile_Time (T) then - - -- This is a special case of definite subtypes. To allocate a - -- specific size to the subtype, we need to know the value at compile - -- time. This might not be the case if the default value is the - -- result of a function. In that case, the object might be definite - -- and limited but the needed size might not be statically known or - -- too tricky to obtain. In that case, we will not build the subtype. - - return False; - end if; - - return Is_Definite_Subtype (T) and then Is_Limited_View (T); - end Should_Build_Subtype; - ------------------------------------- -- Signed_Integer_Type_Declaration -- ------------------------------------- diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb index 66315ad..c5c8a7c 100644 --- a/gcc/ada/sem_ch5.adb +++ b/gcc/ada/sem_ch5.adb @@ -2019,13 +2019,11 @@ package body Sem_Ch5 is -- Now to analyze the elsif parts if any are present - if Present (Elsif_Parts (N)) then - E := First (Elsif_Parts (N)); - while Present (E) loop - Analyze_Cond_Then (E); - Next (E); - end loop; - end if; + E := First (Elsif_Parts (N)); + while Present (E) loop + Analyze_Cond_Then (E); + Next (E); + end loop; if Present (Else_Statements (N)) then Analyze_Statements (Else_Statements (N)); @@ -2054,13 +2052,11 @@ package body Sem_Ch5 is if Is_True (Expr_Value (Condition (N))) then Remove_Warning_Messages (Else_Statements (N)); - if Present (Elsif_Parts (N)) then - E := First (Elsif_Parts (N)); - while Present (E) loop - Remove_Warning_Messages (Then_Statements (E)); - Next (E); - end loop; - end if; + E := First (Elsif_Parts (N)); + while Present (E) loop + Remove_Warning_Messages (Then_Statements (E)); + Next (E); + end loop; else Remove_Warning_Messages (Then_Statements (N)); @@ -2112,9 +2108,6 @@ package body Sem_Ch5 is -- An implicit label declaration is generated in the innermost enclosing -- declarative part. This is done for labels, and block and loop names. - -- Note: any changes in this routine may need to be reflected in - -- Analyze_Label_Entity. - procedure Analyze_Implicit_Label_Declaration (N : Node_Id) is Id : constant Node_Id := Defining_Identifier (N); begin @@ -2122,6 +2115,13 @@ package body Sem_Ch5 is Mutate_Ekind (Id, E_Label); Set_Etype (Id, Standard_Void_Type); Set_Enclosing_Scope (Id, Current_Scope); + + -- A label declared within a Ghost region becomes Ghost (SPARK RM + -- 6.9(2)). + + if Ghost_Mode > None then + Set_Is_Ghost_Entity (Id); + end if; end Analyze_Implicit_Label_Declaration; ------------------------------ @@ -2881,18 +2881,6 @@ package body Sem_Ch5 is Kill_Current_Values; end Analyze_Label; - -------------------------- - -- Analyze_Label_Entity -- - -------------------------- - - procedure Analyze_Label_Entity (E : Entity_Id) is - begin - Mutate_Ekind (E, E_Label); - Set_Etype (E, Standard_Void_Type); - Set_Enclosing_Scope (E, Current_Scope); - Set_Reachable (E, True); - end Analyze_Label_Entity; - ------------------------------------------ -- Analyze_Loop_Parameter_Specification -- ------------------------------------------ @@ -4056,6 +4044,12 @@ package body Sem_Ch5 is -- range requires the secondary stack. In this case the loop is -- wrapped within a block in order to manage the secondary stack. + -- ??? This overlooks finalization: the loop may leave the secondary + -- stack untouched, but its iterator or discrete range may need + -- finalization, in which case the block is also required. Therefore + -- the criterion must be based on Sem_Util.Requires_Transient_Scope, + -- which happens to be what is currently implemented. + if Present (Iter) then declare Stop_Processing : Boolean; diff --git a/gcc/ada/sem_ch5.ads b/gcc/ada/sem_ch5.ads index 22675c2..f6f6047 100644 --- a/gcc/ada/sem_ch5.ads +++ b/gcc/ada/sem_ch5.ads @@ -45,13 +45,6 @@ package Sem_Ch5 is procedure Analyze_Statements (L : List_Id); procedure Analyze_Target_Name (N : Node_Id); - procedure Analyze_Label_Entity (E : Entity_Id); - -- This procedure performs direct analysis of the label entity E. It - -- is used when a label is created by the expander without bothering - -- to insert an N_Implicit_Label_Declaration in the tree. It also takes - -- care of setting Reachable, since labels defined by the expander can - -- be assumed to be reachable. - procedure Check_Unreachable_Code (N : Node_Id); -- This procedure is called with N being the node for a statement that is -- an unconditional transfer of control or an apparent infinite loop. It diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb index 8ca2974..848c234 100644 --- a/gcc/ada/sem_ch6.adb +++ b/gcc/ada/sem_ch6.adb @@ -570,42 +570,52 @@ package body Sem_Ch6 is -- RM in 4.9(3.2/5-3.4/5) and we flag an error. if Is_Static_Function (Def_Id) then - if not Is_Static_Expression (Expr) then - declare - Exp_Copy : constant Node_Id := New_Copy_Tree (Expr); - begin - Set_Checking_Potentially_Static_Expression (True); + declare + -- If a potentially static expr like "Parameter / 0" + -- is transformed into "(raise Constraint_Error)", then we + -- need to copy the Original_Node. + function Make_Expr_Copy return Node_Id is + (New_Copy_Tree (if Expr in N_Raise_xxx_Error_Id + then Original_Node (Expr) + else Expr)); + begin + if not Is_Static_Expression (Expr) then + declare + Exp_Copy : constant Node_Id := Make_Expr_Copy; + begin + Set_Checking_Potentially_Static_Expression (True); - Preanalyze_Formal_Expression (Exp_Copy, Typ); + Preanalyze_Formal_Expression (Exp_Copy, Typ); - if not Is_Static_Expression (Exp_Copy) then - Error_Msg_N - ("static expression function requires " - & "potentially static expression", Expr); - end if; + if not Is_Static_Expression (Exp_Copy) then + Error_Msg_N + ("static expression function requires " + & "potentially static expression", Expr); + end if; - Set_Checking_Potentially_Static_Expression (False); - end; - end if; + Set_Checking_Potentially_Static_Expression (False); + end; + end if; - -- We also make an additional copy of the expression and - -- replace the expression of the expression function with - -- this copy, because the currently present expression is - -- now associated with the body created for the static - -- expression function, which will later be analyzed and - -- possibly rewritten, and we need to have the separate - -- unanalyzed copy available for use with later static - -- calls. + -- We also make an additional copy of the expression and + -- replace the expression of the expression function with + -- this copy, because the currently present expression is + -- now associated with the body created for the static + -- expression function, which will later be analyzed and + -- possibly rewritten, and we need to have the separate + -- unanalyzed copy available for use with later static + -- calls. - Set_Expression - (Original_Node (Subprogram_Spec (Def_Id)), - New_Copy_Tree (Expr)); + Set_Expression + (Original_Node (Subprogram_Spec (Def_Id)), + Make_Expr_Copy); - -- Mark static expression functions as inlined, to ensure - -- that even calls with nonstatic actuals will be inlined. + -- Mark static expression functions as inlined, to ensure + -- that even calls with nonstatic actuals will be inlined. - Set_Has_Pragma_Inline (Def_Id); - Set_Is_Inlined (Def_Id); + Set_Has_Pragma_Inline (Def_Id); + Set_Is_Inlined (Def_Id); + end; end if; end if; @@ -702,14 +712,12 @@ package body Sem_Ch6 is -- Otherwise analyze the parameters - if Present (Actuals) then - Actual := First (Actuals); - while Present (Actual) loop - Analyze (Actual); - Check_Parameterless_Call (Actual); - Next (Actual); - end loop; - end if; + Actual := First (Actuals); + while Present (Actual) loop + Analyze (Actual); + Check_Parameterless_Call (Actual); + Next (Actual); + end loop; Analyze_Call (N); end Analyze_Function_Call; @@ -2290,15 +2298,13 @@ package body Sem_Ch6 is -- Otherwise analyze the parameters - if Present (Actuals) then - Actual := First (Actuals); + Actual := First (Actuals); - while Present (Actual) loop - Analyze (Actual); - Check_Parameterless_Call (Actual); - Next (Actual); - end loop; - end if; + while Present (Actual) loop + Analyze (Actual); + Check_Parameterless_Call (Actual); + Next (Actual); + end loop; -- Special processing for Elab_Spec, Elab_Body and Elab_Subp_Body calls @@ -3051,31 +3057,27 @@ package body Sem_Ch6 is begin -- Check for aspects that may generate a contract - if Present (Aspect_Specifications (N)) then - Item := First (Aspect_Specifications (N)); - while Present (Item) loop - if Is_Subprogram_Contract_Annotation (Item) then - return True; - end if; + Item := First (Aspect_Specifications (N)); + while Present (Item) loop + if Is_Subprogram_Contract_Annotation (Item) then + return True; + end if; - Next (Item); - end loop; - end if; + Next (Item); + end loop; -- Check for pragmas that may generate a contract - if Present (Decls) then - Item := First (Decls); - while Present (Item) loop - if Nkind (Item) = N_Pragma - and then Is_Subprogram_Contract_Annotation (Item) - then - return True; - end if; + Item := First (Decls); + while Present (Item) loop + if Nkind (Item) = N_Pragma + and then Is_Subprogram_Contract_Annotation (Item) + then + return True; + end if; - Next (Item); - end loop; - end if; + Next (Item); + end loop; return False; end Body_Has_Contract; @@ -3091,41 +3093,37 @@ package body Sem_Ch6 is begin -- Check for SPARK_Mode aspect - if Present (Aspect_Specifications (N)) then - Item := First (Aspect_Specifications (N)); - while Present (Item) loop - if Get_Aspect_Id (Item) = Aspect_SPARK_Mode then - return Get_SPARK_Mode_From_Annotation (Item) = On; - end if; + Item := First (Aspect_Specifications (N)); + while Present (Item) loop + if Get_Aspect_Id (Item) = Aspect_SPARK_Mode then + return Get_SPARK_Mode_From_Annotation (Item) = On; + end if; - Next (Item); - end loop; - end if; + Next (Item); + end loop; -- Check for SPARK_Mode pragma - if Present (Decls) then - Item := First (Decls); - while Present (Item) loop + Item := First (Decls); + while Present (Item) loop - -- Pragmas that apply to a subprogram body are usually grouped - -- together. Look for a potential pragma SPARK_Mode among them. + -- Pragmas that apply to a subprogram body are usually grouped + -- together. Look for a potential pragma SPARK_Mode among them. - if Nkind (Item) = N_Pragma then - if Get_Pragma_Id (Item) = Pragma_SPARK_Mode then - return Get_SPARK_Mode_From_Annotation (Item) = On; - end if; + if Nkind (Item) = N_Pragma then + if Get_Pragma_Id (Item) = Pragma_SPARK_Mode then + return Get_SPARK_Mode_From_Annotation (Item) = On; + end if; - -- Otherwise the first non-pragma declarative item terminates - -- the region where pragma SPARK_Mode may appear. + -- Otherwise the first non-pragma declarative item terminates the + -- region where pragma SPARK_Mode may appear. - else - exit; - end if; + else + exit; + end if; - Next (Item); - end loop; - end if; + Next (Item); + end loop; -- Otherwise, the applicable SPARK_Mode is inherited from the -- enclosing subprogram or package. @@ -4379,25 +4377,15 @@ package body Sem_Ch6 is end if; -- A subprogram body should cause freezing of its own declaration, - -- but if there was no previous explicit declaration, then the - -- subprogram will get frozen too late (there may be code within - -- the body that depends on the subprogram having been frozen, - -- such as uses of extra formals), so we force it to be frozen - -- here. Same holds if the body and spec are compilation units. - -- Finally, if the return type is an anonymous access to protected - -- subprogram, it must be frozen before the body because its - -- expansion has generated an equivalent type that is used when - -- elaborating the body. - - -- An exception in the case of Ada 2012, AI05-177: The bodies - -- created for expression functions do not freeze. - - if No (Spec_Id) - and then Nkind (Original_Node (N)) /= N_Expression_Function + -- so, if the body and spec are compilation units, we must do it + -- manually here. Moreover, if the return type is anonymous access + -- to protected subprogram, it must be frozen before the body + -- because its expansion has generated an equivalent type that is + -- used when elaborating the body. + + if Present (Spec_Id) + and then Nkind (Parent (N)) = N_Compilation_Unit then - Freeze_Before (N, Body_Id); - - elsif Nkind (Parent (N)) = N_Compilation_Unit then Freeze_Before (N, Spec_Id); elsif Is_Access_Subprogram_Type (Etype (Body_Id)) then @@ -4765,13 +4753,35 @@ package body Sem_Ch6 is -- No warnings for expression functions - and then Nkind (Original_Node (N)) /= N_Expression_Function + and then (Nkind (N) /= N_Subprogram_Body + or else not Was_Expression_Function (N)) then Style.Body_With_No_Spec (N); end if; New_Overloaded_Entity (Body_Id); + -- A subprogram body should cause freezing of its own declaration, + -- but if there was no previous explicit declaration, then the + -- subprogram will get frozen too late (there may be code within + -- the body that depends on the subprogram having been frozen, + -- such as uses of extra formals), so we force it to be frozen here. + -- An exception in Ada 2012 is that the body created for expression + -- functions does not freeze. + + if Nkind (N) /= N_Subprogram_Body + or else not Was_Expression_Function (N) + then + -- First clear the Is_Public flag on thunks since they are only + -- referenced locally by dispatch tables and thus never inlined. + + if Is_Thunk (Body_Id) then + Set_Is_Public (Body_Id, False); + end if; + + Freeze_Before (N, Body_Id); + end if; + if Nkind (N) /= N_Subprogram_Body_Stub then Set_Acts_As_Spec (N); Generate_Definition (Body_Id); @@ -5974,7 +5984,7 @@ package body Sem_Ch6 is -- the subprogram is abstract also. This does not apply to renaming -- declarations, where abstractness is inherited, and to subprogram -- bodies generated for stream operations, which become renamings as - -- bodies. + -- bodies. We also skip the check for thunks. -- In case of primitives associated with abstract interface types -- the check is applied later (see Analyze_Subprogram_Declaration). @@ -5983,6 +5993,7 @@ package body Sem_Ch6 is N_Abstract_Subprogram_Declaration | N_Formal_Abstract_Subprogram_Declaration | N_Subprogram_Renaming_Declaration + and then not Is_Thunk (Designator) then if Is_Abstract_Type (Etype (Designator)) then Error_Msg_N @@ -7776,17 +7787,15 @@ package body Sem_Ch6 is Check_Statement_Sequence (Then_Statements (Last_Stm)); Check_Statement_Sequence (Else_Statements (Last_Stm)); - if Present (Elsif_Parts (Last_Stm)) then - declare - Elsif_Part : Node_Id := First (Elsif_Parts (Last_Stm)); + declare + Elsif_Part : Node_Id := First (Elsif_Parts (Last_Stm)); - begin - while Present (Elsif_Part) loop - Check_Statement_Sequence (Then_Statements (Elsif_Part)); - Next (Elsif_Part); - end loop; - end; - end if; + begin + while Present (Elsif_Part) loop + Check_Statement_Sequence (Then_Statements (Elsif_Part)); + Next (Elsif_Part); + end loop; + end; return; @@ -8996,7 +9005,7 @@ package body Sem_Ch6 is -- Local variables Formal_Type : Entity_Id; - P_Formal : Entity_Id := Empty; + P_Formal : Entity_Id; -- Start of processing for Create_Extra_Formals @@ -9008,10 +9017,10 @@ package body Sem_Ch6 is return; end if; - -- No need to generate extra formals in interface thunks whose target - -- primitive has no extra formals. + -- No need to generate extra formals in thunks whose target has no extra + -- formals, but we can have two of them chained (interface and stack). - if Is_Thunk (E) and then No (Extra_Formals (Thunk_Entity (E))) then + if Is_Thunk (E) and then No (Extra_Formals (Thunk_Target (E))) then return; end if; @@ -9021,6 +9030,8 @@ package body Sem_Ch6 is if Is_Overloadable (E) and then Present (Alias (E)) then P_Formal := First_Formal (Alias (E)); + else + P_Formal := Empty; end if; Formal := First_Formal (E); diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb index 03aecc0..31c04ad 100644 --- a/gcc/ada/sem_ch7.adb +++ b/gcc/ada/sem_ch7.adb @@ -304,6 +304,46 @@ package body Sem_Ch7 is Decl_Id : Entity_Id; In_Instance : Boolean; Spec : Node_Id; + Ignore : Boolean; + + function Set_Referencer_Of_Non_Subprograms return Boolean; + -- Set Has_Referencer_Of_Non_Subprograms and call + -- Scan_Subprogram_Refs if relevant. + -- Return whether Scan_Subprogram_Refs was called. + + --------------------------------------- + -- Set_Referencer_Of_Non_Subprograms -- + --------------------------------------- + + function Set_Referencer_Of_Non_Subprograms return Boolean is + begin + -- An inlined subprogram body acts as a referencer + -- unless we generate C code since inlining is then + -- handled by the C compiler. + + -- Note that we test Has_Pragma_Inline here in addition + -- to Is_Inlined. We are doing this for a client, since + -- we are computing which entities should be public, and + -- it is the client who will decide if actual inlining + -- should occur, so we need to catch all cases where the + -- subprogram may be inlined by the client. + + if (not CCG_Mode or else Has_Pragma_Inline_Always (Decl_Id)) + and then (Is_Inlined (Decl_Id) + or else Has_Pragma_Inline (Decl_Id)) + then + Has_Referencer_Of_Non_Subprograms := True; + + -- Inspect the statements of the subprogram body + -- to determine whether the body references other + -- subprograms. + + Scan_Subprogram_Refs (Decl); + return True; + else + return False; + end if; + end Set_Referencer_Of_Non_Subprograms; begin if No (Decls) then @@ -398,54 +438,17 @@ package body Sem_Ch7 is return True; end if; - -- An inlined subprogram body acts as a referencer - -- unless we generate C code since inlining is then - -- handled by the C compiler. - - -- Note that we test Has_Pragma_Inline here in addition - -- to Is_Inlined. We are doing this for a client, since - -- we are computing which entities should be public, and - -- it is the client who will decide if actual inlining - -- should occur, so we need to catch all cases where the - -- subprogram may be inlined by the client. - - if not CCG_Mode - and then (Is_Inlined (Decl_Id) - or else Has_Pragma_Inline (Decl_Id)) - then - Has_Referencer_Of_Non_Subprograms := True; - - -- Inspect the statements of the subprogram body - -- to determine whether the body references other - -- subprograms. - - Scan_Subprogram_Refs (Decl); - end if; + Ignore := Set_Referencer_Of_Non_Subprograms; -- Otherwise this is a stand alone subprogram body else Decl_Id := Defining_Entity (Decl); - -- An inlined subprogram body acts as a referencer - -- unless we generate C code since inlining is then - -- handled by the C compiler. - - if not CCG_Mode - and then (Is_Inlined (Decl_Id) - or else Has_Pragma_Inline (Decl_Id)) + if not Set_Referencer_Of_Non_Subprograms + and then not Subprogram_Table.Get (Decl_Id) then - Has_Referencer_Of_Non_Subprograms := True; - - -- Inspect the statements of the subprogram body - -- to determine whether the body references other - -- subprograms. - - Scan_Subprogram_Refs (Decl); - - -- Otherwise we can reset Is_Public right away - - elsif not Subprogram_Table.Get (Decl_Id) then + -- We can reset Is_Public right away Set_Is_Public (Decl_Id, False); end if; end if; diff --git a/gcc/ada/sem_ch8.adb b/gcc/ada/sem_ch8.adb index 35a9054..0e75bb4 100644 --- a/gcc/ada/sem_ch8.adb +++ b/gcc/ada/sem_ch8.adb @@ -9831,22 +9831,20 @@ package body Sem_Ch8 is Decl : Node_Id; begin - if Present (L) then - Decl := First (L); - while Present (Decl) loop - if Nkind (Decl) = N_Use_Package_Clause then - Chain_Use_Clause (Decl); - Use_One_Package (Decl, Name (Decl)); + Decl := First (L); + while Present (Decl) loop + if Nkind (Decl) = N_Use_Package_Clause then + Chain_Use_Clause (Decl); + Use_One_Package (Decl, Name (Decl)); - elsif Nkind (Decl) = N_Use_Type_Clause then - Chain_Use_Clause (Decl); - Use_One_Type (Subtype_Mark (Decl)); + elsif Nkind (Decl) = N_Use_Type_Clause then + Chain_Use_Clause (Decl); + Use_One_Type (Subtype_Mark (Decl)); - end if; + end if; - Next (Decl); - end loop; - end if; + Next (Decl); + end loop; end Set_Use; ----------------------------- @@ -10326,6 +10324,11 @@ package body Sem_Ch8 is -- Potentially use-visible entity remains hidden + if Warn_On_Hiding then + Warn_On_Hiding_Entity (N, Hidden => Id, Visible => Prev, + On_Use_Clause => True); + end if; + goto Next_Usable_Entity; -- A use clause within an instance hides outer global entities, diff --git a/gcc/ada/sem_disp.adb b/gcc/ada/sem_disp.adb index 3e75a47..7bead6b 100644 --- a/gcc/ada/sem_disp.adb +++ b/gcc/ada/sem_disp.adb @@ -296,6 +296,12 @@ package body Sem_Disp is Ctrl_Type : Entity_Id; begin + -- We skip the check for thunks + + if Is_Thunk (Subp) then + return; + end if; + Formal := First_Formal (Subp); while Present (Formal) loop Ctrl_Type := Check_Controlling_Type (Etype (Formal), Subp); @@ -1516,11 +1522,10 @@ package body Sem_Disp is ("\spec should appear immediately after the type!", Subp); - elsif Is_Frozen (Subp) then + else -- The subprogram body declares a primitive operation. - -- If the subprogram is already frozen, we must update - -- its dispatching information explicitly here. The + -- We must update its dispatching information here. The -- information is taken from the overridden subprogram. -- We must also generate a cross-reference entry because -- references to other primitives were already created @@ -1728,7 +1733,11 @@ package body Sem_Disp is -- emitted after those tables are built, to prevent access before -- elaboration in gigi. - if Body_Is_Last_Primitive and then Expander_Active then + if Body_Is_Last_Primitive + and then not Building_Static_DT (Tagged_Type) + and then Expander_Active + and then Tagged_Type_Expansion + then declare Subp_Body : constant Node_Id := Unit_Declaration_Node (Subp); Elmt : Elmt_Id; @@ -1739,13 +1748,9 @@ package body Sem_Disp is while Present (Elmt) loop Prim := Node (Elmt); - -- No code required to register primitives in VM targets - if Present (Alias (Prim)) and then Present (Interface_Alias (Prim)) and then Alias (Prim) = Subp - and then not Building_Static_DT (Tagged_Type) - and then Tagged_Type_Expansion then Insert_Actions_After (Subp_Body, Register_Primitive (Sloc (Subp_Body), Prim => Prim)); diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb index 0d5befc..077c988 100644 --- a/gcc/ada/sem_elab.adb +++ b/gcc/ada/sem_elab.adb @@ -18910,18 +18910,16 @@ package body Sem_Elab is procedure Collect_Tasks (Decls : List_Id) is begin - if Present (Decls) then - Decl := First (Decls); - while Present (Decl) loop - if Nkind (Decl) = N_Object_Declaration - and then Has_Task (Etype (Defining_Identifier (Decl))) - then - Add_Task_Proc (Etype (Defining_Identifier (Decl))); - end if; + Decl := First (Decls); + while Present (Decl) loop + if Nkind (Decl) = N_Object_Declaration + and then Has_Task (Etype (Defining_Identifier (Decl))) + then + Add_Task_Proc (Etype (Defining_Identifier (Decl))); + end if; - Next (Decl); - end loop; - end if; + Next (Decl); + end loop; end Collect_Tasks; ---------------- diff --git a/gcc/ada/sem_eval.adb b/gcc/ada/sem_eval.adb index 553c7e1..114c904 100644 --- a/gcc/ada/sem_eval.adb +++ b/gcc/ada/sem_eval.adb @@ -7485,17 +7485,15 @@ package body Sem_Eval is return; end if; - if Present (Expressions (N)) then - Exp := First (Expressions (N)); - while Present (Exp) loop - if Raises_Constraint_Error (Exp) then - Why_Not_Static (Exp); - return; - end if; + Exp := First (Expressions (N)); + while Present (Exp) loop + if Raises_Constraint_Error (Exp) then + Why_Not_Static (Exp); + return; + end if; - Next (Exp); - end loop; - end if; + Next (Exp); + end loop; -- Special case a subtype name diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 8cc42c6..4d67841 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -2139,11 +2139,24 @@ package body Sem_Prag is Expr : Node_Id; begin - -- Do not analyze the pragma multiple times, but set the output - -- parameter to the argument specified by the pragma. + -- Ensure that the Boolean expression (if present) is static. A missing + -- argument defaults the value to True (SPARK RM 7.1.2(5)). + + Expr_Val := True; + + if Present (Arg1) then + Expr := Get_Pragma_Arg (Arg1); + + if Is_OK_Static_Expression (Expr) then + Expr_Val := Is_True (Expr_Value (Expr)); + end if; + end if; + + -- The output parameter was set to the argument specified by the pragma. + -- Do not analyze the pragma multiple times. if Is_Analyzed_Pragma (N) then - goto Leave; + return; end if; Error_Msg_Name_1 := Pragma_Name (N); @@ -2163,9 +2176,11 @@ package body Sem_Prag is if Ekind (Obj_Id) = E_Variable and then No_Caching_Enabled (Obj_Id) then - SPARK_Msg_N - ("illegal combination of external property % and property " - & """No_Caching"" (SPARK RM 7.1.2(6))", N); + if Expr_Val then -- Confirming value of False is allowed + SPARK_Msg_N + ("illegal combination of external property % and property " + & """No_Caching"" (SPARK RM 7.1.2(6))", N); + end if; else SPARK_Msg_N ("external property % must apply to a volatile type or object", @@ -2185,22 +2200,6 @@ package body Sem_Prag is end if; Set_Is_Analyzed_Pragma (N); - - <<Leave>> - - -- Ensure that the Boolean expression (if present) is static. A missing - -- argument defaults the value to True (SPARK RM 7.1.2(5)). - - Expr_Val := True; - - if Present (Arg1) then - Expr := Get_Pragma_Arg (Arg1); - - if Is_OK_Static_Expression (Expr) then - Expr_Val := Is_True (Expr_Value (Expr)); - end if; - end if; - end Analyze_External_Property_In_Decl_Part; --------------------------------- @@ -3293,27 +3292,25 @@ package body Sem_Prag is -- Collect all objects that appear in the visible declarations of the -- related package. - if Present (Visible_Declarations (Pack_Spec)) then - Decl := First (Visible_Declarations (Pack_Spec)); - while Present (Decl) loop - if Comes_From_Source (Decl) - and then Nkind (Decl) in N_Object_Declaration - | N_Object_Renaming_Declaration - then - Append_New_Elmt (Defining_Entity (Decl), States_And_Objs); + Decl := First (Visible_Declarations (Pack_Spec)); + while Present (Decl) loop + if Comes_From_Source (Decl) + and then Nkind (Decl) in N_Object_Declaration + | N_Object_Renaming_Declaration + then + Append_New_Elmt (Defining_Entity (Decl), States_And_Objs); - elsif Nkind (Decl) = N_Package_Declaration then - Collect_States_And_Objects (Decl); + elsif Nkind (Decl) = N_Package_Declaration then + Collect_States_And_Objects (Decl); - elsif Is_Single_Concurrent_Type_Declaration (Decl) then - Append_New_Elmt - (Anonymous_Object (Defining_Entity (Decl)), - States_And_Objs); - end if; + elsif Is_Single_Concurrent_Type_Declaration (Decl) then + Append_New_Elmt + (Anonymous_Object (Defining_Entity (Decl)), + States_And_Objs); + end if; - Next (Decl); - end loop; - end if; + Next (Decl); + end loop; end Collect_States_And_Objects; -- Local variables @@ -11001,7 +10998,7 @@ package body Sem_Prag is Scope_Suppress.Suppress (C) := Suppress_Case; end if; - -- Also make an entry in the Local_Entity_Suppress table + -- Also push an entry in the local suppress stack Push_Local_Suppress_Stack_Entry (Entity => Empty, diff --git a/gcc/ada/sem_prag.ads b/gcc/ada/sem_prag.ads index 44590ac..0a1ad5b 100644 --- a/gcc/ada/sem_prag.ads +++ b/gcc/ada/sem_prag.ads @@ -149,6 +149,7 @@ package Sem_Prag is Pragma_Precondition => True, Pragma_Predicate => True, Pragma_Refined_Post => True, + Pragma_Subprogram_Variant => True, Pragma_Test_Case => True, Pragma_Type_Invariant => True, Pragma_Type_Invariant_Class => True, diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb index 4ffb64c..7d595eb 100644 --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -2060,7 +2060,11 @@ package body Sem_Res is -- case of Ada 2012 constructs such as quantified expressions, which are -- expanded in two separate steps. - if GNATprove_Mode then + -- We also do not want to suppress checks if we are not dealing + -- with a default expression. One such case that is known to reach + -- this point is the expression of an expression function. + + if GNATprove_Mode or Nkind (Parent (N)) = N_Simple_Return_Statement then Analyze_And_Resolve (N, T); else Analyze_And_Resolve (N, T, Suppress => All_Checks); @@ -6955,8 +6959,7 @@ package body Sem_Res is and then Requires_Transient_Scope (Etype (Nam)) and then not Is_Ignored_Ghost_Entity (Nam) then - Establish_Transient_Scope - (N, Returns_On_Secondary_Stack (Etype (Nam))); + Establish_Transient_Scope (N, Needs_Secondary_Stack (Etype (Nam))); -- If the call appears within the bounds of a loop, it will be -- rewritten and reanalyzed, nothing left to do here. @@ -8536,8 +8539,7 @@ package body Sem_Res is elsif Expander_Active and then Requires_Transient_Scope (Etype (Nam)) then - Establish_Transient_Scope - (N, Returns_On_Secondary_Stack (Etype (Nam))); + Establish_Transient_Scope (N, Needs_Secondary_Stack (Etype (Nam))); end if; -- Now we know that this is not a call to a function that returns an diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index 7cfd5f4..9f861a2 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -31,6 +31,7 @@ with Elists; use Elists; with Errout; use Errout; with Erroutc; use Erroutc; with Exp_Ch3; use Exp_Ch3; +with Exp_Ch6; use Exp_Ch6; with Exp_Ch11; use Exp_Ch11; with Exp_Util; use Exp_Util; with Fname; use Fname; @@ -2533,6 +2534,80 @@ package body Sem_Util is end; end Build_Default_Subtype; + ------------------------------ + -- Build_Default_Subtype_OK -- + ------------------------------ + + function Build_Default_Subtype_OK (T : Entity_Id) return Boolean is + + function Default_Discriminant_Values_Known_At_Compile_Time + (T : Entity_Id) return Boolean; + -- For an unconstrained type T, return False if the given type has a + -- discriminant with default value not known at compile time. Return + -- True otherwise. + + --------------------------------------------------------- + -- Default_Discriminant_Values_Known_At_Compile_Time -- + --------------------------------------------------------- + + function Default_Discriminant_Values_Known_At_Compile_Time + (T : Entity_Id) return Boolean + is + Discr : Entity_Id; + DDV : Node_Id; + + begin + + -- If the type has no discriminant, we know them all at compile time + + if not Has_Discriminants (T) then + return True; + end if; + + -- The type has discriminants, check that none of them has a default + -- value not known at compile time. + + Discr := First_Discriminant (T); + + while Present (Discr) loop + DDV := Discriminant_Default_Value (Discr); + + if Present (DDV) and then not Compile_Time_Known_Value (DDV) then + return False; + end if; + + Next_Discriminant (Discr); + end loop; + + return True; + end Default_Discriminant_Values_Known_At_Compile_Time; + + -- Start of processing for Build_Default_Subtype_OK + + begin + + if Is_Constrained (T) then + + -- We won't build a new subtype if T is constrained + + return False; + end if; + + if not Default_Discriminant_Values_Known_At_Compile_Time (T) then + + -- This is a special case of definite subtypes. To allocate a + -- specific size to the subtype, we need to know the value at compile + -- time. This might not be the case if the default value is the + -- result of a function. In that case, the object might be definite + -- and limited but the needed size might not be statically known or + -- too tricky to obtain. In that case, we will not build the subtype. + + return False; + end if; + + return Is_Definite_Subtype (T) and then Is_Limited_View (T); + end Build_Default_Subtype_OK; + -------------------------------------------- -- Build_Discriminal_Subtype_Of_Component -- -------------------------------------------- @@ -6807,19 +6882,25 @@ package body Sem_Util is ---------------------------- procedure Compute_Returns_By_Ref (Func : Entity_Id) is - Typ : constant Entity_Id := Etype (Func); + Kind : constant Entity_Kind := Ekind (Func); + Typ : constant Entity_Id := Etype (Func); begin - if Is_Limited_View (Typ) then + -- Nothing to do for procedures + + if Kind in E_Procedure | E_Generic_Procedure + or else (Kind = E_Subprogram_Type and then Typ = Standard_Void_Type) + then + null; + + -- The build-in-place protocols return a reference to the result + + elsif Is_Build_In_Place_Function (Func) then Set_Returns_By_Ref (Func); - -- For class-wide types and types which both need finalization and are - -- returned on the secondary stack, the secondary stack allocation is - -- done by the front end, see Expand_Simple_Function_Return. + -- In Ada 95, limited types are returned by reference - elsif Returns_On_Secondary_Stack (Typ) - and then CW_Or_Needs_Finalization (Underlying_Type (Typ)) - then + elsif Is_Limited_View (Typ) then Set_Returns_By_Ref (Func); end if; end Compute_Returns_By_Ref; @@ -7048,16 +7129,14 @@ package body Sem_Util is -- Create new entities for the formal parameters - if Present (Parameter_Specifications (Result)) then - Formal_Spec := First (Parameter_Specifications (Result)); - while Present (Formal_Spec) loop - Def_Id := Defining_Identifier (Formal_Spec); - Set_Defining_Identifier (Formal_Spec, - Make_Defining_Identifier (Sloc (Def_Id), Chars (Def_Id))); + Formal_Spec := First (Parameter_Specifications (Result)); + while Present (Formal_Spec) loop + Def_Id := Defining_Identifier (Formal_Spec); + Set_Defining_Identifier (Formal_Spec, + Make_Defining_Identifier (Sloc (Def_Id), Chars (Def_Id))); - Next (Formal_Spec); - end loop; - end if; + Next (Formal_Spec); + end loop; return Result; end Copy_Subprogram_Spec; @@ -8825,47 +8904,9 @@ package body Sem_Util is -- Warn if new entity hides an old one - if Warn_On_Hiding and then Present (C) - - -- Don't warn for record components since they always have a well - -- defined scope which does not confuse other uses. Note that in - -- some cases, Ekind has not been set yet. - - and then Ekind (C) /= E_Component - and then Ekind (C) /= E_Discriminant - and then Nkind (Parent (C)) /= N_Component_Declaration - and then Ekind (Def_Id) /= E_Component - and then Ekind (Def_Id) /= E_Discriminant - and then Nkind (Parent (Def_Id)) /= N_Component_Declaration - - -- Don't warn for one character variables. It is too common to use - -- such variables as locals and will just cause too many false hits. - - and then Length_Of_Name (Chars (C)) /= 1 - - -- Don't warn for non-source entities - - and then Comes_From_Source (C) - and then Comes_From_Source (Def_Id) - - -- Don't warn within a generic instantiation - - and then not In_Instance - - -- Don't warn unless entity in question is in extended main source - - and then In_Extended_Main_Source_Unit (Def_Id) - - -- Finally, the hidden entity must be either immediately visible or - -- use visible (i.e. from a used package). - - and then - (Is_Immediately_Visible (C) - or else - Is_Potentially_Use_Visible (C)) - then - Error_Msg_Sloc := Sloc (C); - Error_Msg_N ("declaration hides &#?h?", Def_Id); + if Warn_On_Hiding and then Present (C) then + Warn_On_Hiding_Entity (Def_Id, Hidden => C, Visible => Def_Id, + On_Use_Clause => False); end if; end Enter_Name; @@ -19052,13 +19093,11 @@ package body Sem_Util is Nod : Node_Id; begin - if Present (List) then - Nod := First (List); - while Present (Nod) loop - Visit (Nod); - Next (Nod); - end loop; - end if; + Nod := First (List); + while Present (Nod) loop + Visit (Nod); + Next (Nod); + end loop; end Visit_List; ------------------ @@ -23229,6 +23268,268 @@ package body Sem_Util is end if; end Needs_Result_Accessibility_Level; + ---------------------------- + -- Needs_Secondary_Stack -- + ---------------------------- + + function Needs_Secondary_Stack (Id : Entity_Id) return Boolean is + pragma Assert (if Present (Id) then Ekind (Id) in E_Void | Type_Kind); + + function Caller_Known_Size_Record (Typ : Entity_Id) return Boolean; + -- Called for untagged record and protected types. Return True if the + -- size of function results is known in the caller for Typ. + + function Large_Max_Size_Mutable (Typ : Entity_Id) return Boolean; + -- Returns True if Typ is a nonlimited record with defaulted + -- discriminants whose max size makes it unsuitable for allocating on + -- the primary stack. + + ------------------------------ + -- Caller_Known_Size_Record -- + ------------------------------ + + function Caller_Known_Size_Record (Typ : Entity_Id) return Boolean is + pragma Assert (Typ = Underlying_Type (Typ)); + + function Depends_On_Discriminant (Typ : Entity_Id) return Boolean; + -- Called for untagged record and protected types. Return True if Typ + -- depends on discriminants, either directly when it is unconstrained + -- or indirectly when it is constrained by uplevel discriminants. + + ----------------------------- + -- Depends_On_Discriminant -- + ----------------------------- + + function Depends_On_Discriminant (Typ : Entity_Id) return Boolean is + Cons : Elmt_Id; + + begin + if Has_Discriminants (Typ) then + if not Is_Constrained (Typ) then + return True; + + else + Cons := First_Elmt (Discriminant_Constraint (Typ)); + while Present (Cons) loop + if Nkind (Node (Cons)) = N_Identifier + and then Ekind (Entity (Node (Cons))) = E_Discriminant + then + return True; + end if; + + Next_Elmt (Cons); + end loop; + end if; + end if; + + return False; + end Depends_On_Discriminant; + + begin + -- First see if we have a variant part and return False if it depends + -- on discriminants. + + if Has_Variant_Part (Typ) and then Depends_On_Discriminant (Typ) then + return False; + end if; + + -- Then loop over components and return False if their subtype has a + -- caller-unknown size, possibly recursively. + + -- ??? This is overly conservative, an array could be nested inside + -- some other record that is constrained by nondiscriminants. That + -- is, the recursive calls are too conservative. + + declare + Comp : Entity_Id; + + begin + Comp := First_Component (Typ); + while Present (Comp) loop + declare + Comp_Type : constant Entity_Id := + Underlying_Type (Etype (Comp)); + + begin + if Is_Record_Type (Comp_Type) + or else + Is_Protected_Type (Comp_Type) + then + if not Caller_Known_Size_Record (Comp_Type) then + return False; + end if; + + elsif Is_Array_Type (Comp_Type) then + if Size_Depends_On_Discriminant (Comp_Type) then + return False; + end if; + end if; + end; + + Next_Component (Comp); + end loop; + end; + + return True; + end Caller_Known_Size_Record; + + ------------------------------ + -- Large_Max_Size_Mutable -- + ------------------------------ + + function Large_Max_Size_Mutable (Typ : Entity_Id) return Boolean is + pragma Assert (Typ = Underlying_Type (Typ)); + + function Is_Large_Discrete_Type (T : Entity_Id) return Boolean; + -- Returns true if the discrete type T has a large range + + ---------------------------- + -- Is_Large_Discrete_Type -- + ---------------------------- + + function Is_Large_Discrete_Type (T : Entity_Id) return Boolean is + Threshold : constant Int := 16; + -- Arbitrary threshold above which we consider it "large". We want + -- a fairly large threshold, because these large types really + -- shouldn't have default discriminants in the first place, in + -- most cases. + + begin + return UI_To_Int (RM_Size (T)) > Threshold; + end Is_Large_Discrete_Type; + + -- Start of processing for Large_Max_Size_Mutable + + begin + if Is_Record_Type (Typ) + and then not Is_Limited_View (Typ) + and then Has_Defaulted_Discriminants (Typ) + then + -- Loop through the components, looking for an array whose upper + -- bound(s) depends on discriminants, where both the subtype of + -- the discriminant and the index subtype are too large. + + declare + Comp : Entity_Id; + + begin + Comp := First_Component (Typ); + while Present (Comp) loop + declare + Comp_Type : constant Entity_Id := + Underlying_Type (Etype (Comp)); + + Hi : Node_Id; + Indx : Node_Id; + Ityp : Entity_Id; + + begin + if Is_Array_Type (Comp_Type) then + Indx := First_Index (Comp_Type); + + while Present (Indx) loop + Ityp := Etype (Indx); + Hi := Type_High_Bound (Ityp); + + if Nkind (Hi) = N_Identifier + and then Ekind (Entity (Hi)) = E_Discriminant + and then Is_Large_Discrete_Type (Ityp) + and then Is_Large_Discrete_Type + (Etype (Entity (Hi))) + then + return True; + end if; + + Next_Index (Indx); + end loop; + end if; + end; + + Next_Component (Comp); + end loop; + end; + end if; + + return False; + end Large_Max_Size_Mutable; + + -- Local declarations + + Typ : constant Entity_Id := Underlying_Type (Id); + + -- Start of processing for Needs_Secondary_Stack + + begin + -- This is a private type which is not completed yet. This can only + -- happen in a default expression (of a formal parameter or of a + -- record component). Do not expand transient scope in this case. + + if No (Typ) then + return False; + end if; + + -- Do not expand transient scope for non-existent procedure return or + -- string literal types. + + if Typ = Standard_Void_Type + or else Ekind (Typ) = E_String_Literal_Subtype + then + return False; + + -- If Typ is a generic formal incomplete type, then we want to look at + -- the actual type. + + elsif Ekind (Typ) = E_Record_Subtype + and then Present (Cloned_Subtype (Typ)) + then + return Needs_Secondary_Stack (Cloned_Subtype (Typ)); + + -- Class-wide types obviously have an unknown size. For specific tagged + -- types, if a call returning one of them is dispatching on result, and + -- this type is not returned on the secondary stack, then the call goes + -- through a thunk that only moves the result from the primary onto the + -- secondary stack, because the computation of the size of the result is + -- possible but complex from the outside. + + elsif Is_Class_Wide_Type (Typ) then + return True; + + -- If the return slot of the back end cannot be accessed, then there + -- is no way to call Adjust at the right time for the return object if + -- the type needs finalization, so the return object must be allocated + -- on the secondary stack. + + elsif not Back_End_Return_Slot and then Needs_Finalization (Typ) then + return True; + + -- Definite subtypes have a known size. This includes all elementary + -- types. Tasks have a known size even if they have discriminants, so + -- we return False here, with one exception: + -- For a type like: + -- type T (Last : Natural := 0) is + -- X : String (1 .. Last); + -- end record; + -- we return True. That's because for "P(F(...));", where F returns T, + -- we don't know the size of the result at the call site, so if we + -- allocated it on the primary stack, we would have to allocate the + -- maximum size, which is way too big. + + elsif Is_Definite_Subtype (Typ) or else Is_Task_Type (Typ) then + return Large_Max_Size_Mutable (Typ); + + -- Indefinite (discriminated) record or protected type + + elsif Is_Record_Type (Typ) or else Is_Protected_Type (Typ) then + return not Caller_Known_Size_Record (Typ); + + -- Unconstrained array + + else + pragma Assert (Is_Array_Type (Typ) and not Is_Definite_Subtype (Typ)); + return True; + end if; + end Needs_Secondary_Stack; + --------------------------------- -- Needs_Simple_Initialization -- --------------------------------- @@ -27015,7 +27316,7 @@ package body Sem_Util is -- The setting of the attributes is intentionally conservative. This -- prevents accidental clobbering of enabled attributes. We need to -- call Base_Type twice, because it is sometimes not set to an actual - -- base type. + -- base type??? if Has_Inherited_DIC (From_Typ) then Set_Has_Inherited_DIC (Base_Type (Base_Type (Typ))); @@ -27065,14 +27366,14 @@ package body Sem_Util is -- The setting of the attributes is intentionally conservative. This -- prevents accidental clobbering of enabled attributes. We need to -- call Base_Type twice, because it is sometimes not set to an actual - -- base type. + -- base type??? if Has_Inheritable_Invariants (From_Typ) then - Set_Has_Inheritable_Invariants (Typ); + Set_Has_Inheritable_Invariants (Base_Type (Base_Type (Typ))); end if; if Has_Inherited_Invariants (From_Typ) then - Set_Has_Inherited_Invariants (Typ); + Set_Has_Inherited_Invariants (Base_Type (Base_Type (Typ))); end if; if Has_Own_Invariants (From_Typ) then @@ -27370,7 +27671,7 @@ package body Sem_Util is function Requires_Transient_Scope (Typ : Entity_Id) return Boolean is begin - return Returns_On_Secondary_Stack (Typ) or else Needs_Finalization (Typ); + return Needs_Secondary_Stack (Typ) or else Needs_Finalization (Typ); end Requires_Transient_Scope; -------------------------- @@ -27418,234 +27719,6 @@ package body Sem_Util is SPARK_Mode_Pragma := Prag; end Restore_SPARK_Mode; - --------------------------------- - -- Returns_On_Secondary_Stack -- - --------------------------------- - - function Returns_On_Secondary_Stack (Id : Entity_Id) return Boolean is - pragma Assert (if Present (Id) then Ekind (Id) in E_Void | Type_Kind); - - function Caller_Known_Size_Record (Typ : Entity_Id) return Boolean; - -- This is called for untagged records and protected types, with - -- nondefaulted discriminants. Returns True if the size of function - -- results is known at the call site, False otherwise. Returns False - -- if there is a variant part that depends on the discriminants of - -- this type, or if there is an array constrained by the discriminants - -- of this type. ???Currently, this is overly conservative (the array - -- could be nested inside some other record that is constrained by - -- nondiscriminants). That is, the recursive calls are too conservative. - - function Large_Max_Size_Mutable (Typ : Entity_Id) return Boolean; - -- Returns True if Typ is a nonlimited record with defaulted - -- discriminants whose max size makes it unsuitable for allocating on - -- the primary stack. - - ------------------------------ - -- Caller_Known_Size_Record -- - ------------------------------ - - function Caller_Known_Size_Record (Typ : Entity_Id) return Boolean is - pragma Assert (Typ = Underlying_Type (Typ)); - - begin - if Has_Variant_Part (Typ) and then not Is_Definite_Subtype (Typ) then - return False; - end if; - - declare - Comp : Entity_Id; - - begin - Comp := First_Component (Typ); - while Present (Comp) loop - - -- Only look at E_Component entities. No need to look at - -- E_Discriminant entities, and we must ignore internal - -- subtypes generated for constrained components. - - declare - Comp_Type : constant Entity_Id := - Underlying_Type (Etype (Comp)); - - begin - if Is_Record_Type (Comp_Type) - or else - Is_Protected_Type (Comp_Type) - then - if not Caller_Known_Size_Record (Comp_Type) then - return False; - end if; - - elsif Is_Array_Type (Comp_Type) then - if Size_Depends_On_Discriminant (Comp_Type) then - return False; - end if; - end if; - end; - - Next_Component (Comp); - end loop; - end; - - return True; - end Caller_Known_Size_Record; - - ------------------------------ - -- Large_Max_Size_Mutable -- - ------------------------------ - - function Large_Max_Size_Mutable (Typ : Entity_Id) return Boolean is - pragma Assert (Typ = Underlying_Type (Typ)); - - function Is_Large_Discrete_Type (T : Entity_Id) return Boolean; - -- Returns true if the discrete type T has a large range - - ---------------------------- - -- Is_Large_Discrete_Type -- - ---------------------------- - - function Is_Large_Discrete_Type (T : Entity_Id) return Boolean is - Threshold : constant Int := 16; - -- Arbitrary threshold above which we consider it "large". We want - -- a fairly large threshold, because these large types really - -- shouldn't have default discriminants in the first place, in - -- most cases. - - begin - return UI_To_Int (RM_Size (T)) > Threshold; - end Is_Large_Discrete_Type; - - -- Start of processing for Large_Max_Size_Mutable - - begin - if Is_Record_Type (Typ) - and then not Is_Limited_View (Typ) - and then Has_Defaulted_Discriminants (Typ) - then - -- Loop through the components, looking for an array whose upper - -- bound(s) depends on discriminants, where both the subtype of - -- the discriminant and the index subtype are too large. - - declare - Comp : Entity_Id; - - begin - Comp := First_Component (Typ); - while Present (Comp) loop - declare - Comp_Type : constant Entity_Id := - Underlying_Type (Etype (Comp)); - - Hi : Node_Id; - Indx : Node_Id; - Ityp : Entity_Id; - - begin - if Is_Array_Type (Comp_Type) then - Indx := First_Index (Comp_Type); - - while Present (Indx) loop - Ityp := Etype (Indx); - Hi := Type_High_Bound (Ityp); - - if Nkind (Hi) = N_Identifier - and then Ekind (Entity (Hi)) = E_Discriminant - and then Is_Large_Discrete_Type (Ityp) - and then Is_Large_Discrete_Type - (Etype (Entity (Hi))) - then - return True; - end if; - - Next_Index (Indx); - end loop; - end if; - end; - - Next_Component (Comp); - end loop; - end; - end if; - - return False; - end Large_Max_Size_Mutable; - - -- Local declarations - - Typ : constant Entity_Id := Underlying_Type (Id); - - -- Start of processing for Returns_On_Secondary_Stack - - begin - -- This is a private type which is not completed yet. This can only - -- happen in a default expression (of a formal parameter or of a - -- record component). Do not expand transient scope in this case. - - if No (Typ) then - return False; - end if; - - -- Do not expand transient scope for non-existent procedure return or - -- string literal types. - - if Typ = Standard_Void_Type - or else Ekind (Typ) = E_String_Literal_Subtype - then - return False; - - -- If Typ is a generic formal incomplete type, then we want to look at - -- the actual type. - - elsif Ekind (Typ) = E_Record_Subtype - and then Present (Cloned_Subtype (Typ)) - then - return Returns_On_Secondary_Stack (Cloned_Subtype (Typ)); - - -- Functions returning specific tagged types may dispatch on result, so - -- their returned value is allocated on the secondary stack, even in the - -- definite case. We must treat nondispatching functions the same way, - -- because access-to-function types can point at both, so the calling - -- conventions must be compatible. - - elsif Is_Tagged_Type (Typ) then - return True; - - -- If the return slot of the back end cannot be accessed, then there - -- is no way to call Adjust at the right time for the return object if - -- the type needs finalization, so the return object must be allocated - -- on the secondary stack. - - elsif not Back_End_Return_Slot and then Needs_Finalization (Typ) then - return True; - - -- Untagged definite subtypes are known size. This includes all - -- elementary [sub]types. Tasks are known size even if they have - -- discriminants. So we return False here, with one exception: - -- For a type like: - -- type T (Last : Natural := 0) is - -- X : String (1 .. Last); - -- end record; - -- we return True. That's because for "P(F(...));", where F returns T, - -- we don't know the size of the result at the call site, so if we - -- allocated it on the primary stack, we would have to allocate the - -- maximum size, which is way too big. - - elsif Is_Definite_Subtype (Typ) or else Is_Task_Type (Typ) then - return Large_Max_Size_Mutable (Typ); - - -- Indefinite (discriminated) untagged record or protected type - - elsif Is_Record_Type (Typ) or else Is_Protected_Type (Typ) then - return not Caller_Known_Size_Record (Typ); - - -- Unconstrained array - - else - pragma Assert (Is_Array_Type (Typ) and not Is_Definite_Subtype (Typ)); - return True; - end if; - end Returns_On_Secondary_Stack; - -------------------------------- -- Returns_Unconstrained_Type -- -------------------------------- @@ -30344,6 +30417,69 @@ package body Sem_Util is return List_1; end Visible_Ancestors; + --------------------------- + -- Warn_On_Hiding_Entity -- + --------------------------- + + procedure Warn_On_Hiding_Entity + (N : Node_Id; + Hidden, Visible : Entity_Id; + On_Use_Clause : Boolean) + is + begin + -- Don't warn for record components since they always have a well + -- defined scope which does not confuse other uses. Note that in + -- some cases, Ekind has not been set yet. + + if Ekind (Hidden) /= E_Component + and then Ekind (Hidden) /= E_Discriminant + and then Nkind (Parent (Hidden)) /= N_Component_Declaration + and then Ekind (Visible) /= E_Component + and then Ekind (Visible) /= E_Discriminant + and then Nkind (Parent (Visible)) /= N_Component_Declaration + + -- Don't warn for one character variables. It is too common to use + -- such variables as locals and will just cause too many false hits. + + and then Length_Of_Name (Chars (Hidden)) /= 1 + + -- Don't warn for non-source entities + + and then Comes_From_Source (Hidden) + and then Comes_From_Source (Visible) + + -- Don't warn within a generic instantiation + + and then not In_Instance + + -- Don't warn unless entity in question is in extended main source + + and then In_Extended_Main_Source_Unit (Visible) + + -- Finally, in the case of a declaration, the hidden entity must + -- be either immediately visible or use visible (i.e. from a used + -- package). In the case of a use clause, the visible entity must + -- be immediately visible. + + and then + (if On_Use_Clause then + Is_Immediately_Visible (Visible) + else + (Is_Immediately_Visible (Hidden) + or else + Is_Potentially_Use_Visible (Hidden))) + then + if On_Use_Clause then + Error_Msg_Sloc := Sloc (Visible); + Error_Msg_NE ("visible declaration of&# hides homonym " + & "from use clause?h?", N, Hidden); + else + Error_Msg_Sloc := Sloc (Hidden); + Error_Msg_NE ("declaration hides &#?h?", N, Visible); + end if; + end if; + end Warn_On_Hiding_Entity; + ---------------------- -- Within_Init_Proc -- ---------------------- @@ -32069,10 +32205,9 @@ package body Sem_Util is -- type Typ (Len : Natural := 0) is -- record F : String (1 .. Len); end record; -- - -- See Large_Max_Size_Mutable function elsewhere in this - -- file (currently declared inside of - -- Requires_Transient_Scope, so it would have to be - -- moved if we want it to be callable from here). + -- See Large_Max_Size_Mutable function elsewhere in this file, + -- currently declared inside of Needs_Secondary_Stack, so it + -- would have to be moved if we want it to be callable from here. end Indirect_Temp_Needed; diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index 2d9cbd3..4121cf0 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -320,6 +320,16 @@ package Sem_Util is -- declaration in the tree before N, and return the entity of that -- subtype. Otherwise, simply return T. + function Build_Default_Subtype_OK (T : Entity_Id) return Boolean; + -- When analyzing components or object declarations, it is possible, in + -- some cases, to build subtypes for discriminated types. This is + -- worthwhile to avoid the backend allocating the maximum possible size for + -- objects of the type. + -- In particular, when T is limited, the discriminants and therefore the + -- size of an object of type T cannot change. Furthermore, if T is definite + -- with statically initialized defaulted discriminants, we are able and + -- want to build a constrained subtype of the right size. + function Build_Discriminal_Subtype_Of_Component (T : Entity_Id) return Node_Id; -- Determine whether a record component has a type that depends on @@ -2667,6 +2677,12 @@ package Sem_Util is -- parameter to identify the accessibility level of the function result -- "determined by the point of call". + function Needs_Secondary_Stack (Id : Entity_Id) return Boolean; + -- Return true if functions whose result type is Id must return on the + -- secondary stack, i.e. allocate the return object on this stack. + + -- WARNING: There is a matching C declaration of this subprogram in fe.h + function Needs_Simple_Initialization (Typ : Entity_Id; Consider_IS : Boolean := True) return Boolean; @@ -3082,12 +3098,6 @@ package Sem_Util is -- Set the current SPARK_Mode to Mode and SPARK_Mode_Pragma to Prag. This -- routine must be used in tandem with Set_SPARK_Mode. - function Returns_On_Secondary_Stack (Id : Entity_Id) return Boolean; - -- Return true if functions whose result type is Id must return on the - -- secondary stack, i.e. allocate the return object on this stack. - - -- WARNING: There is a matching C declaration of this subprogram in fe.h - function Returns_Unconstrained_Type (Subp : Entity_Id) return Boolean; -- Return true if Subp is a function that returns an unconstrained type @@ -3453,6 +3463,18 @@ package Sem_Util is function Within_Scope (E : Entity_Id; S : Entity_Id) return Boolean; -- Returns True if entity E is declared within scope S + procedure Warn_On_Hiding_Entity + (N : Node_Id; + Hidden, Visible : Entity_Id; + On_Use_Clause : Boolean); + -- Warn on hiding of an entity, either because a new declaration hides + -- an entity directly visible or potentially visible through a use_clause + -- (On_Use_Clause = False), or because the entity would be potentially + -- visible through a use_clause if it was now hidden by a visible + -- declaration (On_Use_Clause = True). N is the node on which the warning + -- is potentially issued: it is the visible entity in the former case, and + -- the use_clause in the latter case. + procedure Wrong_Type (Expr : Node_Id; Expected_Type : Entity_Id); -- Output error message for incorrectly typed expression. Expr is the node -- for the incorrectly typed construct (Etype (Expr) is the type found), diff --git a/gcc/ada/sem_warn.adb b/gcc/ada/sem_warn.adb index 2512357..b23be72 100644 --- a/gcc/ada/sem_warn.adb +++ b/gcc/ada/sem_warn.adb @@ -1272,10 +1272,6 @@ package body Sem_Warn is elsif Never_Set_In_Source_Check_Spec (E1) - -- No warning if warning for this case turned off - - and then Warn_On_No_Value_Assigned - -- No warning if address taken somewhere and then not Address_Taken (E1) @@ -1381,7 +1377,7 @@ package body Sem_Warn is -- force use of IN OUT, even if in this particular case -- the formal is not modified. - else + elsif Warn_On_No_Value_Assigned then -- Suppress the warnings for a junk name if not Has_Junk_Name (E1) then @@ -1397,15 +1393,17 @@ package body Sem_Warn is if not Has_Pragma_Unmodified_Check_Spec (E1) and then not Warnings_Off_E1 and then not Has_Junk_Name (E1) + and then Warn_On_No_Value_Assigned then Output_Reference_Error - ("?f?formal parameter& is read but " + ("?v?formal parameter& is read but " & "never assigned!"); end if; elsif not Has_Pragma_Unreferenced_Check_Spec (E1) and then not Warnings_Off_E1 and then not Has_Junk_Name (E1) + and then Check_Unreferenced_Formals then Output_Reference_Error ("?f?formal parameter& is not referenced!"); @@ -1416,7 +1414,8 @@ package body Sem_Warn is else if Referenced (E1) then - if not Has_Unmodified (E1) + if Warn_On_No_Value_Assigned + and then not Has_Unmodified (E1) and then not Warnings_Off_E1 and then not Has_Junk_Name (E1) then @@ -1431,12 +1430,13 @@ package body Sem_Warn is May_Need_Initialized_Actual (E1); end if; - elsif not Has_Unreferenced (E1) + elsif Check_Unreferenced + and then not Has_Unreferenced (E1) and then not Warnings_Off_E1 and then not Has_Junk_Name (E1) then Output_Reference_Error -- CODEFIX - ("?v?variable& is never read and never assigned!"); + ("?u?variable& is never read and never assigned!"); end if; -- Deal with special case where this variable is hidden @@ -1445,14 +1445,15 @@ package body Sem_Warn is if Ekind (E1) = E_Variable and then Present (Hiding_Loop_Variable (E1)) and then not Warnings_Off_E1 + and then Warn_On_Hiding then Error_Msg_N - ("?v?for loop implicitly declares loop variable!", + ("?h?for loop implicitly declares loop variable!", Hiding_Loop_Variable (E1)); Error_Msg_Sloc := Sloc (E1); Error_Msg_N - ("\?v?declaration hides & declared#!", + ("\?h?declaration hides & declared#!", Hiding_Loop_Variable (E1)); end if; end if; @@ -4413,9 +4414,10 @@ package body Sem_Warn is if (No (S) or else not Is_Dispatching_Operation (S)) and then not Is_Trivial_Subprogram (Scope (E)) + and then Check_Unreferenced_Formals then Error_Msg_NE -- CODEFIX - ("?u?formal parameter & is not referenced!", + ("?f?formal parameter & is not referenced!", E, Spec_E); end if; end; diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads index da42ae5..e18a427 100644 --- a/gcc/ada/sinfo.ads +++ b/gcc/ada/sinfo.ads @@ -927,12 +927,6 @@ package Sinfo is -- a pragma Import or Interface applies, in which case no body is -- permitted (in Ada 83 or Ada 95). - -- By_Ref - -- Present in N_Simple_Return_Statement and N_Extended_Return_Statement, - -- this flag is set when the returned expression is already allocated on - -- the secondary stack and thus the result is passed by reference rather - -- than copied another time. - -- Cleanup_Actions -- Present in block statements created for transient blocks, contains -- additional cleanup actions carried over from the transient scope. @@ -1680,6 +1674,10 @@ package Sinfo is -- nodes which emulate the barrier function of a protected entry body. -- The flag is used when checking for incorrect use of Current_Task. + -- Is_Enum_Array_Aggregate + -- A flag set on an aggregate created internally while building the + -- images tables for enumerations. + -- Is_Expanded_Build_In_Place_Call -- This flag is set in an N_Function_Call node to indicate that the extra -- actuals to support a build-in-place style of call have been added to @@ -1794,6 +1792,9 @@ package Sinfo is -- overloading determination. The setting of this flag is not relevant -- once overloading analysis is complete. + -- Is_Parenthesis_Aggregate + -- A flag set on an aggregate that uses parentheses as delimiters + -- Is_Power_Of_2_For_Shift -- A flag present only in N_Op_Expon nodes. It is set when the -- exponentiation is of the form 2 ** N, where the type of N is an @@ -4024,7 +4025,9 @@ package Sinfo is -- Compile_Time_Known_Aggregate -- Expansion_Delayed -- Has_Self_Reference + -- Is_Enum_Array_Aggregate -- Is_Homogeneous_Aggregate + -- Is_Parenthesis_Aggregate -- plus fields for expression -- Note: this structure is used for both record and array aggregates @@ -5567,7 +5570,6 @@ package Sinfo is -- Expression (set to Empty if no expression present) -- Storage_Pool -- Procedure_To_Call - -- By_Ref -- Comes_From_Extended_Return_Statement -- Note: Return_Statement_Entity points to an E_Return_Statement @@ -5582,7 +5584,6 @@ package Sinfo is -- Handled_Statement_Sequence (set to Empty if not present) -- Storage_Pool -- Procedure_To_Call - -- By_Ref -- Note: Return_Statement_Entity points to an E_Return_Statement. diff --git a/gcc/ada/switch-c.adb b/gcc/ada/switch-c.adb index 522cdf6..feac8bd 100644 --- a/gcc/ada/switch-c.adb +++ b/gcc/ada/switch-c.adb @@ -603,7 +603,8 @@ package body Switch.C is Exception_Extra_Info := True; Ptr := Ptr + 1; - -- -gnatef (full source path for brief error messages) + -- -gnatef (full source path for brief error messages and + -- absolute paths for -fdiagnostics-format=json) when 'f' => Store_Switch := False; diff --git a/gcc/ada/usage.adb b/gcc/ada/usage.adb index a3d59b6..7d11ae5 100644 --- a/gcc/ada/usage.adb +++ b/gcc/ada/usage.adb @@ -187,7 +187,7 @@ begin -- Line for -gnatef switch Write_Switch_Char ("ef"); - Write_Line ("Full source path in brief error messages"); + Write_Line ("Full source path in brief error messages and JSON output"); -- Line for -gnateF switch diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 6bceab8..53b3ffb 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,41 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * checker-path.cc (checker_event::get_meaning): New. + (function_entry_event::get_meaning): New. + (state_change_event::get_desc): Add dump of meaning of the event + to the -fanalyzer-verbose-state-changes output. + (state_change_event::get_meaning): New. + (cfg_edge_event::get_meaning): New. + (call_event::get_meaning): New. + (return_event::get_meaning): New. + (start_consolidated_cfg_edges_event::get_meaning): New. + (warning_event::get_meaning): New. + * checker-path.h: Include "tree-logical-location.h". + (checker_event::checker_event): Construct m_logical_loc. + (checker_event::get_logical_location): New. + (checker_event::get_meaning): New decl. + (checker_event::m_logical_loc): New. + (function_entry_event::get_meaning): New decl. + (state_change_event::get_meaning): New decl. + (cfg_edge_event::get_meaning): New decl. + (call_event::get_meaning): New decl. + (return_event::get_meaning): New decl. + (start_consolidated_cfg_edges_event::get_meaning): New. + (warning_event::get_meaning): New decl. + * pending-diagnostic.h: Include "diagnostic-path.h". + (pending_diagnostic::get_meaning_for_state_change): New vfunc. + * sm-file.cc (file_diagnostic::get_meaning_for_state_change): New + vfunc impl. + * sm-malloc.cc (malloc_diagnostic::get_meaning_for_state_change): + Likewise. + * sm-sensitive.cc + (exposure_through_output_file::get_meaning_for_state_change): + Likewise. + * sm-taint.cc (taint_diagnostic::get_meaning_for_state_change): + Likewise. + * varargs.cc + (va_list_sm_diagnostic::get_meaning_for_state_change): Likewise. + 2022-05-23 David Malcolm <dmalcolm@redhat.com> * call-info.cc: Add "final" and "override" to all vfunc diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index 5fdbc38..8aa5bf7 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -112,6 +112,15 @@ event_kind_to_string (enum event_kind ek) /* class checker_event : public diagnostic_event. */ +/* No-op implementation of diagnostic_event::get_meaning vfunc for + checker_event: checker events have no meaning by default. */ + +diagnostic_event::meaning +checker_event::get_meaning () const +{ + return meaning (); +} + /* Dump this event to PP (for debugging/logging purposes). */ void @@ -242,6 +251,15 @@ function_entry_event::get_desc (bool can_colorize) const return make_label_text (can_colorize, "entry to %qE", m_fndecl); } +/* Implementation of diagnostic_event::get_meaning vfunc for + function entry. */ + +diagnostic_event::meaning +function_entry_event::get_meaning () const +{ + return meaning (VERB_enter, NOUN_function); +} + /* class state_change_event : public checker_event. */ /* state_change_event's ctor. */ @@ -292,25 +310,33 @@ state_change_event::get_desc (bool can_colorize) const { if (flag_analyzer_verbose_state_changes) { + /* Get any "meaning" of event. */ + diagnostic_event::meaning meaning = get_meaning (); + pretty_printer meaning_pp; + meaning.dump_to_pp (&meaning_pp); + /* Append debug version. */ label_text result; if (m_origin) result = make_label_text (can_colorize, - "%s (state of %qE: %qs -> %qs, origin: %qE)", + "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)", custom_desc.m_buffer, var, m_from->get_name (), m_to->get_name (), - origin); + origin, + pp_formatted_text (&meaning_pp)); else result = make_label_text (can_colorize, - "%s (state of %qE: %qs -> %qs, NULL origin)", + "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)", custom_desc.m_buffer, var, m_from->get_name (), - m_to->get_name ()); + m_to->get_name (), + pp_formatted_text (&meaning_pp)); + custom_desc.maybe_free (); return result; } @@ -357,6 +383,26 @@ state_change_event::get_desc (bool can_colorize) const } } +/* Implementation of diagnostic_event::get_meaning vfunc for + state change events: delegate to the pending_diagnostic to + get any meaning. */ + +diagnostic_event::meaning +state_change_event::get_meaning () const +{ + if (m_pending_diagnostic) + { + region_model *model = m_dst_state.m_region_model; + tree var = model->get_representative_tree (m_sval); + tree origin = model->get_representative_tree (m_origin); + return m_pending_diagnostic->get_meaning_for_state_change + (evdesc::state_change (false, var, origin, + m_from, m_to, m_emission_id, *this)); + } + else + return meaning (); +} + /* class superedge_event : public checker_event. */ /* Get the callgraph_superedge for this superedge_event, which must be @@ -432,6 +478,21 @@ cfg_edge_event::cfg_edge_event (enum event_kind kind, gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE); } +/* Implementation of diagnostic_event::get_meaning vfunc for + CFG edge events. */ + +diagnostic_event::meaning +cfg_edge_event::get_meaning () const +{ + const cfg_superedge& cfg_sedge = get_cfg_superedge (); + if (cfg_sedge.true_value_p ()) + return meaning (VERB_branch, PROPERTY_true); + else if (cfg_sedge.false_value_p ()) + return meaning (VERB_branch, PROPERTY_false); + else + return meaning (); +} + /* class start_cfg_edge_event : public cfg_edge_event. */ /* Implementation of diagnostic_event::get_desc vfunc for @@ -690,6 +751,15 @@ call_event::get_desc (bool can_colorize) const get_caller_fndecl ()); } +/* Implementation of diagnostic_event::get_meaning vfunc for + function call events. */ + +diagnostic_event::meaning +call_event::get_meaning () const +{ + return meaning (VERB_call, NOUN_function); +} + /* Override of checker_event::is_call_p for calls. */ bool @@ -760,6 +830,15 @@ return_event::get_desc (bool can_colorize) const m_src_snode->m_fun->decl); } +/* Implementation of diagnostic_event::get_meaning vfunc for + function return events. */ + +diagnostic_event::meaning +return_event::get_meaning () const +{ + return meaning (VERB_return, NOUN_function); +} + /* Override of checker_event::is_return_p for returns. */ bool @@ -778,6 +857,16 @@ start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const m_edge_sense ? "true" : "false"); } +/* Implementation of diagnostic_event::get_meaning vfunc for + start_consolidated_cfg_edges_event. */ + +diagnostic_event::meaning +start_consolidated_cfg_edges_event::get_meaning () const +{ + return meaning (VERB_branch, + (m_edge_sense ? PROPERTY_true : PROPERTY_false)); +} + /* class setjmp_event : public checker_event. */ /* Implementation of diagnostic_event::get_desc vfunc for @@ -977,6 +1066,15 @@ warning_event::get_desc (bool can_colorize) const return label_text::borrow ("here"); } +/* Implementation of diagnostic_event::get_meaning vfunc for + warning_event. */ + +diagnostic_event::meaning +warning_event::get_meaning () const +{ + return meaning (VERB_danger, NOUN_unknown); +} + /* Print a single-line representation of this path to PP. */ void diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h index fd274e5..8960d56 100644 --- a/gcc/analyzer/checker-path.h +++ b/gcc/analyzer/checker-path.h @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_CHECKER_PATH_H #define GCC_ANALYZER_CHECKER_PATH_H +#include "tree-logical-location.h" + namespace ana { /* An enum for discriminating between the concrete subclasses of @@ -85,7 +87,8 @@ public: checker_event (enum event_kind kind, location_t loc, tree fndecl, int depth) : m_kind (kind), m_loc (loc), m_fndecl (fndecl), m_depth (depth), - m_pending_diagnostic (NULL), m_emission_id () + m_pending_diagnostic (NULL), m_emission_id (), + m_logical_loc (fndecl) { } @@ -94,6 +97,14 @@ public: location_t get_location () const final override { return m_loc; } tree get_fndecl () const final override { return m_fndecl; } int get_stack_depth () const final override { return m_depth; } + const logical_location *get_logical_location () const final override + { + if (m_fndecl) + return &m_logical_loc; + else + return NULL; + } + meaning get_meaning () const override; /* Additional functionality. */ @@ -122,6 +133,7 @@ public: int m_depth; pending_diagnostic *m_pending_diagnostic; diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred + tree_logical_location m_logical_loc; }; /* A concrete event subclass for a purely textual event, for use in @@ -222,6 +234,7 @@ public: } label_text get_desc (bool can_colorize) const final override; + meaning get_meaning () const override; bool is_function_entry_p () const final override { return true; } }; @@ -241,6 +254,7 @@ public: const program_state &dst_state); label_text get_desc (bool can_colorize) const final override; + meaning get_meaning () const override; function *get_dest_function () const { @@ -295,6 +309,8 @@ public: class cfg_edge_event : public superedge_event { public: + meaning get_meaning () const override; + const cfg_superedge& get_cfg_superedge () const; protected: @@ -353,6 +369,7 @@ public: location_t loc, tree fndecl, int depth); label_text get_desc (bool can_colorize) const override; + meaning get_meaning () const override; bool is_call_p () const final override; @@ -373,6 +390,7 @@ public: location_t loc, tree fndecl, int depth); label_text get_desc (bool can_colorize) const final override; + meaning get_meaning () const override; bool is_return_p () const final override; @@ -394,6 +412,7 @@ public: } label_text get_desc (bool can_colorize) const final override; + meaning get_meaning () const override; private: bool m_edge_sense; @@ -521,6 +540,7 @@ public: } label_text get_desc (bool can_colorize) const final override; + meaning get_meaning () const override; private: const state_machine *m_sm; diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h index a273f89..9e1c656 100644 --- a/gcc/analyzer/pending-diagnostic.h +++ b/gcc/analyzer/pending-diagnostic.h @@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H +#include "diagnostic-path.h" + namespace ana { /* A bundle of information about things that are of interest to a @@ -232,6 +234,15 @@ class pending_diagnostic return label_text (); } + /* Vfunc for implementing diagnostic_event::get_meaning for + state_change_event. */ + virtual diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &) const + { + /* Default no-op implementation. */ + return diagnostic_event::meaning (); + } + /* Precision-of-wording vfunc for describing an interprocedural call carrying critial state for the diagnostic, from caller to callee. diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index e9b5b8b..8514af1 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -143,6 +143,20 @@ public: return label_text (); } + diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &change) + const final override + { + if (change.m_old_state == m_sm.get_start_state () + && change.m_new_state == m_sm.m_unchecked) + return diagnostic_event::meaning (diagnostic_event::VERB_acquire, + diagnostic_event::NOUN_resource); + if (change.m_new_state == m_sm.m_closed) + return diagnostic_event::meaning (diagnostic_event::VERB_release, + diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (); + } + protected: const fileptr_state_machine &m_sm; tree m_arg; diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index 3c0f890..3bd4042 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -736,6 +736,20 @@ public: return label_text (); } + diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &change) + const final override + { + if (change.m_old_state == m_sm.get_start_state () + && unchecked_p (change.m_new_state)) + return diagnostic_event::meaning (diagnostic_event::VERB_acquire, + diagnostic_event::NOUN_memory); + if (freed_p (change.m_new_state)) + return diagnostic_event::meaning (diagnostic_event::VERB_release, + diagnostic_event::NOUN_memory); + return diagnostic_event::meaning (); + } + protected: const malloc_state_machine &m_sm; tree m_arg; diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc index 20809dd..83c1906 100644 --- a/gcc/analyzer/sm-sensitive.cc +++ b/gcc/analyzer/sm-sensitive.cc @@ -117,6 +117,15 @@ public: return label_text (); } + diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &change) + const final override + { + if (change.m_new_state == m_sm.m_sensitive) + return diagnostic_event::meaning (diagnostic_event::VERB_acquire, + diagnostic_event::NOUN_sensitive); + return diagnostic_event::meaning (); + } label_text describe_call_with_state (const evdesc::call_with_state &info) final override { diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index 3aaa69a..d2d03c3 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -163,6 +163,17 @@ public: change.m_expr); return label_text (); } + + diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &change) + const final override + { + if (change.m_new_state == m_sm.m_tainted) + return diagnostic_event::meaning (diagnostic_event::VERB_acquire, + diagnostic_event::NOUN_taint); + return diagnostic_event::meaning (); + } + protected: const taint_state_machine &m_sm; tree m_arg; diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 2d27484..846a0b1 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -335,6 +335,19 @@ public: return label_text (); } + diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &change) + const final override + { + if (change.m_new_state == m_sm.m_started) + return diagnostic_event::meaning (diagnostic_event::VERB_acquire, + diagnostic_event::NOUN_resource); + if (change.m_new_state == m_sm.m_ended) + return diagnostic_event::meaning (diagnostic_event::VERB_release, + diagnostic_event::NOUN_resource); + return diagnostic_event::meaning (); + } + protected: va_list_sm_diagnostic (const va_list_state_machine &sm, const svalue *ap_sval, tree ap_tree) diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 1de21db..0bc8b8e 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,18 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * c-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + (c_get_sarif_source_language): New. + * c-tree.h (c_get_sarif_source_language): New decl. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (c.tags): Look at *.cc. + +2022-05-31 Jakub Jelinek <jakub@redhat.com> + + * c-parser.cc (OMP_SCOPE_CLAUSE_MASK): Add firstprivate and allocate + clauses. + 2022-05-28 Jakub Jelinek <jakub@redhat.com> * c-parser.cc (c_parser_omp_declare_target): If OMP_CLAUSE_LINK was diff --git a/gcc/c/Make-lang.in b/gcc/c/Make-lang.in index 1367a10..9bd9c0e 100644 --- a/gcc/c/Make-lang.in +++ b/gcc/c/Make-lang.in @@ -109,7 +109,7 @@ c.srcinfo: c.srcextra: gengtype-lex.cc -cp -p $^ $(srcdir) c.tags: force - cd $(srcdir)/c; $(ETAGS) -o TAGS.sub *.c *.h; \ + cd $(srcdir)/c; $(ETAGS) -o TAGS.sub *.cc *.h; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub c.man: c.srcman: diff --git a/gcc/c/c-lang.cc b/gcc/c/c-lang.cc index eecc0a0..0e67045 100644 --- a/gcc/c/c-lang.cc +++ b/gcc/c/c-lang.cc @@ -46,9 +46,21 @@ enum c_language_kind c_language = clk_c; #undef LANG_HOOKS_GET_SUBSTRING_LOCATION #define LANG_HOOKS_GET_SUBSTRING_LOCATION c_get_substring_location +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE c_get_sarif_source_language + /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +const char * +c_get_sarif_source_language (const char *) +{ + return "c"; +} + #if CHECKING_P namespace selftest { diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 7cc4d93c..c9a8d14 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -20413,7 +20413,9 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) #define OMP_SCOPE_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 3b322ad..e655afd 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -837,6 +837,8 @@ set_c_expr_source_range (c_expr *expr, /* In c-fold.cc */ extern vec<tree> incomplete_record_decls; +extern const char *c_get_sarif_source_language (const char *filename); + #if CHECKING_P namespace selftest { extern void run_c_tests (void); diff --git a/gcc/calls.cc b/gcc/calls.cc index bbaf69c..a4336c1 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -2095,7 +2095,8 @@ load_register_parameters (struct arg_data *args, int num_actuals, poly_int64 size = 0; HOST_WIDE_INT const_size = 0; rtx_insn *before_arg = get_last_insn (); - tree type = TREE_TYPE (args[i].tree_value); + tree tree_value = args[i].tree_value; + tree type = TREE_TYPE (tree_value); if (RECORD_OR_UNION_TYPE_P (type) && TYPE_TRANSPARENT_AGGR (type)) type = TREE_TYPE (first_field (type)); /* Set non-negative if we must move a word at a time, even if @@ -2172,6 +2173,24 @@ load_register_parameters (struct arg_data *args, int num_actuals, emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j), args[i].aligned_regs[j]); + /* If we need a single register and the source is a constant + VAR_DECL with a simple constructor, expand that constructor + via a pseudo rather than read from (possibly misaligned) + memory. PR middle-end/95126. */ + else if (nregs == 1 + && partial == 0 + && !args[i].pass_on_stack + && VAR_P (tree_value) + && TREE_READONLY (tree_value) + && !TREE_SIDE_EFFECTS (tree_value) + && immediate_const_ctor_p (DECL_INITIAL (tree_value))) + { + rtx target = gen_reg_rtx (word_mode); + rtx x = expand_expr (DECL_INITIAL (tree_value), + target, word_mode, EXPAND_NORMAL); + reg = gen_rtx_REG (word_mode, REGNO (reg)); + emit_move_insn (reg, x); + } else if (partial == 0 || args[i].pass_on_stack) { /* SIZE and CONST_SIZE are 0 for partial arguments and diff --git a/gcc/common.opt b/gcc/common.opt index 8a0dafc..7ca0cce 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1390,7 +1390,7 @@ Common Joined RejectNegative UInteger fdiagnostics-format= Common Joined RejectNegative Enum(diagnostics_output_format) --fdiagnostics-format=[text|json] Select output format. +-fdiagnostics-format=[text|sarif-stderr|sarif-file|json|json-stderr|json-file] Select output format. fdiagnostics-escape-format= Common Joined RejectNegative Enum(diagnostics_escape_format) @@ -1425,7 +1425,19 @@ EnumValue Enum(diagnostics_output_format) String(text) Value(DIAGNOSTICS_OUTPUT_FORMAT_TEXT) EnumValue -Enum(diagnostics_output_format) String(json) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON) +Enum(diagnostics_output_format) String(json) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR) + +EnumValue +Enum(diagnostics_output_format) String(json-stderr) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR) + +EnumValue +Enum(diagnostics_output_format) String(json-file) Value(DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE) + +EnumValue +Enum(diagnostics_output_format) String(sarif-stderr) Value(DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR) + +EnumValue +Enum(diagnostics_output_format) String(sarif-file) Value(DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE) fdiagnostics-parseable-fixits Common Var(flag_diagnostics_parseable_fixits) diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc index 767ee0c..3d2fb5e 100644 --- a/gcc/config/aarch64/aarch64-c.cc +++ b/gcc/config/aarch64/aarch64-c.cc @@ -82,7 +82,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile) { aarch64_def_or_undef (flag_unsafe_math_optimizations, "__ARM_FP_FAST", pfile); - builtin_define_with_int_value ("__ARM_ARCH", aarch64_architecture_version); + builtin_define_with_int_value ("__ARM_ARCH", AARCH64_ISA_V9 ? 9 : 8); builtin_define_with_int_value ("__ARM_SIZEOF_MINIMAL_ENUM", flag_short_enums ? 1 : 4); diff --git a/gcc/config/aarch64/aarch64-opts.h b/gcc/config/aarch64/aarch64-opts.h index 93572fe..421648a 100644 --- a/gcc/config/aarch64/aarch64-opts.h +++ b/gcc/config/aarch64/aarch64-opts.h @@ -98,4 +98,10 @@ enum stack_protector_guard { SSP_GLOBAL /* global canary */ }; +/* The key type that -msign-return-address should use. */ +enum aarch64_key_type { + AARCH64_KEY_A, + AARCH64_KEY_B +}; + #endif diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index df31181..dabd047 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -672,14 +672,6 @@ enum simd_immediate_check { AARCH64_CHECK_MOV = AARCH64_CHECK_ORR | AARCH64_CHECK_BIC }; -/* The key type that -msign-return-address should use. */ -enum aarch64_key_type { - AARCH64_KEY_A, - AARCH64_KEY_B -}; - -extern enum aarch64_key_type aarch64_ra_sign_key; - extern struct tune_params aarch64_tune_params; /* The available SVE predicate patterns, known in the ACLE as "svpattern". */ diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index d4c575c..5969d1f 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -306,9 +306,6 @@ static bool aarch64_print_address_internal (FILE*, machine_mode, rtx, aarch64_addr_query_type); static HOST_WIDE_INT aarch64_clamp_to_uimm12_shift (HOST_WIDE_INT val); -/* Major revision number of the ARM Architecture implemented by the target. */ -unsigned aarch64_architecture_version; - /* The processor for which instructions should be scheduled. */ enum aarch64_processor aarch64_tune = cortexa53; @@ -2677,7 +2674,6 @@ struct processor enum aarch64_processor ident; enum aarch64_processor sched_core; enum aarch64_arch arch; - unsigned architecture_version; const uint64_t flags; const struct tune_params *const tune; }; @@ -2686,9 +2682,9 @@ struct processor static const struct processor all_architectures[] = { #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \ - {NAME, CORE, CORE, AARCH64_ARCH_##ARCH_IDENT, ARCH_REV, FLAGS, NULL}, + {NAME, CORE, CORE, AARCH64_ARCH_##ARCH_IDENT, FLAGS, NULL}, #include "aarch64-arches.def" - {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, 0, NULL} + {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL} }; /* Processor cores implementing AArch64. */ @@ -2696,23 +2692,13 @@ static const struct processor all_cores[] = { #define AARCH64_CORE(NAME, IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \ {NAME, IDENT, SCHED, AARCH64_ARCH_##ARCH, \ - all_architectures[AARCH64_ARCH_##ARCH].architecture_version, \ FLAGS, &COSTS##_tunings}, #include "aarch64-cores.def" - {"generic", generic, cortexa53, AARCH64_ARCH_8A, 8, + {"generic", generic, cortexa53, AARCH64_ARCH_8A, AARCH64_FL_FOR_ARCH8, &generic_tunings}, - {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, 0, NULL} + {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL} }; - -/* Target specification. These are populated by the -march, -mtune, -mcpu - handling code or by target attributes. */ -static const struct processor *selected_arch; -static const struct processor *selected_cpu; -static const struct processor *selected_tune; - -enum aarch64_key_type aarch64_ra_sign_key = AARCH64_KEY_A; - /* The current tuning set. */ struct tune_params aarch64_tune_params = generic_tunings; @@ -10353,8 +10339,8 @@ aarch64_case_values_threshold (void) /* Use the specified limit for the number of cases before using jump tables at higher optimization levels. */ if (optimize > 2 - && selected_cpu->tune->max_case_values != 0) - return selected_cpu->tune->max_case_values; + && aarch64_tune_params.max_case_values != 0) + return aarch64_tune_params.max_case_values; else return optimize_size ? 8 : 11; } @@ -17425,6 +17411,26 @@ initialize_aarch64_tls_size (struct gcc_options *opts) return; } +/* Return the CPU corresponding to the enum CPU. */ + +static const struct processor * +aarch64_get_tune_cpu (enum aarch64_processor cpu) +{ + gcc_assert (cpu != aarch64_none); + + return &all_cores[cpu]; +} + +/* Return the architecture corresponding to the enum ARCH. */ + +static const struct processor * +aarch64_get_arch (enum aarch64_arch arch) +{ + gcc_assert (arch != aarch64_no_arch); + + return &all_architectures[arch]; +} + /* Parse STRING looking for options in the format: string :: option:string option :: name=substring @@ -17535,18 +17541,18 @@ aarch64_override_options_after_change_1 (struct gcc_options *opts) void aarch64_override_options_internal (struct gcc_options *opts) { - aarch64_tune_flags = selected_tune->flags; - aarch64_tune = selected_tune->sched_core; + const struct processor *tune = aarch64_get_tune_cpu (opts->x_selected_tune); + aarch64_tune_flags = tune->flags; + aarch64_tune = tune->sched_core; /* Make a copy of the tuning parameters attached to the core, which we may later overwrite. */ - aarch64_tune_params = *(selected_tune->tune); - aarch64_architecture_version = selected_arch->architecture_version; - if (selected_tune->tune == &generic_tunings) + aarch64_tune_params = *(tune->tune); + if (tune->tune == &generic_tunings) aarch64_adjust_generic_arch_tuning (aarch64_tune_params); if (opts->x_aarch64_override_tune_string) aarch64_parse_override_string (opts->x_aarch64_override_tune_string, - &aarch64_tune_params); + &aarch64_tune_params); /* This target defaults to strict volatile bitfields. */ if (opts->x_flag_strict_volatile_bitfields < 0 && abi_version_at_least (2)) @@ -17707,13 +17713,6 @@ aarch64_override_options_internal (struct gcc_options *opts) && opts->x_optimize >= aarch64_tune_params.prefetch->default_opt_level) opts->x_flag_prefetch_loop_arrays = 1; - if (opts->x_aarch64_arch_string == NULL) - opts->x_aarch64_arch_string = selected_arch->name; - if (opts->x_aarch64_cpu_string == NULL) - opts->x_aarch64_cpu_string = selected_cpu->name; - if (opts->x_aarch64_tune_string == NULL) - opts->x_aarch64_tune_string = selected_tune->name; - aarch64_override_options_after_change_1 (opts); } @@ -18065,26 +18064,6 @@ aarch64_validate_mtune (const char *str, const struct processor **res) return false; } -/* Return the CPU corresponding to the enum CPU. */ - -static const struct processor * -aarch64_get_tune_cpu (enum aarch64_processor cpu) -{ - gcc_assert (cpu != aarch64_none); - - return &all_cores[cpu]; -} - -/* Return the architecture corresponding to the enum ARCH. */ - -static const struct processor * -aarch64_get_arch (enum aarch64_arch arch) -{ - gcc_assert (arch != aarch64_no_arch); - - return &all_architectures[arch]; -} - /* Return the VG value associated with -msve-vector-bits= value VALUE. */ static poly_uint16 @@ -18120,9 +18099,9 @@ aarch64_override_options (void) uint64_t arch_isa = 0; aarch64_isa_flags = 0; - selected_cpu = NULL; - selected_arch = NULL; - selected_tune = NULL; + const struct processor *cpu = NULL; + const struct processor *arch = NULL; + const struct processor *tune = NULL; if (aarch64_harden_sls_string) aarch64_validate_sls_mitigation (aarch64_harden_sls_string); @@ -18134,56 +18113,52 @@ aarch64_override_options (void) If either of -march or -mtune is given, they override their respective component of -mcpu. */ if (aarch64_cpu_string) - aarch64_validate_mcpu (aarch64_cpu_string, &selected_cpu, &cpu_isa); + aarch64_validate_mcpu (aarch64_cpu_string, &cpu, &cpu_isa); if (aarch64_arch_string) - aarch64_validate_march (aarch64_arch_string, &selected_arch, &arch_isa); + aarch64_validate_march (aarch64_arch_string, &arch, &arch_isa); if (aarch64_tune_string) - aarch64_validate_mtune (aarch64_tune_string, &selected_tune); + aarch64_validate_mtune (aarch64_tune_string, &tune); #ifdef SUBTARGET_OVERRIDE_OPTIONS SUBTARGET_OVERRIDE_OPTIONS; #endif - if (selected_cpu && selected_arch) + if (cpu && arch) { /* If both -mcpu and -march are specified, warn if they are not architecturally compatible and prefer the -march ISA flags. */ - if (selected_arch->arch != selected_cpu->arch) + if (arch->arch != cpu->arch) { warning (0, "switch %<-mcpu=%s%> conflicts with %<-march=%s%> switch", aarch64_cpu_string, aarch64_arch_string); } + selected_arch = arch->arch; aarch64_isa_flags = arch_isa; } - else if (selected_cpu) + else if (cpu) { - selected_arch = &all_architectures[selected_cpu->arch]; + selected_arch = cpu->arch; aarch64_isa_flags = cpu_isa; } - else if (selected_arch) + else if (arch) { - selected_cpu = &all_cores[selected_arch->ident]; + cpu = &all_cores[arch->ident]; + selected_arch = arch->arch; aarch64_isa_flags = arch_isa; } else { /* No -mcpu or -march specified, so use the default CPU. */ - selected_cpu = &all_cores[TARGET_CPU_DEFAULT]; - selected_arch = &all_architectures[selected_cpu->arch]; - aarch64_isa_flags = selected_cpu->flags; + cpu = &all_cores[TARGET_CPU_DEFAULT]; + selected_arch = cpu->arch; + aarch64_isa_flags = cpu->flags; } - explicit_arch = selected_arch->arch; - if (!selected_tune) - selected_tune = selected_cpu; - explicit_tune_core = selected_tune->ident; - - gcc_assert (explicit_tune_core != aarch64_none); - gcc_assert (explicit_arch != aarch64_no_arch); + selected_tune = tune ? tune->ident : cpu->ident; if (aarch64_enable_bti == 2) { @@ -18302,38 +18277,14 @@ initialize_aarch64_code_model (struct gcc_options *opts) } } -/* Implement TARGET_OPTION_SAVE. */ - -static void -aarch64_option_save (struct cl_target_option *ptr, struct gcc_options *opts, - struct gcc_options */* opts_set */) -{ - ptr->x_aarch64_override_tune_string = opts->x_aarch64_override_tune_string; - ptr->x_aarch64_branch_protection_string - = opts->x_aarch64_branch_protection_string; -} - /* Implements TARGET_OPTION_RESTORE. Restore the backend codegen decisions using the information saved in PTR. */ static void aarch64_option_restore (struct gcc_options *opts, - struct gcc_options */* opts_set */, - struct cl_target_option *ptr) + struct gcc_options * /* opts_set */, + struct cl_target_option * /* ptr */) { - opts->x_explicit_arch = ptr->x_explicit_arch; - selected_arch = aarch64_get_arch (ptr->x_explicit_arch); - opts->x_explicit_tune_core = ptr->x_explicit_tune_core; - selected_tune = aarch64_get_tune_cpu (ptr->x_explicit_tune_core); - opts->x_aarch64_override_tune_string = ptr->x_aarch64_override_tune_string; - opts->x_aarch64_branch_protection_string - = ptr->x_aarch64_branch_protection_string; - if (opts->x_aarch64_branch_protection_string) - { - aarch64_parse_branch_protection (opts->x_aarch64_branch_protection_string, - NULL); - } - aarch64_override_options_internal (opts); } @@ -18343,11 +18294,11 @@ static void aarch64_option_print (FILE *file, int indent, struct cl_target_option *ptr) { const struct processor *cpu - = aarch64_get_tune_cpu (ptr->x_explicit_tune_core); - uint64_t isa_flags = ptr->x_aarch64_isa_flags; - const struct processor *arch = aarch64_get_arch (ptr->x_explicit_arch); + = aarch64_get_tune_cpu (ptr->x_selected_tune); + const struct processor *arch = aarch64_get_arch (ptr->x_selected_arch); std::string extension - = aarch64_get_extension_string_for_isa_flags (isa_flags, arch->flags); + = aarch64_get_extension_string_for_isa_flags (ptr->x_aarch64_isa_flags, + arch->flags); fprintf (file, "%*sselected tune = %s\n", indent, "", cpu->name); fprintf (file, "%*sselected arch = %s%s\n", indent, "", @@ -18460,8 +18411,7 @@ aarch64_handle_attr_arch (const char *str) if (parse_res == AARCH64_PARSE_OK) { gcc_assert (tmp_arch); - selected_arch = tmp_arch; - explicit_arch = selected_arch->arch; + selected_arch = tmp_arch->arch; return true; } @@ -18499,11 +18449,8 @@ aarch64_handle_attr_cpu (const char *str) if (parse_res == AARCH64_PARSE_OK) { gcc_assert (tmp_cpu); - selected_tune = tmp_cpu; - explicit_tune_core = selected_tune->ident; - - selected_arch = &all_architectures[tmp_cpu->arch]; - explicit_arch = selected_arch->arch; + selected_tune = tmp_cpu->ident; + selected_arch = tmp_cpu->arch; return true; } @@ -18571,8 +18518,7 @@ aarch64_handle_attr_tune (const char *str) if (parse_res == AARCH64_PARSE_OK) { gcc_assert (tmp_tune); - selected_tune = tmp_tune; - explicit_tune_core = selected_tune->ident; + selected_tune = tmp_tune->ident; return true; } @@ -19748,15 +19694,15 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, field_t = long_double_type_node; field_ptr_t = long_double_ptr_type_node; break; - case SDmode: + case E_SDmode: field_t = dfloat32_type_node; field_ptr_t = build_pointer_type (dfloat32_type_node); break; - case DDmode: + case E_DDmode: field_t = dfloat64_type_node; field_ptr_t = build_pointer_type (dfloat64_type_node); break; - case TDmode: + case E_TDmode: field_t = dfloat128_type_node; field_ptr_t = build_pointer_type (dfloat128_type_node); break; @@ -22492,7 +22438,7 @@ aarch64_declare_function_name (FILE *stream, const char* name, gcc_assert (targ_options); const struct processor *this_arch - = aarch64_get_arch (targ_options->x_explicit_arch); + = aarch64_get_arch (targ_options->x_selected_arch); uint64_t isa_flags = targ_options->x_aarch64_isa_flags; std::string extension @@ -22511,7 +22457,7 @@ aarch64_declare_function_name (FILE *stream, const char* name, useful to readers of the generated asm. Do it only when it changes from function to function and verbose assembly is requested. */ const struct processor *this_tune - = aarch64_get_tune_cpu (targ_options->x_explicit_tune_core); + = aarch64_get_tune_cpu (targ_options->x_selected_tune); if (flag_debug_asm && aarch64_last_printed_tune_string != this_tune->name) { @@ -22597,7 +22543,7 @@ aarch64_start_file (void) = TREE_TARGET_OPTION (target_option_default_node); const struct processor *default_arch - = aarch64_get_arch (default_options->x_explicit_arch); + = aarch64_get_arch (default_options->x_selected_arch); uint64_t default_isa_flags = default_options->x_aarch64_isa_flags; std::string extension = aarch64_get_extension_string_for_isa_flags (default_isa_flags, @@ -27477,9 +27423,6 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_OFFLOAD_OPTIONS #define TARGET_OFFLOAD_OPTIONS aarch64_offload_options -#undef TARGET_OPTION_SAVE -#define TARGET_OPTION_SAVE aarch64_option_save - #undef TARGET_OPTION_RESTORE #define TARGET_OPTION_RESTORE aarch64_option_restore diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index f835da3..80cfe4b 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -148,9 +148,6 @@ #define PCC_BITFIELD_TYPE_MATTERS 1 -/* Major revision number of the ARM Architecture implemented by the target. */ -extern unsigned aarch64_architecture_version; - /* Instruction tuning/selection flags. */ /* Bit values used to identify processor capabilities. */ diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 92220b2..d8e1f42 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -22,13 +22,10 @@ HeaderInclude config/aarch64/aarch64-opts.h TargetVariable -enum aarch64_processor explicit_tune_core = aarch64_none +enum aarch64_processor selected_tune = aarch64_none TargetVariable -enum aarch64_arch explicit_arch = aarch64_no_arch - -TargetSave -const char *x_aarch64_override_tune_string +enum aarch64_arch selected_arch = aarch64_no_arch TargetVariable uint64_t aarch64_isa_flags = 0 @@ -36,6 +33,9 @@ uint64_t aarch64_isa_flags = 0 TargetVariable unsigned aarch64_enable_bti = 2 +TargetVariable +enum aarch64_key_type aarch64_ra_sign_key = AARCH64_KEY_A + ; The TLS dialect names to use with -mtls-dialect. Enum @@ -139,7 +139,7 @@ Target RejectNegative Joined Enum(aarch64_abi) Var(aarch64_abi) Init(AARCH64_ABI Generate code that conforms to the specified ABI. moverride= -Target RejectNegative ToLower Joined Var(aarch64_override_tune_string) +Target RejectNegative ToLower Joined Var(aarch64_override_tune_string) Save -moverride=<string> Power users only! Override CPU optimization parameters. Enum diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 5cd7b99..617bee2 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -2317,21 +2317,15 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label) case E_DImode: if (TARGET_64BIT) goto simple; - /* For 32-bit target DI comparison may be performed on - SSE registers. To allow this we should avoid split - to SI mode which is achieved by doing xor in DI mode - and then comparing with zero (which is recognized by - STV pass). We don't compare using xor when optimizing - for size. */ - if (!optimize_insn_for_size_p () - && TARGET_STV - && (code == EQ || code == NE)) - { - op0 = force_reg (mode, gen_rtx_XOR (mode, op0, op1)); - op1 = const0_rtx; - } /* FALLTHRU */ case E_TImode: + /* DI and TI mode equality/inequality comparisons may be performed + on SSE registers. Avoid splitting them, except when optimizing + for size. */ + if ((code == EQ || code == NE) + && !optimize_insn_for_size_p ()) + goto simple; + /* Expand DImode branch into multiple compare+branch. */ { rtx lo[2], hi[2]; @@ -2350,34 +2344,7 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label) submode = mode == DImode ? SImode : DImode; - /* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to - avoid two branches. This costs one extra insn, so disable when - optimizing for size. */ - - if ((code == EQ || code == NE) - && (!optimize_insn_for_size_p () - || hi[1] == const0_rtx || lo[1] == const0_rtx)) - { - rtx xor0, xor1; - - xor1 = hi[0]; - if (hi[1] != const0_rtx) - xor1 = expand_binop (submode, xor_optab, xor1, hi[1], - NULL_RTX, 0, OPTAB_WIDEN); - - xor0 = lo[0]; - if (lo[1] != const0_rtx) - xor0 = expand_binop (submode, xor_optab, xor0, lo[1], - NULL_RTX, 0, OPTAB_WIDEN); - - tmp = expand_binop (submode, ior_optab, xor1, xor0, - NULL_RTX, 0, OPTAB_WIDEN); - - ix86_expand_branch (code, tmp, const0_rtx, label); - return; - } - - /* Otherwise, if we are doing less-than or greater-or-equal-than, + /* If we are doing less-than or greater-or-equal-than, op1 is a constant and the low word is zero, then we can just examine the high word. Similarly for low word -1 and less-or-equal-than or greater-than. */ @@ -3142,6 +3109,7 @@ ix86_expand_int_movcc (rtx operands[]) rtx compare_op; machine_mode mode = GET_MODE (operands[0]); bool sign_bit_compare_p = false; + bool negate_cc_compare_p = false; rtx op0 = XEXP (operands[1], 0); rtx op1 = XEXP (operands[1], 1); rtx op2 = operands[2]; @@ -3188,16 +3156,48 @@ ix86_expand_int_movcc (rtx operands[]) HOST_WIDE_INT cf = INTVAL (op3); HOST_WIDE_INT diff; + if ((mode == SImode + || (TARGET_64BIT && mode == DImode)) + && (GET_MODE (op0) == SImode + || (TARGET_64BIT && GET_MODE (op0) == DImode))) + { + /* Special case x != 0 ? -1 : y. */ + if (code == NE && op1 == const0_rtx && ct == -1) + { + negate_cc_compare_p = true; + std::swap (ct, cf); + code = EQ; + } + else if (code == EQ && op1 == const0_rtx && cf == -1) + negate_cc_compare_p = true; + } + diff = ct - cf; /* Sign bit compares are better done using shifts than we do by using sbb. */ if (sign_bit_compare_p + || negate_cc_compare_p || ix86_expand_carry_flag_compare (code, op0, op1, &compare_op)) { /* Detect overlap between destination and compare sources. */ rtx tmp = out; - if (!sign_bit_compare_p) + if (negate_cc_compare_p) + { + if (GET_MODE (op0) == DImode) + emit_insn (gen_x86_negdi_ccc (gen_reg_rtx (DImode), op0)); + else + emit_insn (gen_x86_negsi_ccc (gen_reg_rtx (SImode), + gen_lowpart (SImode, op0))); + + tmp = gen_reg_rtx (mode); + if (mode == DImode) + emit_insn (gen_x86_movdicc_0_m1_neg (tmp)); + else + emit_insn (gen_x86_movsicc_0_m1_neg (gen_lowpart (SImode, + tmp))); + } + else if (!sign_bit_compare_p) { rtx flags; bool fpcmp = false; diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index 6fe41c3..8908e42 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -711,8 +711,7 @@ gen_gpr_to_xmm_move_src (enum machine_mode vmode, rtx gpr) switch (GET_MODE_NUNITS (vmode)) { case 1: - /* We are not using this case currently. */ - gcc_unreachable (); + return gen_rtx_SUBREG (vmode, gpr, 0); case 2: return gen_rtx_VEC_CONCAT (vmode, gpr, CONST0_RTX (GET_MODE_INNER (vmode))); @@ -932,6 +931,48 @@ general_scalar_chain::convert_op (rtx *op, rtx_insn *insn) } } +/* Convert COMPARE to vector mode. */ + +rtx +general_scalar_chain::convert_compare (rtx op1, rtx op2, rtx_insn *insn) +{ + rtx tmp = gen_reg_rtx (vmode); + rtx src; + convert_op (&op1, insn); + /* Comparison against anything other than zero, requires an XOR. */ + if (op2 != const0_rtx) + { + convert_op (&op2, insn); + /* If both operands are MEMs, explicitly load the OP1 into TMP. */ + if (MEM_P (op1) && MEM_P (op2)) + { + emit_insn_before (gen_rtx_SET (tmp, op1), insn); + src = tmp; + } + else + src = op1; + src = gen_rtx_XOR (vmode, src, op2); + } + else + src = op1; + emit_insn_before (gen_rtx_SET (tmp, src), insn); + + if (vmode == V2DImode) + emit_insn_before (gen_vec_interleave_lowv2di (copy_rtx_if_shared (tmp), + copy_rtx_if_shared (tmp), + copy_rtx_if_shared (tmp)), + insn); + else if (vmode == V4SImode) + emit_insn_before (gen_sse2_pshufd (copy_rtx_if_shared (tmp), + copy_rtx_if_shared (tmp), + const0_rtx), + insn); + + return gen_rtx_UNSPEC (CCmode, gen_rtvec (2, copy_rtx_if_shared (tmp), + copy_rtx_if_shared (tmp)), + UNSPEC_PTEST); +} + /* Convert INSN to vector mode. */ void @@ -1090,19 +1131,8 @@ general_scalar_chain::convert_insn (rtx_insn *insn) break; case COMPARE: - src = SUBREG_REG (XEXP (XEXP (src, 0), 0)); - - gcc_assert (REG_P (src) && GET_MODE (src) == DImode); - subreg = gen_rtx_SUBREG (V2DImode, src, 0); - emit_insn_before (gen_vec_interleave_lowv2di - (copy_rtx_if_shared (subreg), - copy_rtx_if_shared (subreg), - copy_rtx_if_shared (subreg)), - insn); dst = gen_rtx_REG (CCmode, FLAGS_REG); - src = gen_rtx_UNSPEC (CCmode, gen_rtvec (2, copy_rtx_if_shared (subreg), - copy_rtx_if_shared (subreg)), - UNSPEC_PTEST); + src = convert_compare (XEXP (src, 0), XEXP (src, 1), insn); break; case CONST_INT: @@ -1339,20 +1369,14 @@ pseudo_reg_set (rtx_insn *insn) return set; } -/* Check if comparison INSN may be transformed - into vector comparison. Currently we transform - zero checks only which look like: - - (set (reg:CCZ 17 flags) - (compare:CCZ (ior:SI (subreg:SI (reg:DI x) 4) - (subreg:SI (reg:DI x) 0)) - (const_int 0 [0]))) */ +/* Check if comparison INSN may be transformed into vector comparison. + Currently we transform equality/inequality checks which look like: + (set (reg:CCZ 17 flags) (compare:CCZ (reg:TI x) (reg:TI y))) */ static bool convertible_comparison_p (rtx_insn *insn, enum machine_mode mode) { - /* ??? Currently convertible for double-word DImode chain only. */ - if (TARGET_64BIT || mode != DImode) + if (mode != (TARGET_64BIT ? TImode : DImode)) return false; if (!TARGET_SSE4_1) @@ -1375,31 +1399,14 @@ convertible_comparison_p (rtx_insn *insn, enum machine_mode mode) rtx op1 = XEXP (src, 0); rtx op2 = XEXP (src, 1); - if (op2 != CONST0_RTX (GET_MODE (op2))) + if (!CONST_INT_P (op1) + && ((!REG_P (op1) && !MEM_P (op1)) + || GET_MODE (op1) != mode)) return false; - if (GET_CODE (op1) != IOR) - return false; - - op2 = XEXP (op1, 1); - op1 = XEXP (op1, 0); - - if (!SUBREG_P (op1) - || !SUBREG_P (op2) - || GET_MODE (op1) != SImode - || GET_MODE (op2) != SImode - || ((SUBREG_BYTE (op1) != 0 - || SUBREG_BYTE (op2) != GET_MODE_SIZE (SImode)) - && (SUBREG_BYTE (op2) != 0 - || SUBREG_BYTE (op1) != GET_MODE_SIZE (SImode)))) - return false; - - op1 = SUBREG_REG (op1); - op2 = SUBREG_REG (op2); - - if (op1 != op2 - || !REG_P (op1) - || GET_MODE (op1) != DImode) + if (!CONST_INT_P (op2) + && ((!REG_P (op2) && !MEM_P (op2)) + || GET_MODE (op2) != mode)) return false; return true; diff --git a/gcc/config/i386/i386-features.h b/gcc/config/i386/i386-features.h index 5c30760..891cb46 100644 --- a/gcc/config/i386/i386-features.h +++ b/gcc/config/i386/i386-features.h @@ -181,6 +181,7 @@ class general_scalar_chain : public scalar_chain void convert_reg (rtx_insn *insn, rtx dst, rtx src); void make_vector_copies (rtx_insn *, rtx); void convert_registers (); + rtx convert_compare (rtx op1, rtx op2, rtx_insn *insn); int vector_const_cost (rtx exp); }; diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index daa60ac..11f4ddf 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -20141,6 +20141,18 @@ ix86_modes_tieable_p (machine_mode mode1, machine_mode mode2) return (GET_MODE_SIZE (mode1) == 8 && ix86_hard_regno_mode_ok (FIRST_MMX_REG, mode1)); + /* SCmode and DImode can be tied. */ + if ((mode1 == E_SCmode && mode2 == E_DImode) + || (mode1 == E_DImode && mode2 == E_SCmode)) + return TARGET_64BIT; + + /* [SD]Cmode and V2[SD]Fmode modes can be tied. */ + if ((mode1 == E_SCmode && mode2 == E_V2SFmode) + || (mode1 == E_V2SFmode && mode2 == E_SCmode) + || (mode1 == E_DCmode && mode2 == E_V2DFmode) + || (mode1 == E_V2DFmode && mode2 == E_DCmode)) + return true; + return false; } @@ -20983,6 +20995,20 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno, *total += 1; return false; + case ZERO_EXTRACT: + if (XEXP (x, 1) == const1_rtx + && GET_CODE (XEXP (x, 2)) == ZERO_EXTEND + && GET_MODE (XEXP (x, 2)) == SImode + && GET_MODE (XEXP (XEXP (x, 2), 0)) == QImode) + { + /* Ignore cost of zero extension and masking of last argument. */ + *total += rtx_cost (XEXP (x, 0), mode, code, 0, speed); + *total += rtx_cost (XEXP (x, 1), mode, code, 1, speed); + *total += rtx_cost (XEXP (XEXP (x, 2), 0), mode, code, 2, speed); + return true; + } + return false; + default: return false; } diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 17bdbd9..48a98e1 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1357,14 +1357,20 @@ (define_expand "cstore<mode>4" [(set (reg:CC FLAGS_REG) - (compare:CC (match_operand:SWIM 2 "nonimmediate_operand") - (match_operand:SWIM 3 "<general_operand>"))) + (compare:CC (match_operand:SDWIM 2 "nonimmediate_operand") + (match_operand:SDWIM 3 "<general_operand>"))) (set (match_operand:QI 0 "register_operand") (match_operator 1 "ordered_comparison_operator" [(reg:CC FLAGS_REG) (const_int 0)]))] "" { - if (MEM_P (operands[2]) && MEM_P (operands[3])) + if (<MODE>mode == (TARGET_64BIT ? TImode : DImode)) + { + if (GET_CODE (operands[1]) != EQ + && GET_CODE (operands[1]) != NE) + FAIL; + } + else if (MEM_P (operands[2]) && MEM_P (operands[3])) operands[2] = force_reg (<MODE>mode, operands[2]); ix86_expand_setcc (operands[0], GET_CODE (operands[1]), operands[2], operands[3]); @@ -1500,6 +1506,52 @@ [(set_attr "type" "icmp") (set_attr "mode" "QI")]) +(define_insn_and_split "*cmp<dwi>_doubleword" + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ (match_operand:<DWI> 0 "nonimmediate_operand") + (match_operand:<DWI> 1 "x86_64_general_operand")))] + "ix86_pre_reload_split ()" + "#" + "&& 1" + [(parallel [(set (reg:CCZ FLAGS_REG) + (compare:CCZ (ior:DWIH (match_dup 4) (match_dup 5)) + (const_int 0))) + (set (match_dup 4) (ior:DWIH (match_dup 4) (match_dup 5)))])] +{ + split_double_mode (<DWI>mode, &operands[0], 2, &operands[0], &operands[2]); + /* Placing the SUBREG pieces in pseudos helps reload. */ + for (int i = 0; i < 4; i++) + if (SUBREG_P (operands[i])) + operands[i] = force_reg (<MODE>mode, operands[i]); + + operands[4] = gen_reg_rtx (<MODE>mode); + if (operands[1] == const0_rtx) + emit_move_insn (operands[4], operands[0]); + else if (operands[0] == const0_rtx) + emit_move_insn (operands[4], operands[1]); + else if (operands[1] == constm1_rtx) + emit_insn (gen_one_cmpl<mode>2 (operands[4], operands[0])); + else if (operands[0] == constm1_rtx) + emit_insn (gen_one_cmpl<mode>2 (operands[4], operands[1])); + else + emit_insn (gen_xor<mode>3 (operands[4], operands[0], operands[1])); + + if (operands[3] == const0_rtx) + operands[5] = operands[2]; + else if (operands[2] == const0_rtx) + operands[5] = operands[3]; + else + { + operands[5] = gen_reg_rtx (<MODE>mode); + if (operands[3] == constm1_rtx) + emit_insn (gen_one_cmpl<mode>2 (operands[5], operands[2])); + else if (operands[2] == constm1_rtx) + emit_insn (gen_one_cmpl<mode>2 (operands[5], operands[3])); + else + emit_insn (gen_xor<mode>3 (operands[5], operands[2], operands[3])); + } +}) + ;; These implement float point compares. ;; %%% See if we can get away with VOIDmode operands on the actual insns, ;; which would allow mix and match FP modes on the compares. Which is what @@ -6298,7 +6350,7 @@ [(set (reg FLAGS_REG) (compare (match_operand:SWI124 1 "nonimmediate_operand" "0") - (match_operand:SWI124 2 "const_int_operand" "n"))) + (match_operand:SWI124 2 "const_int_operand"))) (clobber (match_scratch:SWI124 0 "=<r>"))] "ix86_match_ccmode (insn, CCGCmode)" { @@ -6504,7 +6556,7 @@ (eq:CCO (plus:<DWI> (sign_extend:<DWI> (match_operand:SWI 1 "nonimmediate_operand" "0")) - (match_operand:<DWI> 3 "const_int_operand" "i")) + (match_operand:<DWI> 3 "const_int_operand")) (sign_extend:<DWI> (plus:SWI (match_dup 1) @@ -6577,7 +6629,7 @@ (plus:<QPWI> (sign_extend:<QPWI> (match_operand:<DWI> 1 "nonimmediate_operand" "%0")) - (match_operand:<QPWI> 3 "const_scalar_int_operand" "")) + (match_operand:<QPWI> 3 "const_scalar_int_operand" "n")) (sign_extend:<QPWI> (plus:<DWI> (match_dup 1) @@ -6662,7 +6714,7 @@ [(match_operand 3 "flags_reg_operand") (const_int 0)]) (sign_extend:<DWI> (match_operand:SWI 1 "nonimmediate_operand" "%0"))) - (match_operand:<DWI> 6 "const_int_operand" "")) + (match_operand:<DWI> 6 "const_int_operand" "n")) (sign_extend:<DWI> (plus:SWI (plus:SWI @@ -6827,8 +6879,8 @@ (any_or:SWI12 (ashift:SWI12 (match_operand:SWI12 1 "index_register_operand" "l") - (match_operand 2 "const_0_to_3_operand" "n")) - (match_operand 3 "const_int_operand" "n")))] + (match_operand 2 "const_0_to_3_operand")) + (match_operand 3 "const_int_operand")))] "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && ((unsigned HOST_WIDE_INT) INTVAL (operands[3]) < (HOST_WIDE_INT_1U << INTVAL (operands[2])))" @@ -6851,8 +6903,8 @@ (any_or:SWI48 (ashift:SWI48 (match_operand:SWI48 1 "index_register_operand" "l") - (match_operand 2 "const_0_to_3_operand" "n")) - (match_operand 3 "const_int_operand" "n")))] + (match_operand 2 "const_0_to_3_operand")) + (match_operand 3 "const_int_operand")))] "(unsigned HOST_WIDE_INT) INTVAL (operands[3]) < (HOST_WIDE_INT_1U << INTVAL (operands[2]))" "#" @@ -7048,7 +7100,7 @@ (eq:CCO (minus:<DWI> (sign_extend:<DWI> (match_operand:SWI 1 "nonimmediate_operand" "0")) - (match_operand:<DWI> 3 "const_int_operand" "i")) + (match_operand:<DWI> 3 "const_int_operand")) (sign_extend:<DWI> (minus:SWI (match_dup 1) @@ -7116,7 +7168,7 @@ (minus:<QPWI> (sign_extend:<QPWI> (match_operand:<DWI> 1 "nonimmediate_operand" "0")) - (match_operand:<QPWI> 3 "const_scalar_int_operand" "")) + (match_operand:<QPWI> 3 "const_scalar_int_operand")) (sign_extend:<QPWI> (minus:<DWI> (match_dup 1) @@ -7199,7 +7251,7 @@ (match_operand:SWI 1 "nonimmediate_operand" "%0")) (match_operator:<DWI> 4 "ix86_carry_flag_operator" [(match_operand 3 "flags_reg_operand") (const_int 0)])) - (match_operand:<DWI> 6 "const_int_operand" "")) + (match_operand:<DWI> 6 "const_int_operand" "n")) (sign_extend:<DWI> (minus:SWI (minus:SWI @@ -7469,7 +7521,7 @@ (match_operand:SWI48 1 "nonimmediate_operand" "%0")) (match_operand:SWI48 2 "x86_64_immediate_operand" "e"))) (plus:<DWI> - (match_operand:<DWI> 6 "const_scalar_int_operand" "") + (match_operand:<DWI> 6 "const_scalar_int_operand") (match_operator:<DWI> 4 "ix86_carry_flag_operator" [(match_dup 3) (const_int 0)])))) (set (match_operand:SWI48 0 "nonimmediate_operand" "=rm") @@ -8463,7 +8515,7 @@ (lshiftrt:<DWI> (mult:<DWI> (zero_extend:<DWI> (match_dup 2)) (zero_extend:<DWI> (match_dup 3))) - (match_operand:QI 4 "const_int_operand" "n"))))] + (match_operand:QI 4 "const_int_operand"))))] "TARGET_BMI2 && INTVAL (operands[4]) == <MODE_SIZE> * BITS_PER_UNIT && !(MEM_P (operands[2]) && MEM_P (operands[3]))" "mulx\t{%3, %0, %1|%1, %0, %3}" @@ -9097,7 +9149,7 @@ (define_insn_and_split "*udivmod<mode>4_pow2" [(set (match_operand:SWI48 0 "register_operand" "=r") (udiv:SWI48 (match_operand:SWI48 2 "register_operand" "0") - (match_operand:SWI48 3 "const_int_operand" "n"))) + (match_operand:SWI48 3 "const_int_operand"))) (set (match_operand:SWI48 1 "register_operand" "=r") (umod:SWI48 (match_dup 2) (match_dup 3))) (clobber (reg:CC FLAGS_REG))] @@ -9178,7 +9230,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (udiv:SI (match_operand:SI 2 "register_operand" "0") - (match_operand:SI 3 "const_int_operand" "n")))) + (match_operand:SI 3 "const_int_operand")))) (set (match_operand:SI 1 "register_operand" "=r") (umod:SI (match_dup 2) (match_dup 3))) (clobber (reg:CC FLAGS_REG))] @@ -9262,7 +9314,7 @@ [(set (match_operand:DI 1 "register_operand" "=r") (zero_extend:DI (umod:SI (match_operand:SI 2 "register_operand" "0") - (match_operand:SI 3 "const_int_operand" "n")))) + (match_operand:SI 3 "const_int_operand")))) (set (match_operand:SI 0 "register_operand" "=r") (udiv:SI (match_dup 2) (match_dup 3))) (clobber (reg:CC FLAGS_REG))] @@ -9329,7 +9381,7 @@ ;; Avoid sign-extension (using cdq) for constant numerators. (define_insn_and_split "*divmodsi4_const" [(set (match_operand:SI 0 "register_operand" "=&a") - (div:SI (match_operand:SI 2 "const_int_operand" "n") + (div:SI (match_operand:SI 2 "const_int_operand") (match_operand:SI 3 "nonimmediate_operand" "rm"))) (set (match_operand:SI 1 "register_operand" "=&d") (mod:SI (match_dup 2) (match_dup 3))) @@ -9614,8 +9666,8 @@ (match_operator 1 "compare_operator" [(zero_extract:SWI248 (match_operand 2 "int_nonimmediate_operand" "rm") - (match_operand 3 "const_int_operand" "n") - (match_operand 4 "const_int_operand" "n")) + (match_operand 3 "const_int_operand") + (match_operand 4 "const_int_operand")) (const_int 0)]))] "/* Ensure that resulting mask is zero or sign extended operand. */ INTVAL (operands[4]) >= 0 @@ -11189,6 +11241,14 @@ [(set_attr "type" "negnot") (set_attr "mode" "<MODE>")]) +(define_expand "x86_neg<mode>_ccc" + [(parallel + [(set (reg:CCC FLAGS_REG) + (ne:CCC (match_operand:SWI48 1 "register_operand") + (const_int 0))) + (set (match_operand:SWI48 0 "register_operand") + (neg:SWI48 (match_dup 1)))])]) + (define_insn "*negqi_ext<mode>_2" [(set (zero_extract:SWI248 (match_operand:SWI248 0 "register_operand" "+Q") @@ -11830,11 +11890,16 @@ (ashift:<DWI> (match_operand:<DWI> 1 "register_operand") (subreg:QI - (and:SI - (match_operand:SI 2 "register_operand" "c") - (match_operand:SI 3 "const_int_operand")) 0))) - (clobber (reg:CC FLAGS_REG))] - "(INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + (and + (match_operand 2 "register_operand" "c") + (match_operand 3 "const_int_operand")) 0))) + (clobber (reg:CC FLAGS_REG))] + "((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + || ((INTVAL (operands[3]) & (2 * <MODE_SIZE> * BITS_PER_UNIT - 1)) + == (2 * <MODE_SIZE> * BITS_PER_UNIT - 1))) + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -11852,6 +11917,15 @@ (ashift:DWIH (match_dup 5) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] { + if ((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) != 0) + { + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); + emit_insn (gen_ashl<dwi>3_doubleword (operands[0], operands[1], + operands[2])); + DONE; + } + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT - 1); @@ -11860,11 +11934,15 @@ if ((INTVAL (operands[3]) & ((<MODE_SIZE> * BITS_PER_UNIT) - 1)) != ((<MODE_SIZE> * BITS_PER_UNIT) - 1)) { - rtx tem = gen_reg_rtx (SImode); - emit_insn (gen_andsi3 (tem, operands[2], operands[3])); - operands[2] = tem; + rtx xops[3]; + xops[0] = gen_reg_rtx (GET_MODE (operands[2])); + xops[1] = operands[2]; + xops[2] = operands[3]; + ix86_expand_binary_operator (AND, GET_MODE (operands[2]), xops); + operands[2] = xops[0]; } + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); operands[2] = gen_lowpart (QImode, operands[2]); if (!rtx_equal_p (operands[6], operands[7])) @@ -11879,7 +11957,9 @@ (match_operand:QI 2 "register_operand" "c") (match_operand:QI 3 "const_int_operand")))) (clobber (reg:CC FLAGS_REG))] - "(INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + "((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + || ((INTVAL (operands[3]) & (2 * <MODE_SIZE> * BITS_PER_UNIT - 1)) + == (2 * <MODE_SIZE> * BITS_PER_UNIT - 1))) && ix86_pre_reload_split ()" "#" "&& 1" @@ -11897,6 +11977,13 @@ (ashift:DWIH (match_dup 5) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] { + if ((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) != 0) + { + emit_insn (gen_ashl<dwi>3_doubleword (operands[0], operands[1], + operands[2])); + DONE; + } + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT - 1); @@ -11914,7 +12001,7 @@ emit_move_insn (operands[6], operands[7]); }) -(define_insn "*ashl<mode>3_doubleword" +(define_insn "ashl<mode>3_doubleword" [(set (match_operand:DWI 0 "register_operand" "=&r") (ashift:DWI (match_operand:DWI 1 "reg_or_pm1_operand" "0n") (match_operand:QI 2 "nonmemory_operand" "<S>c"))) @@ -11972,12 +12059,12 @@ (define_insn "*x86_64_shld_1" [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m") (ior:DI (ashift:DI (match_dup 0) - (match_operand:QI 2 "const_0_to_63_operand" "J")) + (match_operand:QI 2 "const_0_to_63_operand")) (subreg:DI (lshiftrt:TI (zero_extend:TI (match_operand:DI 1 "register_operand" "r")) - (match_operand:QI 3 "const_0_to_255_operand" "N")) 0))) + (match_operand:QI 3 "const_0_to_255_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && INTVAL (operands[3]) == 64 - INTVAL (operands[2])" @@ -12036,12 +12123,12 @@ (define_insn "*x86_shld_1" [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m") (ior:SI (ashift:SI (match_dup 0) - (match_operand:QI 2 "const_0_to_31_operand" "I")) + (match_operand:QI 2 "const_0_to_31_operand")) (subreg:SI (lshiftrt:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) - (match_operand:QI 3 "const_0_to_63_operand" "J")) 0))) + (match_operand:QI 3 "const_0_to_63_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "INTVAL (operands[3]) == 32 - INTVAL (operands[2])" "shld{l}\t{%2, %1, %0|%0, %1, %2}" @@ -12126,13 +12213,16 @@ (ashift:SWI48 (match_operand:SWI48 1 "nonimmediate_operand") (subreg:QI - (and:SI - (match_operand:SI 2 "register_operand" "c,r") - (match_operand:SI 3 "const_int_operand")) 0))) + (and + (match_operand 2 "register_operand" "c,r") + (match_operand 3 "const_int_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (ASHIFT, <MODE>mode, operands) && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1)) == GET_MODE_BITSIZE (<MODE>mode)-1 + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -12141,7 +12231,10 @@ (ashift:SWI48 (match_dup 1) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] - "operands[2] = gen_lowpart (QImode, operands[2]);" +{ + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); +} [(set_attr "isa" "*,bmi2")]) (define_insn_and_split "*ashl<mode>3_mask_1" @@ -12561,7 +12654,7 @@ [(set (reg FLAGS_REG) (compare (ashift:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_1_to_31_operand")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))] @@ -12714,13 +12807,16 @@ (any_shiftrt:SWI48 (match_operand:SWI48 1 "nonimmediate_operand") (subreg:QI - (and:SI - (match_operand:SI 2 "register_operand" "c,r") - (match_operand:SI 3 "const_int_operand")) 0))) + (and + (match_operand 2 "register_operand" "c,r") + (match_operand 3 "const_int_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands) && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1)) == GET_MODE_BITSIZE (<MODE>mode)-1 + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -12729,7 +12825,10 @@ (any_shiftrt:SWI48 (match_dup 1) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] - "operands[2] = gen_lowpart (QImode, operands[2]);" +{ + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); +} [(set_attr "isa" "*,bmi2")]) (define_insn_and_split "*<insn><mode>3_mask_1" @@ -12759,11 +12858,16 @@ (any_shiftrt:<DWI> (match_operand:<DWI> 1 "register_operand") (subreg:QI - (and:SI - (match_operand:SI 2 "register_operand" "c") - (match_operand:SI 3 "const_int_operand")) 0))) - (clobber (reg:CC FLAGS_REG))] - "(INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + (and + (match_operand 2 "register_operand" "c") + (match_operand 3 "const_int_operand")) 0))) + (clobber (reg:CC FLAGS_REG))] + "((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + || ((INTVAL (operands[3]) & (2 * <MODE_SIZE> * BITS_PER_UNIT - 1)) + == (2 * <MODE_SIZE> * BITS_PER_UNIT - 1))) + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -12781,6 +12885,15 @@ (any_shiftrt:DWIH (match_dup 7) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] { + if ((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) != 0) + { + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); + emit_insn (gen_<insn><dwi>3_doubleword (operands[0], operands[1], + operands[2])); + DONE; + } + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT - 1); @@ -12789,11 +12902,15 @@ if ((INTVAL (operands[3]) & ((<MODE_SIZE> * BITS_PER_UNIT) - 1)) != ((<MODE_SIZE> * BITS_PER_UNIT) - 1)) { - rtx tem = gen_reg_rtx (SImode); - emit_insn (gen_andsi3 (tem, operands[2], operands[3])); - operands[2] = tem; + rtx xops[3]; + xops[0] = gen_reg_rtx (GET_MODE (operands[2])); + xops[1] = operands[2]; + xops[2] = operands[3]; + ix86_expand_binary_operator (AND, GET_MODE (operands[2]), xops); + operands[2] = xops[0]; } + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); operands[2] = gen_lowpart (QImode, operands[2]); if (!rtx_equal_p (operands[4], operands[5])) @@ -12808,7 +12925,9 @@ (match_operand:QI 2 "register_operand" "c") (match_operand:QI 3 "const_int_operand")))) (clobber (reg:CC FLAGS_REG))] - "(INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + "((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) == 0 + || ((INTVAL (operands[3]) & (2 * <MODE_SIZE> * BITS_PER_UNIT - 1)) + == (2 * <MODE_SIZE> * BITS_PER_UNIT - 1))) && ix86_pre_reload_split ()" "#" "&& 1" @@ -12826,6 +12945,13 @@ (any_shiftrt:DWIH (match_dup 7) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] { + if ((INTVAL (operands[3]) & (<MODE_SIZE> * BITS_PER_UNIT)) != 0) + { + emit_insn (gen_<insn><dwi>3_doubleword (operands[0], operands[1], + operands[2])); + DONE; + } + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT - 1); @@ -12843,7 +12969,7 @@ emit_move_insn (operands[4], operands[5]); }) -(define_insn_and_split "*<insn><mode>3_doubleword" +(define_insn_and_split "<insn><mode>3_doubleword" [(set (match_operand:DWI 0 "register_operand" "=&r") (any_shiftrt:DWI (match_operand:DWI 1 "register_operand" "0") (match_operand:QI 2 "nonmemory_operand" "<S>c"))) @@ -12895,12 +13021,12 @@ (define_insn "*x86_64_shrd_1" [(set (match_operand:DI 0 "nonimmediate_operand" "+r*m") (ior:DI (lshiftrt:DI (match_dup 0) - (match_operand:QI 2 "const_0_to_63_operand" "J")) + (match_operand:QI 2 "const_0_to_63_operand")) (subreg:DI (ashift:TI (zero_extend:TI (match_operand:DI 1 "register_operand" "r")) - (match_operand:QI 3 "const_0_to_255_operand" "N")) 0))) + (match_operand:QI 3 "const_0_to_255_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && INTVAL (operands[3]) == 64 - INTVAL (operands[2])" @@ -12959,12 +13085,12 @@ (define_insn "*x86_shrd_1" [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m") (ior:SI (lshiftrt:SI (match_dup 0) - (match_operand:QI 2 "const_0_to_31_operand" "I")) + (match_operand:QI 2 "const_0_to_31_operand")) (subreg:SI (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) - (match_operand:QI 3 "const_0_to_63_operand" "J")) 0))) + (match_operand:QI 3 "const_0_to_63_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "INTVAL (operands[3]) == 32 - INTVAL (operands[2])" "shrd{l}\t{%2, %1, %0|%0, %1, %2}" @@ -13372,7 +13498,7 @@ [(set (reg FLAGS_REG) (compare (any_shiftrt:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "const_1_to_31_operand" "I")) + (match_operand:QI 2 "const_1_to_31_operand")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (any_shiftrt:SI (match_dup 1) (match_dup 2))))] @@ -13526,13 +13652,16 @@ (any_rotate:SWI (match_operand:SWI 1 "nonimmediate_operand") (subreg:QI - (and:SI - (match_operand:SI 2 "register_operand" "c") - (match_operand:SI 3 "const_int_operand")) 0))) + (and + (match_operand 2 "register_operand" "c") + (match_operand 3 "const_int_operand")) 0))) (clobber (reg:CC FLAGS_REG))] "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands) && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1)) == GET_MODE_BITSIZE (<MODE>mode)-1 + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -13541,18 +13670,24 @@ (any_rotate:SWI (match_dup 1) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] - "operands[2] = gen_lowpart (QImode, operands[2]);") +{ + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (QImode, operands[2]); +}) (define_split [(set (match_operand:SWI 0 "register_operand") (any_rotate:SWI (match_operand:SWI 1 "const_int_operand") (subreg:QI - (and:SI - (match_operand:SI 2 "register_operand") - (match_operand:SI 3 "const_int_operand")) 0)))] + (and + (match_operand 2 "register_operand") + (match_operand 3 "const_int_operand")) 0)))] "(INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode) - 1)) - == GET_MODE_BITSIZE (<MODE>mode) - 1" + == GET_MODE_BITSIZE (<MODE>mode) - 1 + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0))" [(set (match_dup 4) (match_dup 1)) (set (match_dup 0) (any_rotate:SWI (match_dup 4) @@ -13749,7 +13884,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "rm") - (match_operand:QI 2 "const_0_to_31_operand" "I"))))] + (match_operand:QI 2 "const_0_to_31_operand"))))] "TARGET_64BIT && TARGET_BMI2 && !optimize_function_for_size_p (cfun)" "rorx\t{%2, %1, %k0|%k0, %1, %2}" [(set_attr "type" "rotatex") @@ -13916,14 +14051,17 @@ (ashift:SWI48 (const_int 1) (subreg:QI - (and:SI - (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "const_int_operand")) 0)) + (and + (match_operand 1 "register_operand") + (match_operand 2 "const_int_operand")) 0)) (match_operand:SWI48 3 "register_operand"))) (clobber (reg:CC FLAGS_REG))] "TARGET_USE_BT && (INTVAL (operands[2]) & (GET_MODE_BITSIZE (<MODE>mode)-1)) == GET_MODE_BITSIZE (<MODE>mode)-1 + && GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[1])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -13934,7 +14072,10 @@ (match_dup 1)) (match_dup 3))) (clobber (reg:CC FLAGS_REG))])] - "operands[1] = gen_lowpart (QImode, operands[1]);") +{ + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + operands[1] = gen_lowpart (QImode, operands[1]); +}) (define_insn_and_split "*<btsc><mode>_mask_1" [(set (match_operand:SWI48 0 "register_operand") @@ -13981,14 +14122,17 @@ (rotate:SWI48 (const_int -2) (subreg:QI - (and:SI - (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "const_int_operand")) 0)) + (and + (match_operand 1 "register_operand") + (match_operand 2 "const_int_operand")) 0)) (match_operand:SWI48 3 "register_operand"))) (clobber (reg:CC FLAGS_REG))] "TARGET_USE_BT && (INTVAL (operands[2]) & (GET_MODE_BITSIZE (<MODE>mode)-1)) == GET_MODE_BITSIZE (<MODE>mode)-1 + && GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[1])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) && ix86_pre_reload_split ()" "#" "&& 1" @@ -13999,7 +14143,10 @@ (match_dup 1)) (match_dup 3))) (clobber (reg:CC FLAGS_REG))])] - "operands[1] = gen_lowpart (QImode, operands[1]);") +{ + operands[1] = force_reg (GET_MODE (operands[1]), operands[1]); + operands[1] = gen_lowpart (QImode, operands[1]); +}) (define_insn_and_split "*btr<mode>_mask_1" [(set (match_operand:SWI48 0 "register_operand") @@ -14102,7 +14249,7 @@ (define_insn "*btsq_imm" [(set (zero_extract:DI (match_operand:DI 0 "nonimmediate_operand" "+rm") (const_int 1) - (match_operand 1 "const_0_to_63_operand" "J")) + (match_operand 1 "const_0_to_63_operand")) (const_int 1)) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && (TARGET_USE_BT || reload_completed)" @@ -14115,7 +14262,7 @@ (define_insn "*btrq_imm" [(set (zero_extract:DI (match_operand:DI 0 "nonimmediate_operand" "+rm") (const_int 1) - (match_operand 1 "const_0_to_63_operand" "J")) + (match_operand 1 "const_0_to_63_operand")) (const_int 0)) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && (TARGET_USE_BT || reload_completed)" @@ -14128,7 +14275,7 @@ (define_insn "*btcq_imm" [(set (zero_extract:DI (match_operand:DI 0 "nonimmediate_operand" "+rm") (const_int 1) - (match_operand 1 "const_0_to_63_operand" "J")) + (match_operand 1 "const_0_to_63_operand")) (not:DI (zero_extract:DI (match_dup 0) (const_int 1) (match_dup 1)))) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && (TARGET_USE_BT || reload_completed)" @@ -14350,6 +14497,47 @@ PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0]))); }) +(define_insn_and_split "*jcc_bt<mode>_mask_1" + [(set (pc) + (if_then_else (match_operator 0 "bt_comparison_operator" + [(zero_extract:SWI48 + (match_operand:SWI48 1 "register_operand") + (const_int 1) + (zero_extend:SI + (subreg:QI + (and + (match_operand 2 "register_operand") + (match_operand 3 "const_int_operand")) 0)))]) + (label_ref (match_operand 4)) + (pc))) + (clobber (reg:CC FLAGS_REG))] + "(TARGET_USE_BT || optimize_function_for_size_p (cfun)) + && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1)) + == GET_MODE_BITSIZE (<MODE>mode)-1 + && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT + && IN_RANGE (GET_MODE_SIZE (GET_MODE (operands[2])), 2, + 4 << (TARGET_64BIT ? 1 : 0)) + && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (zero_extract:SWI48 + (match_dup 1) + (const_int 1) + (match_dup 2)) + (const_int 0))) + (set (pc) + (if_then_else (match_op_dup 0 [(reg:CCC FLAGS_REG) (const_int 0)]) + (label_ref (match_dup 4)) + (pc)))] +{ + operands[2] = force_reg (GET_MODE (operands[2]), operands[2]); + operands[2] = gen_lowpart (SImode, operands[2]); + operands[0] = shallow_copy_rtx (operands[0]); + PUT_CODE (operands[0], reverse_condition (GET_CODE (operands[0]))); +}) + ;; Help combine recognize bt followed by cmov (define_split [(set (match_operand:SWI248 0 "register_operand") @@ -14656,7 +14844,7 @@ (unspec:QI [(match_operand:HF 1 "register_operand" "v") (match_operand:HF 2 "nonimmediate_operand" "vm") - (match_operand:SI 3 "const_0_to_31_operand" "n")] + (match_operand:SI 3 "const_0_to_31_operand")] UNSPEC_PCMP))] "TARGET_AVX512FP16" "vcmpsh\t{%3, %2, %1, %0|%0, %1, %2, %3}" @@ -16673,7 +16861,7 @@ (zero_extract:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm") (umin:SWI48 (and:SWI48 (match_dup 2) (const_int 255)) - (match_operand:SWI48 3 "const_int_operand" "n")) + (match_operand:SWI48 3 "const_int_operand")) (const_int 0)) (const_int 0))) (clobber (reg:CC FLAGS_REG))] @@ -16690,7 +16878,7 @@ (zero_extract:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm") (umin:SWI48 (zero_extend:SWI48 (match_dup 2)) - (match_operand:SWI48 3 "const_int_operand" "n")) + (match_operand:SWI48 3 "const_int_operand")) (const_int 0)) (const_int 0))) (clobber (reg:CC FLAGS_REG))] @@ -16708,7 +16896,7 @@ (zero_extract:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm") (umin:SWI48 (zero_extend:SWI48 (match_dup 2)) - (match_operand:SWI48 3 "const_int_operand" "n")) + (match_operand:SWI48 3 "const_int_operand")) (const_int 0)) (const_int 0)) (const_int 0))) @@ -16791,8 +16979,8 @@ [(set (match_operand:SWI48 0 "register_operand" "=r") (zero_extract:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm") - (match_operand 2 "const_0_to_255_operand" "N") - (match_operand 3 "const_0_to_255_operand" "N"))) + (match_operand 2 "const_0_to_255_operand") + (match_operand 3 "const_0_to_255_operand"))) (clobber (reg:CC FLAGS_REG))] "TARGET_TBM" { @@ -19415,7 +19603,7 @@ [(set (match_operand:MODEFH 0 "register_operand" "=x,x,x,v,v") (unspec:MODEFH [(match_operand:MODEFH 1 "nonimmediate_operand" "0,x,m,v,m") - (match_operand:SI 2 "const_0_to_15_operand" "n,n,n,n,n")] + (match_operand:SI 2 "const_0_to_15_operand")] UNSPEC_ROUND))] "TARGET_SSE4_1" "@ @@ -20700,6 +20888,12 @@ (set_attr "mode" "<MODE>") (set_attr "length_immediate" "0")]) +(define_expand "x86_mov<mode>cc_0_m1_neg" + [(parallel + [(set (match_operand:SWI48 0 "register_operand") + (neg:SWI48 (ltu:SWI48 (reg:CCC FLAGS_REG) (const_int 0)))) + (clobber (reg:CC FLAGS_REG))])]) + (define_split [(set (match_operand:SWI48 0 "register_operand") (neg:SWI48 @@ -21607,7 +21801,7 @@ (unspec_volatile:P [(match_operand:P 1 "register_operand" "0")] UNSPECV_PROBE_STACK_RANGE)) (set (reg:P SP_REG) - (minus:P (reg:P SP_REG) (match_operand:P 2 "const_int_operand" "n"))) + (minus:P (reg:P SP_REG) (match_operand:P 2 "const_int_operand"))) (clobber (reg:CC FLAGS_REG)) (clobber (mem:BLK (scratch)))] "" @@ -21617,7 +21811,7 @@ (define_insn "@probe_stack_range_<mode>" [(set (match_operand:P 0 "register_operand" "=r") (unspec_volatile:P [(match_operand:P 1 "register_operand" "0") - (match_operand:P 2 "const_int_operand" "n")] + (match_operand:P 2 "const_int_operand")] UNSPECV_PROBE_STACK_RANGE)) (clobber (reg:CC FLAGS_REG))] "" @@ -23061,7 +23255,7 @@ (define_insn "*prefetch_3dnow" [(prefetch (match_operand 0 "address_operand" "p") - (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 1 "const_int_operand") (const_int 3))] "TARGET_3DNOW || TARGET_PRFCHW || TARGET_PREFETCHWT1" { @@ -23611,7 +23805,7 @@ (define_insn "@lwp_lwpval<mode>" [(unspec_volatile [(match_operand:SWI48 0 "register_operand" "r") (match_operand:SI 1 "nonimmediate_operand" "rm") - (match_operand:SI 2 "const_int_operand" "i")] + (match_operand:SI 2 "const_int_operand")] UNSPECV_LWPVAL_INTRINSIC)] "TARGET_LWP" "lwpval\t{%2, %1, %0|%0, %1, %2}" @@ -23624,7 +23818,7 @@ [(set (reg:CCC FLAGS_REG) (unspec_volatile:CCC [(match_operand:SWI48 0 "register_operand" "r") (match_operand:SI 1 "nonimmediate_operand" "rm") - (match_operand:SI 2 "const_int_operand" "i")] + (match_operand:SI 2 "const_int_operand")] UNSPECV_LWPINS_INTRINSIC))] "TARGET_LWP" "lwpins\t{%2, %1, %0|%0, %1, %2}" @@ -23830,7 +24024,7 @@ (set_attr "length" "3")]) (define_insn "xabort" - [(unspec_volatile [(match_operand:SI 0 "const_0_to_255_operand" "n")] + [(unspec_volatile [(match_operand:SI 0 "const_0_to_255_operand")] UNSPECV_XABORT)] "TARGET_RTM" "xabort\t%0" diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md index 197f19e..ba53007a 100644 --- a/gcc/config/i386/mmx.md +++ b/gcc/config/i386/mmx.md @@ -3454,7 +3454,7 @@ [(set (match_operand:HI 0 "register_sse4nonimm_operand" "=r,r,m") (vec_select:HI (match_operand:V4HI 1 "register_operand" "y,YW,YW") - (parallel [(match_operand:SI 2 "const_0_to_3_operand" "n,n,n")])))] + (parallel [(match_operand:SI 2 "const_0_to_3_operand")])))] "(TARGET_MMX || TARGET_MMX_WITH_SSE) && (TARGET_SSE || TARGET_3DNOW_A)" "@ @@ -3473,7 +3473,7 @@ (zero_extend:SWI48 (vec_select:HI (match_operand:V4HI 1 "register_operand" "y,YW") - (parallel [(match_operand:SI 2 "const_0_to_3_operand" "n,n")]))))] + (parallel [(match_operand:SI 2 "const_0_to_3_operand")]))))] "(TARGET_MMX || TARGET_MMX_WITH_SSE) && (TARGET_SSE || TARGET_3DNOW_A)" "@ @@ -3490,7 +3490,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,m") (vec_select:QI (match_operand:V8QI 1 "register_operand" "YW,YW") - (parallel [(match_operand:SI 2 "const_0_to_7_operand" "n,n")])))] + (parallel [(match_operand:SI 2 "const_0_to_7_operand")])))] "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" "@ %vpextrb\t{%2, %1, %k0|%k0, %1, %2} @@ -3507,7 +3507,7 @@ (zero_extend:SWI248 (vec_select:QI (match_operand:V8QI 1 "register_operand" "YW") - (parallel [(match_operand:SI 2 "const_0_to_7_operand" "n")]))))] + (parallel [(match_operand:SI 2 "const_0_to_7_operand")]))))] "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" "%vpextrb\t{%2, %1, %k0|%k0, %1, %2}" [(set_attr "type" "sselog1") @@ -3630,7 +3630,7 @@ (vec_merge:V4HI (match_operand:V4HI 2 "register_operand" "Yr,*x,x") (match_operand:V4HI 1 "register_operand" "0,0,x") - (match_operand:SI 3 "const_0_to_15_operand" "n,n,n")))] + (match_operand:SI 3 "const_0_to_15_operand")))] "TARGET_SSE4_1 && TARGET_MMX_WITH_SSE" "@ pblendw\t{%3, %2, %0|%0, %2, %3} @@ -3648,7 +3648,7 @@ (vec_merge:V2HI (match_operand:V2HI 2 "register_operand" "Yr,*x,x") (match_operand:V2HI 1 "register_operand" "0,0,x") - (match_operand:SI 3 "const_0_to_7_operand" "n,n,n")))] + (match_operand:SI 3 "const_0_to_7_operand")))] "TARGET_SSE4_1" "@ pblendw\t{%3, %2, %0|%0, %2, %3} @@ -4035,7 +4035,7 @@ [(set (match_operand:HI 0 "register_sse4nonimm_operand" "=r,m") (vec_select:HI (match_operand:V2HI 1 "register_operand" "YW,YW") - (parallel [(match_operand:SI 2 "const_0_to_1_operand" "n,n")])))] + (parallel [(match_operand:SI 2 "const_0_to_1_operand")])))] "TARGET_SSE2" "@ %vpextrw\t{%2, %1, %k0|%k0, %1, %2} @@ -4051,7 +4051,7 @@ (zero_extend:SWI48 (vec_select:HI (match_operand:V2HI 1 "register_operand" "YW") - (parallel [(match_operand:SI 2 "const_0_to_1_operand" "n")]))))] + (parallel [(match_operand:SI 2 "const_0_to_1_operand")]))))] "TARGET_SSE2" "%vpextrw\t{%2, %1, %k0|%k0, %1, %2}" [(set_attr "type" "sselog1") @@ -4063,7 +4063,7 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,m") (vec_select:QI (match_operand:V4QI 1 "register_operand" "YW,YW") - (parallel [(match_operand:SI 2 "const_0_to_3_operand" "n,n")])))] + (parallel [(match_operand:SI 2 "const_0_to_3_operand")])))] "TARGET_SSE4_1" "@ %vpextrb\t{%2, %1, %k0|%k0, %1, %2} @@ -4080,7 +4080,7 @@ (zero_extend:SWI248 (vec_select:QI (match_operand:V4QI 1 "register_operand" "YW") - (parallel [(match_operand:SI 2 "const_0_to_3_operand" "n")]))))] + (parallel [(match_operand:SI 2 "const_0_to_3_operand")]))))] "TARGET_SSE4_1" "%vpextrb\t{%2, %1, %k0|%k0, %1, %2}" [(set_attr "type" "sselog1") @@ -4405,13 +4405,21 @@ (set_attr "type" "sseiadd") (set_attr "mode" "TI")]) -(define_insn "mmx_psadbw" +(define_expand "mmx_psadbw" + [(set (match_operand:V1DI 0 "register_operand") + (unspec:V1DI [(match_operand:V8QI 1 "register_mmxmem_operand") + (match_operand:V8QI 2 "register_mmxmem_operand")] + UNSPEC_PSADBW))] + "(TARGET_MMX || TARGET_MMX_WITH_SSE) && (TARGET_SSE || TARGET_3DNOW_A)" + "ix86_fixup_binary_operands_no_copy (PLUS, V8QImode, operands);") + +(define_insn "*mmx_psadbw" [(set (match_operand:V1DI 0 "register_operand" "=y,x,Yw") - (unspec:V1DI [(match_operand:V8QI 1 "register_operand" "0,0,Yw") + (unspec:V1DI [(match_operand:V8QI 1 "register_mmxmem_operand" "%0,0,Yw") (match_operand:V8QI 2 "register_mmxmem_operand" "ym,x,Yw")] UNSPEC_PSADBW))] - "(TARGET_MMX || TARGET_MMX_WITH_SSE) - && (TARGET_SSE || TARGET_3DNOW_A)" + "(TARGET_MMX || TARGET_MMX_WITH_SSE) && (TARGET_SSE || TARGET_3DNOW_A) + && ix86_binary_operator_ok (PLUS, V8QImode, operands)" "@ psadbw\t{%2, %0|%0, %2} psadbw\t{%2, %0|%0, %2} diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 8b2602b..62688f8 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -301,7 +301,8 @@ ;; All 128bit and 256bit vector modes (define_mode_iterator V_128_256 - [V32QI V16QI V16HI V8HI V8SI V4SI V4DI V2DI V16HF V8HF V8SF V4SF V4DF V2DF]) + [V32QI V16QI V16HI V8HI V8SI V4SI V4DI V2DI V2TI V1TI + V16HF V8HF V8SF V4SF V4DF V2DF]) ;; All 512bit vector modes (define_mode_iterator V_512 [V64QI V32HI V16SI V8DI V16SF V8DF]) @@ -466,9 +467,9 @@ ;; All DImode vector integer modes (define_mode_iterator V_AVX - [V16QI V8HI V4SI V2DI V4SF V2DF + [V16QI V8HI V4SI V2DI V1TI V4SF V2DF (V32QI "TARGET_AVX") (V16HI "TARGET_AVX") - (V8SI "TARGET_AVX") (V4DI "TARGET_AVX") + (V8SI "TARGET_AVX") (V4DI "TARGET_AVX") (V2TI "TARGET_AVX") (V8SF "TARGET_AVX") (V4DF"TARGET_AVX")]) (define_mode_iterator VI48_AVX @@ -890,15 +891,16 @@ [(V4SF "sse4_1") (V2DF "sse4_1") (V8SF "avx") (V4DF "avx") (V8DF "avx512f") + (V2TI "avx") (V1TI "sse4_1") (V4DI "avx") (V2DI "sse4_1") (V8SI "avx") (V4SI "sse4_1") (V16QI "sse4_1") (V32QI "avx") (V8HI "sse4_1") (V16HI "avx")]) (define_mode_attr avxsizesuffix - [(V64QI "512") (V32HI "512") (V16SI "512") (V8DI "512") - (V32QI "256") (V16HI "256") (V8SI "256") (V4DI "256") - (V16QI "") (V8HI "") (V4SI "") (V2DI "") + [(V64QI "512") (V32HI "512") (V16SI "512") (V8DI "512") (V4TI "512") + (V32QI "256") (V16HI "256") (V8SI "256") (V4DI "256") (V2TI "256") + (V16QI "") (V8HI "") (V4SI "") (V2DI "") (V1TI "") (V32HF "512") (V16SF "512") (V8DF "512") (V16HF "256") (V8SF "256") (V4DF "256") (V8HF "") (V4SF "") (V2DF "")]) @@ -1484,7 +1486,7 @@ (match_operand:MODEFH 1 "memory_operand" "m")) (match_operand:<ssevecmode> 2 "nonimm_or_0_operand" "0C") (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:<ssevecmode> 4 "const0_operand" "C") + (match_operand:<ssevecmode> 4 "const0_operand") (const_int 1)))] "TARGET_AVX512F" "vmov<ssescalarmodesuffix>\t{%1, %0%{%3%}%N2|%0%{3%}%N2, %1}" @@ -1624,7 +1626,7 @@ (vec_select:<ssescalarmode> (match_operand:VI8F_128 1 "nonimmediate_operand" "vm") (parallel [(const_int 0)])) - (match_operand:<ssescalarmode> 2 "const0_operand" "C")))] + (match_operand:<ssescalarmode> 2 "const0_operand")))] "TARGET_SSE2" "%vmovq\t{%1, %0|%0, %q1}" [(set_attr "type" "ssemov") @@ -2018,7 +2020,7 @@ [(set (match_operand:SWI1248_AVX512BWDQ 0 "register_operand" "=k") (any_lshift:SWI1248_AVX512BWDQ (match_operand:SWI1248_AVX512BWDQ 1 "register_operand" "k") - (match_operand 2 "const_0_to_255_operand" "n"))) + (match_operand 2 "const_0_to_255_operand"))) (unspec [(const_int 0)] UNSPEC_MASKOP)] "TARGET_AVX512F" "k<mshift><mskmodesuffix>\t{%2, %1, %0|%0, %1, %2}" @@ -3440,7 +3442,7 @@ (unspec:VF_128_256 [(match_operand:VF_128_256 1 "register_operand" "x") (match_operand:VF_128_256 2 "nonimmediate_operand" "xm") - (match_operand:SI 3 "const_0_to_31_operand" "n")] + (match_operand:SI 3 "const_0_to_31_operand")] UNSPEC_PCMP))] "TARGET_AVX" "vcmp<ssemodesuffix>\t{%3, %2, %1, %0|%0, %1, %2, %3}" @@ -3652,7 +3654,7 @@ (unspec:VF_128 [(match_operand:VF_128 1 "register_operand" "x") (match_operand:VF_128 2 "nonimmediate_operand" "xm") - (match_operand:SI 3 "const_0_to_31_operand" "n")] + (match_operand:SI 3 "const_0_to_31_operand")] UNSPEC_PCMP) (match_dup 1) (const_int 1)))] @@ -3745,7 +3747,7 @@ (unspec:<V48H_AVX512VL:avx512fmaskmode> [(match_operand:V48H_AVX512VL 1 "nonimmediate_operand") (match_operand:V48H_AVX512VL 2 "nonimmediate_operand") - (match_operand:SI 3 "const_0_to_7_operand" "n")] + (match_operand:SI 3 "const_0_to_7_operand")] UNSPEC_PCMP)))] "TARGET_AVX512F && (!VALID_MASK_AVX512BW_MODE (<SWI248x:MODE>mode) || TARGET_AVX512BW) @@ -3951,7 +3953,7 @@ (unspec:<avx512fmaskmode> [(match_operand:VI12_AVX512VL 1 "register_operand" "v") (match_operand:VI12_AVX512VL 2 "nonimmediate_operand" "vm") - (match_operand:SI 3 "const_0_to_7_operand" "n")] + (match_operand:SI 3 "const_0_to_7_operand")] UNSPEC_UNSIGNED_PCMP))] "TARGET_AVX512BW" "vpcmpu<ssemodesuffix>\t{%3, %2, %1, %0<mask_scalar_merge_operand4>|%0<mask_scalar_merge_operand4>, %1, %2, %3}" @@ -4049,7 +4051,7 @@ (unspec:<avx512fmaskmode> [(match_operand:VI48_AVX512VL 1 "register_operand" "v") (match_operand:VI48_AVX512VL 2 "nonimmediate_operand" "vm") - (match_operand:SI 3 "const_0_to_7_operand" "n")] + (match_operand:SI 3 "const_0_to_7_operand")] UNSPEC_UNSIGNED_PCMP))] "TARGET_AVX512F" "vpcmpu<ssemodesuffix>\t{%3, %2, %1, %0<mask_scalar_merge_operand4>|%0<mask_scalar_merge_operand4>, %1, %2, %3}" @@ -4189,7 +4191,7 @@ (unspec:<avx512fmaskmode> [(match_operand:VFH_128 1 "register_operand" "v") (match_operand:VFH_128 2 "<round_saeonly_nimm_scalar_predicate>" "<round_saeonly_constraint>") - (match_operand:SI 3 "const_0_to_31_operand" "n")] + (match_operand:SI 3 "const_0_to_31_operand")] UNSPEC_PCMP) (const_int 1)))] "TARGET_AVX512F" @@ -4205,7 +4207,7 @@ (unspec:<avx512fmaskmode> [(match_operand:VFH_128 1 "register_operand" "v") (match_operand:VFH_128 2 "<round_saeonly_nimm_scalar_predicate>" "<round_saeonly_constraint>") - (match_operand:SI 3 "const_0_to_31_operand" "n")] + (match_operand:SI 3 "const_0_to_31_operand")] UNSPEC_PCMP) (and:<avx512fmaskmode> (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk") @@ -6081,7 +6083,7 @@ (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:VFH_128 4 "const0_operand") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -6139,7 +6141,7 @@ (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:VFH_128 4 "const0_operand") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -6211,7 +6213,7 @@ (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:VFH_128 4 "const0_operand") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -6272,7 +6274,7 @@ (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:VFH_128 4 "const0_operand") (match_operand:QI 5 "register_operand" "Yk,Yk")) (match_dup 1) (const_int 1)))] @@ -6937,7 +6939,7 @@ [(set (match_operand:V8HF 0 "register_operand" "=v") (vec_concat:V8HF (any_float:V4HF (match_operand:VI4_128_8_256 1 "vector_operand" "vm")) - (match_operand:V4HF 2 "const0_operand" "C")))] + (match_operand:V4HF 2 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<floatsuffix><sseintconvert>2ph<qq2phsuff>\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") @@ -6966,7 +6968,7 @@ (match_operand:V8HF 2 "nonimm_or_0_operand" "0C") (parallel [(const_int 0) (const_int 1) (const_int 2) (const_int 3)])) (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:V4HF 4 "const0_operand" "C")))] + (match_operand:V4HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<floatsuffix><sseintconvert>2ph<qq2phsuff>\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}" [(set_attr "type" "ssecvt") @@ -6979,9 +6981,9 @@ (vec_merge:V4HF (any_float:V4HF (match_operand:VI4_128_8_256 1 "vector_operand" "vm")) - (match_operand:V4HF 3 "const0_operand" "C") + (match_operand:V4HF 3 "const0_operand") (match_operand:QI 2 "register_operand" "Yk")) - (match_operand:V4HF 4 "const0_operand" "C")))] + (match_operand:V4HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<floatsuffix><sseintconvert>2ph<qq2phsuff>\t{%1, %0%{%2%}%{z%}|%0%{%2%}%{z%}, %1}" [(set_attr "type" "ssecvt") @@ -7013,7 +7015,7 @@ [(set (match_operand:V8HF 0 "register_operand" "=v") (vec_concat:V8HF (any_float:V2HF (match_operand:V2DI 1 "vector_operand" "vm")) - (match_operand:V6HF 2 "const0_operand" "C")))] + (match_operand:V6HF 2 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<floatsuffix>qq2ph{x}\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") @@ -7042,7 +7044,7 @@ (match_operand:V8HF 2 "nonimm_or_0_operand" "0C") (parallel [(const_int 0) (const_int 1)])) (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:V6HF 4 "const0_operand" "C")))] + (match_operand:V6HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<floatsuffix>qq2ph{x}\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}" [(set_attr "type" "ssecvt") @@ -7055,9 +7057,9 @@ (vec_merge:V2HF (any_float:V2HF (match_operand:V2DI 1 "vector_operand" "vm")) - (match_operand:V2HF 3 "const0_operand" "C") + (match_operand:V2HF 3 "const0_operand") (match_operand:QI 2 "register_operand" "Yk")) - (match_operand:V6HF 4 "const0_operand" "C")))] + (match_operand:V6HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<floatsuffix>qq2ph{x}\t{%1, %0%{%2%}%{z%}|%0%{%2%}%{z%}, %1}" [(set_attr "type" "ssecvt") @@ -7360,7 +7362,7 @@ (vec_concat:V8HF (float_truncate:V4HF (match_operand:VF4_128_8_256 1 "vector_operand" "vm")) - (match_operand:V4HF 2 "const0_operand" "C")))] + (match_operand:V4HF 2 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<castmode>2ph<ph2pssuffix><qq2phsuff>\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") @@ -7393,7 +7395,7 @@ (parallel [(const_int 0) (const_int 1) (const_int 2) (const_int 3)])) (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:V4HF 4 "const0_operand" "C")))] + (match_operand:V4HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<castmode>2ph<ph2pssuffix><qq2phsuff>\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}" [(set_attr "type" "ssecvt") @@ -7406,9 +7408,9 @@ (vec_merge:V4HF (float_truncate:V4HF (match_operand:VF4_128_8_256 1 "vector_operand" "vm")) - (match_operand:V4HF 3 "const0_operand" "C") + (match_operand:V4HF 3 "const0_operand") (match_operand:QI 2 "register_operand" "Yk")) - (match_operand:V4HF 4 "const0_operand" "C")))] + (match_operand:V4HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvt<castmode>2ph<ph2pssuffix><qq2phsuff>\t{%1, %0%{%2%}%{z%}|%0%{%2%}%{z%}, %1}" [(set_attr "type" "ssecvt") @@ -7439,7 +7441,7 @@ (vec_concat:V8HF (float_truncate:V2HF (match_operand:V2DF 1 "vector_operand" "vm")) - (match_operand:V6HF 2 "const0_operand" "C")))] + (match_operand:V6HF 2 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvtpd2ph{x}\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") @@ -7469,7 +7471,7 @@ (match_operand:V8HF 2 "nonimm_or_0_operand" "0C") (parallel [(const_int 0) (const_int 1)])) (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:V6HF 4 "const0_operand" "C")))] + (match_operand:V6HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvtpd2ph{x}\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}" [(set_attr "type" "ssecvt") @@ -7482,9 +7484,9 @@ (vec_merge:V2HF (float_truncate:V2HF (match_operand:V2DF 1 "vector_operand" "vm")) - (match_operand:V2HF 3 "const0_operand" "C") + (match_operand:V2HF 3 "const0_operand") (match_operand:QI 2 "register_operand" "Yk")) - (match_operand:V6HF 4 "const0_operand" "C")))] + (match_operand:V6HF 4 "const0_operand")))] "TARGET_AVX512FP16 && TARGET_AVX512VL" "vcvtpd2ph{x}\t{%1, %0%{%2%}%{z%}|%0%{%2%}%{z%}, %1}" [(set_attr "type" "ssecvt") @@ -8268,7 +8270,7 @@ [(set (match_operand:V4SF 0 "register_operand" "=v") (vec_concat:V4SF (any_float:V2SF (match_operand:V2DI 1 "nonimmediate_operand" "vm")) - (match_operand:V2SF 2 "const0_operand" "C")))] + (match_operand:V2SF 2 "const0_operand")))] "TARGET_AVX512DQ && TARGET_AVX512VL" "vcvt<floatsuffix>qq2ps{x}\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") @@ -8343,7 +8345,7 @@ (match_operand:V4SF 2 "nonimm_or_0_operand" "0C") (parallel [(const_int 0) (const_int 1)])) (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:V2SF 4 "const0_operand" "C")))] + (match_operand:V2SF 4 "const0_operand")))] "TARGET_AVX512DQ && TARGET_AVX512VL" "vcvt<floatsuffix>qq2ps{x}\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}" [(set_attr "type" "ssecvt") @@ -8356,9 +8358,9 @@ (vec_merge:V2SF (any_float:V2SF (match_operand:V2DI 1 "nonimmediate_operand" "vm")) - (match_operand:V2SF 3 "const0_operand" "C") + (match_operand:V2SF 3 "const0_operand") (match_operand:QI 2 "register_operand" "Yk")) - (match_operand:V2SF 4 "const0_operand" "C")))] + (match_operand:V2SF 4 "const0_operand")))] "TARGET_AVX512DQ && TARGET_AVX512VL" "vcvt<floatsuffix>qq2ps{x}\t{%1, %0%{%2%}%{z%}|%0%{%2%}%{z%}, %1}" [(set_attr "type" "ssecvt") @@ -8982,7 +8984,7 @@ (vec_concat:V4SF (float_truncate:V2SF (match_operand:V2DF 1 "vector_operand" "vBm")) - (match_operand:V2SF 2 "const0_operand" "C")))] + (match_operand:V2SF 2 "const0_operand")))] "TARGET_SSE2" { if (TARGET_AVX) @@ -9027,7 +9029,7 @@ (match_operand:V4SF 2 "nonimm_or_0_operand" "0C") (parallel [(const_int 0) (const_int 1)])) (match_operand:QI 3 "register_operand" "Yk")) - (match_operand:V2SF 4 "const0_operand" "C")))] + (match_operand:V2SF 4 "const0_operand")))] "TARGET_AVX512VL" "vcvtpd2ps{x}\t{%1, %0%{%3%}%N2|%0%{%3%}%N2, %1}" [(set_attr "type" "ssecvt") @@ -9040,9 +9042,9 @@ (vec_merge:V2SF (float_truncate:V2SF (match_operand:V2DF 1 "nonimmediate_operand" "vm")) - (match_operand:V2SF 3 "const0_operand" "C") + (match_operand:V2SF 3 "const0_operand") (match_operand:QI 2 "register_operand" "Yk")) - (match_operand:V2SF 4 "const0_operand" "C")))] + (match_operand:V2SF 4 "const0_operand")))] "TARGET_AVX512VL" "vcvtpd2ps{x}\t{%1, %0%{%2%}%{z%}|%0%{%2%}%{z%}, %1}" [(set_attr "type" "ssecvt") @@ -10577,7 +10579,7 @@ [(set (match_operand:V4SF 0 "register_operand" "=v") (vec_concat:V4SF (match_operand:V2SF 1 "nonimmediate_operand" "vm") - (match_operand:V2SF 2 "const0_operand" " C")))] + (match_operand:V2SF 2 "const0_operand")))] "TARGET_SSE2" "%vmovq\t{%1, %0|%0, %1}" [(set_attr "type" "ssemov") @@ -10735,7 +10737,7 @@ (vec_merge:VI2F_256_512 (vec_duplicate:VI2F_256_512 (match_operand:<ssescalarmode> 2 "nonimmediate_operand" "r,m")) - (match_operand:VI2F_256_512 1 "const0_operand" "C,C") + (match_operand:VI2F_256_512 1 "const0_operand") (const_int 1)))] "TARGET_AVX512FP16" "@ @@ -10835,7 +10837,7 @@ (vec_merge:VI4F_256_512 (vec_duplicate:VI4F_256_512 (match_operand:<ssescalarmode> 2 "nonimmediate_operand" "v,m,r")) - (match_operand:VI4F_256_512 1 "const0_operand" "C,C,C") + (match_operand:VI4F_256_512 1 "const0_operand") (const_int 1)))] "TARGET_AVX" "@ @@ -10898,7 +10900,7 @@ [(set (match_operand:V4SF 0 "register_operand" "=Yr,*x,v") (unspec:V4SF [(match_operand:V4SF 2 "nonimmediate_operand" "Yrm,*xm,vm") (match_operand:V4SF 1 "register_operand" "0,0,v") - (match_operand:SI 3 "const_0_to_255_operand" "n,n,n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_INSERTPS))] "TARGET_SSE4_1" { @@ -11015,7 +11017,7 @@ [(set (match_operand:SF 0 "nonimmediate_operand" "=rm,rm,rm,Yv,Yv") (vec_select:SF (match_operand:V4SF 1 "register_operand" "Yr,*x,v,0,v") - (parallel [(match_operand:SI 2 "const_0_to_3_operand" "n,n,n,n,n")])))] + (parallel [(match_operand:SI 2 "const_0_to_3_operand")])))] "TARGET_SSE4_1" "@ extractps\t{%2, %1, %0|%0, %1, %2} @@ -11057,7 +11059,7 @@ [(set (match_operand:SF 0 "register_operand" "=v,*r,f") (vec_select:SF (match_operand:V4SF 1 "memory_operand" "o,o,o") - (parallel [(match_operand 2 "const_0_to_3_operand" "n,n,n")])))] + (parallel [(match_operand 2 "const_0_to_3_operand")])))] "TARGET_SSE" "#" "&& reload_completed" @@ -13540,7 +13542,7 @@ (vec_merge:VF2_512_256 (vec_duplicate:VF2_512_256 (match_operand:<ssescalarmode> 2 "nonimmediate_operand" "vm")) - (match_operand:VF2_512_256 1 "const0_operand" "C") + (match_operand:VF2_512_256 1 "const0_operand") (const_int 1)))] "TARGET_AVX" "vmovq\t{%2, %x0|%x0, %2}" @@ -16028,7 +16030,7 @@ [(set (match_operand:VIMAX_AVX512VL 0 "register_operand" "=v") (any_lshift:VIMAX_AVX512VL (match_operand:VIMAX_AVX512VL 1 "nonimmediate_operand" "vm") - (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n")))] + (match_operand:SI 2 "const_0_to_255_mul_8_operand")))] "TARGET_AVX512BW" { operands[2] = GEN_INT (INTVAL (operands[2]) / 8); @@ -16043,7 +16045,7 @@ [(set (match_operand:VIMAX_AVX2 0 "register_operand" "=x,Yw") (any_lshift:VIMAX_AVX2 (match_operand:VIMAX_AVX2 1 "register_operand" "0,Yw") - (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n,n")))] + (match_operand:SI 2 "const_0_to_255_mul_8_operand")))] "TARGET_SSE2" { operands[2] = GEN_INT (INTVAL (operands[2]) / 8); @@ -18102,7 +18104,7 @@ (match_operand:AVX512_VEC 1 "reg_or_0_operand" "v,C,C") (vec_duplicate:AVX512_VEC (match_operand:<ssequartermode> 2 "nonimmediate_operand" "vm,xm,vm")) - (match_operand:SI 3 "const_int_operand" "n,n,n")))] + (match_operand:SI 3 "const_int_operand")))] "TARGET_AVX512F && (INTVAL (operands[3]) == (GET_MODE_UNIT_SIZE (<MODE>mode) == 4 ? 0xFFF0 : 0xFC))" @@ -18150,7 +18152,7 @@ (match_operand:AVX512_VEC 1 "register_operand" "v") (vec_duplicate:AVX512_VEC (match_operand:<ssequartermode> 2 "nonimmediate_operand" "vm")) - (match_operand:SI 3 "const_int_operand" "n")))] + (match_operand:SI 3 "const_int_operand")))] "TARGET_AVX512F" { int mask; @@ -18818,7 +18820,7 @@ [(set (match_operand:V32HI 0 "register_operand" "=v") (unspec:V32HI [(match_operand:V32HI 1 "nonimmediate_operand" "vm") - (match_operand:SI 2 "const_0_to_255_operand" "n")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_PSHUFLW))] "TARGET_AVX512BW" "vpshuflw\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}" @@ -18994,7 +18996,7 @@ [(set (match_operand:V32HI 0 "register_operand" "=v") (unspec:V32HI [(match_operand:V32HI 1 "nonimmediate_operand" "vm") - (match_operand:SI 2 "const_0_to_255_operand" "n")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_PSHUFHW))] "TARGET_AVX512BW" "vpshufhw\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}" @@ -19726,7 +19728,7 @@ [(set (match_operand:VI124_128 0 "register_operand" "=v,x") (vec_concat:VI124_128 (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm,?!*y") - (match_operand:<ssehalfvecmode> 2 "const0_operand" " C,C")))] + (match_operand:<ssehalfvecmode> 2 "const0_operand")))] "TARGET_SSE2" "@ %vmovq\t{%1, %0|%0, %1} @@ -19800,7 +19802,7 @@ [(set (match_operand:V2DI 0 "register_operand" "=v,v ,x") (vec_concat:V2DI (match_operand:DI 1 "nonimmediate_operand" " r,vm,?!*y") - (match_operand:DI 2 "const0_operand" " C,C ,C")))] + (match_operand:DI 2 "const0_operand")))] "TARGET_SSE2" "@ * return HAVE_AS_IX86_INTERUNIT_MOVQ ? \"%vmovq\t{%1, %0|%0, %1}\" : \"%vmovd\t{%1, %0|%0, %1}\"; @@ -19824,7 +19826,7 @@ (vec_merge:VI8_AVX_AVX512F (vec_duplicate:VI8_AVX_AVX512F (match_operand:<ssescalarmode> 2 "nonimmediate_operand" "r,vm")) - (match_operand:VI8_AVX_AVX512F 1 "const0_operand" "C,C") + (match_operand:VI8_AVX_AVX512F 1 "const0_operand") (const_int 1)))] "TARGET_AVX" "vmovq\t{%2, %x0|%x0, %2}" @@ -19980,13 +19982,23 @@ ;; The correct representation for this is absolutely enormous, and ;; surely not generally useful. -(define_insn "<sse2_avx2>_psadbw" +(define_expand "<sse2_avx2>_psadbw" + [(set (match_operand:VI8_AVX2_AVX512BW 0 "register_operand") + (unspec:VI8_AVX2_AVX512BW + [(match_operand:<ssebytemode> 1 "vector_operand") + (match_operand:<ssebytemode> 2 "vector_operand")] + UNSPEC_PSADBW))] + "TARGET_SSE2" + "ix86_fixup_binary_operands_no_copy (PLUS, <ssebytemode>mode, operands);") + +(define_insn "*<sse2_avx2>_psadbw" [(set (match_operand:VI8_AVX2_AVX512BW 0 "register_operand" "=x,YW") (unspec:VI8_AVX2_AVX512BW - [(match_operand:<ssebytemode> 1 "register_operand" "0,YW") + [(match_operand:<ssebytemode> 1 "vector_operand" "%0,YW") (match_operand:<ssebytemode> 2 "vector_operand" "xBm,YWm")] UNSPEC_PSADBW))] - "TARGET_SSE2" + "TARGET_SSE2 + && ix86_binary_operator_ok (PLUS, <ssebytemode>mode, operands)" "@ psadbw\t{%2, %0|%0, %2} vpsadbw\t{%2, %1, %0|%0, %1, %2}" @@ -20025,7 +20037,7 @@ (unspec:SI [(lt:VF_128_256 (match_operand:<sseintvecmode> 1 "register_operand" "x") - (match_operand:<sseintvecmode> 2 "const0_operand" "C"))] + (match_operand:<sseintvecmode> 2 "const0_operand"))] UNSPEC_MOVMSK))] "TARGET_SSE" "#" @@ -20043,7 +20055,7 @@ (unspec:SI [(lt:VF_128_256 (match_operand:<sseintvecmode> 1 "register_operand" "x") - (match_operand:<sseintvecmode> 2 "const0_operand" "C"))] + (match_operand:<sseintvecmode> 2 "const0_operand"))] UNSPEC_MOVMSK)))] "TARGET_64BIT && TARGET_SSE" "#" @@ -20061,7 +20073,7 @@ [(subreg:VF_128_256 (ashiftrt:<sseintvecmode> (match_operand:<sseintvecmode> 1 "register_operand" "x") - (match_operand:QI 2 "const_int_operand" "n")) 0)] + (match_operand:QI 2 "const_int_operand")) 0)] UNSPEC_MOVMSK))] "TARGET_SSE" "#" @@ -20080,7 +20092,7 @@ [(subreg:VF_128_256 (ashiftrt:<sseintvecmode> (match_operand:<sseintvecmode> 1 "register_operand" "x") - (match_operand:QI 2 "const_int_operand" "n")) 0)] + (match_operand:QI 2 "const_int_operand")) 0)] UNSPEC_MOVMSK)))] "TARGET_64BIT && TARGET_SSE" "#" @@ -20221,7 +20233,7 @@ [(set (match_operand:SI 0 "register_operand" "=r") (unspec:SI [(lt:VI1_AVX2 (match_operand:VI1_AVX2 1 "register_operand" "x") - (match_operand:VI1_AVX2 2 "const0_operand" "C"))] + (match_operand:VI1_AVX2 2 "const0_operand"))] UNSPEC_MOVMSK))] "TARGET_SSE2" "#" @@ -20243,7 +20255,7 @@ (zero_extend:DI (unspec:SI [(lt:VI1_AVX2 (match_operand:VI1_AVX2 1 "register_operand" "x") - (match_operand:VI1_AVX2 2 "const0_operand" "C"))] + (match_operand:VI1_AVX2 2 "const0_operand"))] UNSPEC_MOVMSK)))] "TARGET_64BIT && TARGET_SSE2" "#" @@ -20265,7 +20277,7 @@ (sign_extend:DI (unspec:SI [(lt:V16QI (match_operand:V16QI 1 "register_operand" "x") - (match_operand:V16QI 2 "const0_operand" "C"))] + (match_operand:V16QI 2 "const0_operand"))] UNSPEC_MOVMSK)))] "TARGET_64BIT && TARGET_SSE2" "#" @@ -21064,7 +21076,7 @@ (unspec:VI1_AVX512 [(match_operand:VI1_AVX512 1 "register_operand" "v") (match_operand:VI1_AVX512 2 "nonimmediate_operand" "vm") - (match_operand:SI 3 "const_0_to_255_mul_8_operand" "n")] + (match_operand:SI 3 "const_0_to_255_mul_8_operand")] UNSPEC_PALIGNR) (match_operand:VI1_AVX512 4 "nonimm_or_0_operand" "0C") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] @@ -21085,7 +21097,7 @@ (unspec:SSESCALARMODE [(match_operand:SSESCALARMODE 1 "register_operand" "0,<v_Yw>") (match_operand:SSESCALARMODE 2 "vector_operand" "xBm,<v_Yw>m") - (match_operand:SI 3 "const_0_to_255_mul_8_operand" "n,n")] + (match_operand:SI 3 "const_0_to_255_mul_8_operand")] UNSPEC_PALIGNR))] "TARGET_SSSE3" { @@ -21114,7 +21126,7 @@ [(set (match_operand:DI 0 "register_operand" "=y,x,Yv") (unspec:DI [(match_operand:DI 1 "register_operand" "0,0,Yv") (match_operand:DI 2 "register_mmxmem_operand" "ym,x,Yv") - (match_operand:SI 3 "const_0_to_255_mul_8_operand" "n,n,n")] + (match_operand:SI 3 "const_0_to_255_mul_8_operand")] UNSPEC_PALIGNR))] "(TARGET_MMX || TARGET_MMX_WITH_SSE) && TARGET_SSSE3" { @@ -21401,7 +21413,7 @@ (match_operand:VF_128_256 2 "vector_operand" "YrBm,*xBm,xm") (lt:VF_128_256 (match_operand:<sseintvecmode> 3 "register_operand" "Yz,Yz,x") - (match_operand:<sseintvecmode> 4 "const0_operand" "C,C,C"))] + (match_operand:<sseintvecmode> 4 "const0_operand"))] UNSPEC_BLENDV))] "TARGET_SSE4_1" "#" @@ -21433,7 +21445,7 @@ (subreg:<ssebytemode> (lt:VI48_AVX (match_operand:VI48_AVX 3 "register_operand" "Yz,Yz,x") - (match_operand:VI48_AVX 4 "const0_operand" "C,C,C")) 0)] + (match_operand:VI48_AVX 4 "const0_operand")) 0)] UNSPEC_BLENDV))] "TARGET_SSE4_1" "#" @@ -21488,7 +21500,7 @@ (unspec:VF_128_256 [(match_operand:VF_128_256 1 "vector_operand" "%0,0,x") (match_operand:VF_128_256 2 "vector_operand" "YrBm,*xBm,xm") - (match_operand:SI 3 "const_0_to_255_operand" "n,n,n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_DP))] "TARGET_SSE4_1" "@ @@ -21526,7 +21538,7 @@ (unspec:VI1_AVX2 [(match_operand:VI1_AVX2 1 "register_operand" "0,0,x") (match_operand:VI1_AVX2 2 "vector_operand" "YrBm,*xBm,xm") - (match_operand:SI 3 "const_0_to_255_operand" "n,n,n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_MPSADBW))] "TARGET_SSE4_1" "@ @@ -21615,7 +21627,7 @@ [(match_operand:VI1_AVX2 1 "register_operand" "0,0,x") (match_operand:VI1_AVX2 2 "vector_operand" "YrBm,*xBm,xm") (lt:VI1_AVX2 (match_operand:VI1_AVX2 3 "register_operand" "Yz,Yz,x") - (match_operand:VI1_AVX2 4 "const0_operand" "C,C,C"))] + (match_operand:VI1_AVX2 4 "const0_operand"))] UNSPEC_BLENDV))] "TARGET_SSE4_1" "#" @@ -21659,7 +21671,7 @@ (vec_merge:V8_128 (match_operand:V8_128 2 "vector_operand" "YrBm,*xBm,xm") (match_operand:V8_128 1 "register_operand" "0,0,x") - (match_operand:SI 3 "const_0_to_255_operand" "n,n,n")))] + (match_operand:SI 3 "const_0_to_255_operand")))] "TARGET_SSE4_1" "@ pblendw\t{%3, %2, %0|%0, %2, %3} @@ -21731,7 +21743,7 @@ (vec_merge:V16_256 (match_operand:V16_256 2 "nonimmediate_operand" "xm") (match_operand:V16_256 1 "register_operand" "x") - (match_operand:SI 3 "avx2_pblendw_operand" "n")))] + (match_operand:SI 3 "avx2_pblendw_operand")))] "TARGET_AVX2" { operands[3] = GEN_INT (INTVAL (operands[3]) & 0xff); @@ -21748,7 +21760,7 @@ (vec_merge:VI4_AVX2 (match_operand:VI4_AVX2 2 "nonimmediate_operand" "xm") (match_operand:VI4_AVX2 1 "register_operand" "x") - (match_operand:SI 3 "const_0_to_255_operand" "n")))] + (match_operand:SI 3 "const_0_to_255_operand")))] "TARGET_AVX2" "vpblendd\t{%3, %2, %1, %0|%0, %1, %2, %3}" [(set_attr "type" "ssemov") @@ -21785,9 +21797,9 @@ (vec_select:V32QI (vec_concat:V64QI (match_operand:V32QI 1 "nonimmediate_operand" "vm") - (match_operand:V32QI 2 "const0_operand" "C")) + (match_operand:V32QI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_AVX2" "#" "&& reload_completed" @@ -21804,10 +21816,10 @@ (subreg:V32QI (vec_concat:VI248_256 (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") - (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) - (match_operand:V32QI 3 "const0_operand" "C")) + (match_operand:<ssehalfvecmode> 2 "const0_operand")) 0) + (match_operand:V32QI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_AVX2" "#" "&& reload_completed" @@ -21839,9 +21851,9 @@ (vec_select:V64QI (vec_concat:V128QI (match_operand:V64QI 1 "nonimmediate_operand" "vm") - (match_operand:V64QI 2 "const0_operand" "C")) + (match_operand:V64QI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_AVX512BW" "#" "&& reload_completed" @@ -21858,10 +21870,10 @@ (subreg:V64QI (vec_concat:VI248_512 (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") - (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) - (match_operand:V64QI 3 "const0_operand" "C")) + (match_operand:<ssehalfvecmode> 2 "const0_operand")) 0) + (match_operand:V64QI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_AVX512BW" "#" "&& reload_completed" @@ -21931,9 +21943,9 @@ (vec_select:V16QI (vec_concat:V32QI (match_operand:V16QI 1 "vector_operand" "YrBm,*xBm,Ywm") - (match_operand:V16QI 2 "const0_operand" "C,C,C")) + (match_operand:V16QI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n,n,n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_SSE4_1" "#" "&& reload_completed" @@ -21964,10 +21976,10 @@ (subreg:V16QI (vec_concat:VI248_128 (match_operand:<ssehalfvecmode> 1 "vector_operand" "YrBm,*xBm,Ywm") - (match_operand:<ssehalfvecmode> 2 "const0_operand" "C,C,C")) 0) - (match_operand:V16QI 3 "const0_operand" "C,C,C")) + (match_operand:<ssehalfvecmode> 2 "const0_operand")) 0) + (match_operand:V16QI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n,n,n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_SSE4_1" "#" "&& reload_completed" @@ -22170,9 +22182,9 @@ (vec_select:V32HI (vec_concat:V64HI (match_operand:V32HI 1 "nonimmediate_operand" "vm") - (match_operand:V32HI 2 "const0_operand" "C")) + (match_operand:V32HI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_AVX512F" "#" "&& reload_completed" @@ -22189,10 +22201,10 @@ (subreg:V32HI (vec_concat:VI148_512 (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") - (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) - (match_operand:V32HI 3 "const0_operand" "C")) + (match_operand:<ssehalfvecmode> 2 "const0_operand")) 0) + (match_operand:V32HI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_AVX512F" "#" "&& reload_completed" @@ -22224,9 +22236,9 @@ (vec_select:V16HI (vec_concat:V32HI (match_operand:V16HI 1 "nonimmediate_operand" "vm") - (match_operand:V16HI 2 "const0_operand" "C")) + (match_operand:V16HI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_AVX2" "#" "&& reload_completed" @@ -22243,10 +22255,10 @@ (subreg:V16HI (vec_concat:VI148_256 (match_operand:<ssehalfvecmode> 1 "nonimmediate_operand" "vm") - (match_operand:<ssehalfvecmode> 2 "const0_operand" "C")) 0) - (match_operand:V16HI 3 "const0_operand" "C")) + (match_operand:<ssehalfvecmode> 2 "const0_operand")) 0) + (match_operand:V16HI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_AVX2" "#" "&& reload_completed" @@ -22322,9 +22334,9 @@ (vec_select:V8HI (vec_concat:V16HI (match_operand:V8HI 1 "vector_operand" "YrBm,*xBm,vm") - (match_operand:V8HI 2 "const0_operand" "C,C,C")) + (match_operand:V8HI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n,n,n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_SSE4_1" "#" "&& reload_completed" @@ -22353,10 +22365,10 @@ (subreg:V8HI (vec_concat:VI148_128 (match_operand:<ssehalfvecmode> 1 "vector_operand" "YrBm,*xBm,vm") - (match_operand:<ssehalfvecmode> 2 "const0_operand" "C,C,C")) 0) - (match_operand:V8HI 3 "const0_operand" "C,C,C")) + (match_operand:<ssehalfvecmode> 2 "const0_operand")) 0) + (match_operand:V8HI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n,n,n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_SSE4_1" "#" "&& reload_completed" @@ -22714,9 +22726,9 @@ (vec_select:V16SI (vec_concat:V32SI (match_operand:V16SI 1 "nonimmediate_operand" "vm") - (match_operand:V16SI 2 "const0_operand" "C")) + (match_operand:V16SI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_AVX512F" "#" "&& reload_completed" @@ -22732,10 +22744,10 @@ (vec_concat:V32SI (vec_concat:V16SI (match_operand:V8SI 1 "nonimmediate_operand" "vm") - (match_operand:V8SI 2 "const0_operand" "C")) - (match_operand:V16SI 3 "const0_operand" "C")) + (match_operand:V8SI 2 "const0_operand")) + (match_operand:V16SI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_AVX512F" "#" "&& reload_completed" @@ -22766,9 +22778,9 @@ (vec_select:V8SI (vec_concat:V16SI (match_operand:V8SI 1 "nonimmediate_operand" "vm") - (match_operand:V8SI 2 "const0_operand" "C")) + (match_operand:V8SI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_AVX2" "#" "&& reload_completed" @@ -22784,10 +22796,10 @@ (vec_concat:V16SI (vec_concat:V8SI (match_operand:V4SI 1 "nonimmediate_operand" "vm") - (match_operand:V4SI 2 "const0_operand" "C")) - (match_operand:V8SI 3 "const0_operand" "C")) + (match_operand:V4SI 2 "const0_operand")) + (match_operand:V8SI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_AVX2" "#" "&& reload_completed" @@ -22850,9 +22862,9 @@ (vec_select:V4SI (vec_concat:V8SI (match_operand:V4SI 1 "vector_operand" "YrBm,*xBm,vm") - (match_operand:V4SI 2 "const0_operand" "C,C,C")) + (match_operand:V4SI 2 "const0_operand")) (match_parallel 3 "pmovzx_parallel" - [(match_operand 4 "const_int_operand" "n,n,n")])))] + [(match_operand 4 "const_int_operand")])))] "TARGET_SSE4_1" "#" "&& reload_completed" @@ -22878,10 +22890,10 @@ (vec_concat:V8SI (vec_concat:V4SI (match_operand:V2SI 1 "vector_operand" "YrBm, *xBm, vm") - (match_operand:V2SI 2 "const0_operand" "C,C,C")) - (match_operand:V4SI 3 "const0_operand" "C,C,C")) + (match_operand:V2SI 2 "const0_operand")) + (match_operand:V4SI 3 "const0_operand")) (match_parallel 4 "pmovzx_parallel" - [(match_operand 5 "const_int_operand" "n,n,n")])))] + [(match_operand 5 "const_int_operand")])))] "TARGET_SSE4_1" "#" "&& reload_completed" @@ -22985,7 +22997,7 @@ [(set (match_operand:VF_128_256 0 "register_operand" "=Yr,*x,x") (unspec:VF_128_256 [(match_operand:VF_128_256 1 "vector_operand" "YrBm,*xBm,xm") - (match_operand:SI 2 "const_0_to_15_operand" "n,n,n")] + (match_operand:SI 2 "const_0_to_15_operand")] UNSPEC_ROUND))] "TARGET_SSE4_1" "%vround<ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}" @@ -23078,7 +23090,7 @@ (vec_merge:VF_128 (unspec:VF_128 [(match_operand:VF_128 2 "nonimmediate_operand" "Yrm,*xm,xm,vm") - (match_operand:SI 3 "const_0_to_15_operand" "n,n,n,n")] + (match_operand:SI 3 "const_0_to_15_operand")] UNSPEC_ROUND) (match_operand:VF_128 1 "register_operand" "0,0,x,v") (const_int 1)))] @@ -23102,7 +23114,7 @@ (vec_duplicate:VFH_128 (unspec:<ssescalarmode> [(match_operand:<ssescalarmode> 2 "nonimmediate_operand" "Yrm,*xm,xm,vm") - (match_operand:SI 3 "const_0_to_15_operand" "n,n,n,n")] + (match_operand:SI 3 "const_0_to_15_operand")] UNSPEC_ROUND)) (match_operand:VFH_128 1 "register_operand" "0,0,x,v") (const_int 1)))] @@ -23215,7 +23227,7 @@ (match_operand:SI 3 "register_operand" "a,a") (match_operand:V16QI 4 "nonimmediate_operand" "x,m") (match_operand:SI 5 "register_operand" "d,d") - (match_operand:SI 6 "const_0_to_255_operand" "n,n")] + (match_operand:SI 6 "const_0_to_255_operand")] UNSPEC_PCMPESTR)) (set (match_operand:V16QI 1 "register_operand" "=Yz,Yz") (unspec:V16QI @@ -23275,7 +23287,7 @@ (match_operand:SI 2 "register_operand" "a,a") (match_operand:V16QI 3 "nonimmediate_operand" "x,m") (match_operand:SI 4 "register_operand" "d,d") - (match_operand:SI 5 "const_0_to_255_operand" "n,n")] + (match_operand:SI 5 "const_0_to_255_operand")] UNSPEC_PCMPESTR)) (set (reg:CC FLAGS_REG) (unspec:CC @@ -23303,7 +23315,7 @@ (match_operand:SI 2 "register_operand" "a,a") (match_operand:V16QI 3 "nonimmediate_operand" "x,m") (match_operand:SI 4 "register_operand" "d,d") - (match_operand:SI 5 "const_0_to_255_operand" "n,n")] + (match_operand:SI 5 "const_0_to_255_operand")] UNSPEC_PCMPESTR)) (set (reg:CC FLAGS_REG) (unspec:CC @@ -23331,7 +23343,7 @@ (match_operand:SI 3 "register_operand" "a,a,a,a") (match_operand:V16QI 4 "nonimmediate_operand" "x,m,x,m") (match_operand:SI 5 "register_operand" "d,d,d,d") - (match_operand:SI 6 "const_0_to_255_operand" "n,n,n,n")] + (match_operand:SI 6 "const_0_to_255_operand")] UNSPEC_PCMPESTR)) (clobber (match_scratch:V16QI 0 "=Yz,Yz,X,X")) (clobber (match_scratch:SI 1 "= X, X,c,c"))] @@ -23355,7 +23367,7 @@ (unspec:SI [(match_operand:V16QI 2 "register_operand" "x,x") (match_operand:V16QI 3 "nonimmediate_operand" "x,m") - (match_operand:SI 4 "const_0_to_255_operand" "n,n")] + (match_operand:SI 4 "const_0_to_255_operand")] UNSPEC_PCMPISTR)) (set (match_operand:V16QI 1 "register_operand" "=Yz,Yz") (unspec:V16QI @@ -23406,7 +23418,7 @@ (unspec:SI [(match_operand:V16QI 1 "register_operand" "x,x") (match_operand:V16QI 2 "nonimmediate_operand" "x,m") - (match_operand:SI 3 "const_0_to_255_operand" "n,n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_PCMPISTR)) (set (reg:CC FLAGS_REG) (unspec:CC @@ -23430,7 +23442,7 @@ (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "x,x") (match_operand:V16QI 2 "nonimmediate_operand" "x,m") - (match_operand:SI 3 "const_0_to_255_operand" "n,n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_PCMPISTR)) (set (reg:CC FLAGS_REG) (unspec:CC @@ -23454,7 +23466,7 @@ (unspec:CC [(match_operand:V16QI 2 "register_operand" "x,x,x,x") (match_operand:V16QI 3 "nonimmediate_operand" "x,m,x,m") - (match_operand:SI 4 "const_0_to_255_operand" "n,n,n,n")] + (match_operand:SI 4 "const_0_to_255_operand")] UNSPEC_PCMPISTR)) (clobber (match_scratch:V16QI 0 "=Yz,Yz,X,X")) (clobber (match_scratch:SI 1 "= X, X,c,c"))] @@ -23501,9 +23513,9 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:VI48_512 1 "register_operand" "v") - (match_operand:SI 3 "const1248_operand" "n")] + (match_operand:SI 3 "const1248_operand")] UNSPEC_VSIBADDR)]) - (match_operand:SI 4 "const_2_to_3_operand" "n")] + (match_operand:SI 4 "const_2_to_3_operand")] UNSPEC_GATHER_PREFETCH)] "TARGET_AVX512PF" { @@ -23548,9 +23560,9 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:VI4_256_8_512 1 "register_operand" "v") - (match_operand:SI 3 "const1248_operand" "n")] + (match_operand:SI 3 "const1248_operand")] UNSPEC_VSIBADDR)]) - (match_operand:SI 4 "const_2_to_3_operand" "n")] + (match_operand:SI 4 "const_2_to_3_operand")] UNSPEC_GATHER_PREFETCH)] "TARGET_AVX512PF" { @@ -23595,9 +23607,9 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:VI48_512 1 "register_operand" "v") - (match_operand:SI 3 "const1248_operand" "n")] + (match_operand:SI 3 "const1248_operand")] UNSPEC_VSIBADDR)]) - (match_operand:SI 4 "const2367_operand" "n")] + (match_operand:SI 4 "const2367_operand")] UNSPEC_SCATTER_PREFETCH)] "TARGET_AVX512PF" { @@ -23644,9 +23656,9 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:VI4_256_8_512 1 "register_operand" "v") - (match_operand:SI 3 "const1248_operand" "n")] + (match_operand:SI 3 "const1248_operand")] UNSPEC_VSIBADDR)]) - (match_operand:SI 4 "const2367_operand" "n")] + (match_operand:SI 4 "const2367_operand")] UNSPEC_SCATTER_PREFETCH)] "TARGET_AVX512PF" { @@ -24184,7 +24196,7 @@ [(set (match_operand:VI_128 0 "register_operand" "=x") (rotate:VI_128 (match_operand:VI_128 1 "nonimmediate_operand" "xm") - (match_operand:SI 2 "const_0_to_<sserotatemax>_operand" "n")))] + (match_operand:SI 2 "const_0_to_<sserotatemax>_operand")))] "TARGET_XOP" "vprot<ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "sseishft") @@ -24195,7 +24207,7 @@ [(set (match_operand:VI_128 0 "register_operand" "=x") (rotatert:VI_128 (match_operand:VI_128 1 "nonimmediate_operand" "xm") - (match_operand:SI 2 "const_0_to_<sserotatemax>_operand" "n")))] + (match_operand:SI 2 "const_0_to_<sserotatemax>_operand")))] "TARGET_XOP" { operands[3] @@ -24802,7 +24814,7 @@ (unspec:VI_128 [(match_operand:VI_128 1 "register_operand" "x") (match_operand:VI_128 2 "nonimmediate_operand" "xm") - (match_operand:SI 3 "const_int_operand" "n")] + (match_operand:SI 3 "const_int_operand")] UNSPEC_XOP_TRUEFALSE))] "TARGET_XOP" { @@ -24822,7 +24834,7 @@ [(match_operand:VF_128_256 1 "register_operand" "x,x") (match_operand:VF_128_256 2 "nonimmediate_operand" "x,m") (match_operand:<sseintvecmode> 3 "nonimmediate_operand" "xm,x") - (match_operand:SI 4 "const_0_to_3_operand" "n,n")] + (match_operand:SI 4 "const_0_to_3_operand")] UNSPEC_VPERMIL2))] "TARGET_XOP" "vpermil2<ssemodesuffix>\t{%4, %3, %2, %1, %0|%0, %1, %2, %3, %4}" @@ -24910,7 +24922,7 @@ (define_insn "aeskeygenassist" [(set (match_operand:V2DI 0 "register_operand" "=x") (unspec:V2DI [(match_operand:V2DI 1 "vector_operand" "xBm") - (match_operand:SI 2 "const_0_to_255_operand" "n")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_AESKEYGENASSIST))] "TARGET_AES" "%vaeskeygenassist\t{%2, %1, %0|%0, %1, %2}" @@ -24924,7 +24936,7 @@ [(set (match_operand:V2DI 0 "register_operand" "=x,x") (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "0,x") (match_operand:V2DI 2 "vector_operand" "xBm,xm") - (match_operand:SI 3 "const_0_to_255_operand" "n,n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_PCLMUL))] "TARGET_PCLMUL" "@ @@ -25376,7 +25388,7 @@ (unspec:V4DI [(match_operand:V4DI 1 "register_operand" "x") (match_operand:V4DI 2 "nonimmediate_operand" "xm") - (match_operand:SI 3 "const_0_to_255_operand" "n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_VPERMTI))] "TARGET_AVX2" "vperm2i128\t{%3, %2, %1, %0|%0, %1, %2, %3}" @@ -25920,7 +25932,7 @@ (unspec:AVX256MODE2P [(match_operand:AVX256MODE2P 1 "register_operand" "x") (match_operand:AVX256MODE2P 2 "nonimmediate_operand" "xm") - (match_operand:SI 3 "const_0_to_255_operand" "n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_VPERMIL2F128))] "TARGET_AVX" "vperm2<i128>\t{%3, %2, %1, %0|%0, %1, %2, %3}" @@ -25960,7 +25972,7 @@ (vec_select:V_128 (match_operand:V_128 1 "register_operand" "0,Yw") (match_parallel 2 "palignr_operand" - [(match_operand 3 "const_int_operand" "n,n")])))] + [(match_operand 3 "const_int_operand")])))] "TARGET_SSSE3" { operands[2] = (GEN_INT (INTVAL (operands[3]) @@ -26630,7 +26642,7 @@ [(set (match_operand:V8HI 0 "register_operand" "=v") (vec_concat:V8HI (unspec:V4HI [(match_operand:V4SF 1 "register_operand" "v") - (match_operand:SI 2 "const_0_to_255_operand" "N")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_VCVTPS2PH) (match_operand:V4HI 3 "const0_operand")))] "(TARGET_F16C || TARGET_AVX512VL) && <mask_avx512vl_condition>" @@ -26642,7 +26654,7 @@ (define_insn "*vcvtps2ph_store<merge_mask_name>" [(set (match_operand:V4HI 0 "memory_operand" "=m") (unspec:V4HI [(match_operand:V4SF 1 "register_operand" "v") - (match_operand:SI 2 "const_0_to_255_operand" "N")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_VCVTPS2PH))] "TARGET_F16C || TARGET_AVX512VL" "vcvtps2ph\t{%2, %1, %0<merge_mask_operand3>|%0<merge_mask_operand3>, %1, %2}" @@ -26653,7 +26665,7 @@ (define_insn "vcvtps2ph256<mask_name>" [(set (match_operand:V8HI 0 "register_operand" "=v") (unspec:V8HI [(match_operand:V8SF 1 "register_operand" "v") - (match_operand:SI 2 "const_0_to_255_operand" "N")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_VCVTPS2PH))] "TARGET_F16C || TARGET_AVX512VL" "vcvtps2ph\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}" @@ -26665,7 +26677,7 @@ (define_insn "*vcvtps2ph256<merge_mask_name>" [(set (match_operand:V8HI 0 "memory_operand" "=m") (unspec:V8HI [(match_operand:V8SF 1 "register_operand" "v") - (match_operand:SI 2 "const_0_to_255_operand" "N")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_VCVTPS2PH))] "TARGET_F16C || TARGET_AVX512VL" "vcvtps2ph\t{%2, %1, %0<merge_mask_operand3>|%0<merge_mask_operand3>, %1, %2}" @@ -26678,7 +26690,7 @@ [(set (match_operand:V16HI 0 "register_operand" "=v") (unspec:V16HI [(match_operand:V16SF 1 "register_operand" "v") - (match_operand:SI 2 "const_0_to_255_operand" "N")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_VCVTPS2PH))] "TARGET_AVX512F" "vcvtps2ph\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}" @@ -26690,7 +26702,7 @@ [(set (match_operand:V16HI 0 "memory_operand" "=m") (unspec:V16HI [(match_operand:V16SF 1 "register_operand" "v") - (match_operand:SI 2 "const_0_to_255_operand" "N")] + (match_operand:SI 2 "const_0_to_255_operand")] UNSPEC_VCVTPS2PH))] "TARGET_AVX512F" "vcvtps2ph\t{%2, %1, %0<merge_mask_operand3>|%0<merge_mask_operand3>, %1, %2}" @@ -26748,7 +26760,7 @@ [(unspec:P [(match_operand:P 3 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXSI> 4 "register_operand" "x") - (match_operand:SI 6 "const1248_operand" "n")] + (match_operand:SI 6 "const1248_operand")] UNSPEC_VSIBADDR)]) (mem:BLK (scratch)) (match_operand:VEC_GATHER_MODE 5 "register_operand" "1")] @@ -26768,7 +26780,7 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXSI> 3 "register_operand" "x") - (match_operand:SI 5 "const1248_operand" "n")] + (match_operand:SI 5 "const1248_operand")] UNSPEC_VSIBADDR)]) (mem:BLK (scratch)) (match_operand:VEC_GATHER_MODE 4 "register_operand" "1")] @@ -26809,7 +26821,7 @@ [(unspec:P [(match_operand:P 3 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 4 "register_operand" "x") - (match_operand:SI 6 "const1248_operand" "n")] + (match_operand:SI 6 "const1248_operand")] UNSPEC_VSIBADDR)]) (mem:BLK (scratch)) (match_operand:<VEC_GATHER_SRCDI> 5 "register_operand" "1")] @@ -26829,7 +26841,7 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 3 "register_operand" "x") - (match_operand:SI 5 "const1248_operand" "n")] + (match_operand:SI 5 "const1248_operand")] UNSPEC_VSIBADDR)]) (mem:BLK (scratch)) (match_operand:<VEC_GATHER_SRCDI> 4 "register_operand" "1")] @@ -26854,7 +26866,7 @@ [(unspec:P [(match_operand:P 3 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 4 "register_operand" "x") - (match_operand:SI 6 "const1248_operand" "n")] + (match_operand:SI 6 "const1248_operand")] UNSPEC_VSIBADDR)]) (mem:BLK (scratch)) (match_operand:<VEC_GATHER_SRCDI> 5 "register_operand" "1")] @@ -26877,7 +26889,7 @@ [(unspec:P [(match_operand:P 2 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 3 "register_operand" "x") - (match_operand:SI 5 "const1248_operand" "n")] + (match_operand:SI 5 "const1248_operand")] UNSPEC_VSIBADDR)]) (mem:BLK (scratch)) (match_operand:<VEC_GATHER_SRCDI> 4 "register_operand" "1")] @@ -26919,7 +26931,7 @@ [(unspec:P [(match_operand:P 4 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXSI> 3 "register_operand" "v") - (match_operand:SI 5 "const1248_operand" "n")] + (match_operand:SI 5 "const1248_operand")] UNSPEC_VSIBADDR)])] UNSPEC_GATHER)) (clobber (match_scratch:<avx512fmaskmode> 2 "=&Yk"))] @@ -26940,7 +26952,7 @@ [(unspec:P [(match_operand:P 3 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXSI> 2 "register_operand" "v") - (match_operand:SI 4 "const1248_operand" "n")] + (match_operand:SI 4 "const1248_operand")] UNSPEC_VSIBADDR)])] UNSPEC_GATHER)) (clobber (match_scratch:<avx512fmaskmode> 1 "=&Yk"))] @@ -26981,7 +26993,7 @@ [(unspec:P [(match_operand:P 4 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 3 "register_operand" "v") - (match_operand:SI 5 "const1248_operand" "n")] + (match_operand:SI 5 "const1248_operand")] UNSPEC_VSIBADDR)])] UNSPEC_GATHER)) (clobber (match_scratch:QI 2 "=&Yk"))] @@ -27002,7 +27014,7 @@ [(unspec:P [(match_operand:P 3 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 2 "register_operand" "v") - (match_operand:SI 4 "const1248_operand" "n")] + (match_operand:SI 4 "const1248_operand")] UNSPEC_VSIBADDR)])] UNSPEC_GATHER)) (clobber (match_scratch:QI 1 "=&Yk"))] @@ -27047,7 +27059,7 @@ [(unspec:P [(match_operand:P 0 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXSI> 2 "register_operand" "v") - (match_operand:SI 4 "const1248_operand" "n") + (match_operand:SI 4 "const1248_operand") (match_operand:<avx512fmaskmode> 6 "register_operand" "1")] UNSPEC_VSIBADDR)]) (unspec:VI48F @@ -27087,7 +27099,7 @@ [(unspec:P [(match_operand:P 0 "vsib_address_operand" "Tv") (match_operand:<VEC_GATHER_IDXDI> 2 "register_operand" "v") - (match_operand:SI 4 "const1248_operand" "n") + (match_operand:SI 4 "const1248_operand") (match_operand:QI 6 "register_operand" "1")] UNSPEC_VSIBADDR)]) (unspec:VI48F @@ -27308,7 +27320,7 @@ [(set (match_operand:<avx512fmaskmode> 0 "register_operand" "=k") (unspec:<avx512fmaskmode> [(match_operand:VFH_AVX512VL 1 "vector_operand" "vm") - (match_operand 2 "const_0_to_255_operand" "n")] + (match_operand 2 "const_0_to_255_operand")] UNSPEC_FPCLASS))] "TARGET_AVX512DQ || VALID_AVX512FP16_REG_MODE(<MODE>mode)" "vfpclass<ssemodesuffix><vecmemsuffix>\t{%2, %1, %0<mask_scalar_merge_operand3>|%0<mask_scalar_merge_operand3>, %1, %2}"; @@ -27322,7 +27334,7 @@ (and:<avx512fmaskmode> (unspec:<avx512fmaskmode> [(match_operand:VFH_128 1 "nonimmediate_operand" "vm") - (match_operand 2 "const_0_to_255_operand" "n")] + (match_operand 2 "const_0_to_255_operand")] UNSPEC_FPCLASS) (const_int 1)))] "TARGET_AVX512DQ || VALID_AVX512FP16_REG_MODE(<MODE>mode)" @@ -27446,7 +27458,7 @@ (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "0") (match_operand:V4SI 2 "vector_operand" "xBm") - (match_operand:SI 3 "const_0_to_3_operand" "n")] + (match_operand:SI 3 "const_0_to_3_operand")] UNSPEC_SHA1RNDS4))] "TARGET_SHA" "sha1rnds4\t{%3, %2, %0|%0, %2, %3}" @@ -27673,7 +27685,7 @@ [(match_operand:V16SF 1 "register_operand" "0") (match_operand:V64SF 2 "register_operand" "v") (match_operand:V4SF 3 "memory_operand" "m")] UNSPEC_VP4FMADD) - (match_operand:V16SF 4 "const0_operand" "C") + (match_operand:V16SF 4 "const0_operand") (match_operand:HI 5 "register_operand" "Yk")))] "TARGET_AVX5124FMAPS" "v4fmaddps\t{%3, %g2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %g2, %3}" @@ -27714,7 +27726,7 @@ [(match_operand:V4SF 1 "register_operand" "0") (match_operand:V64SF 2 "register_operand" "v") (match_operand:V4SF 3 "memory_operand" "m")] UNSPEC_VP4FMADD) - (match_operand:V4SF 4 "const0_operand" "C") + (match_operand:V4SF 4 "const0_operand") (match_operand:QI 5 "register_operand" "Yk")))] "TARGET_AVX5124FMAPS" "v4fmaddss\t{%3, %x2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %x2, %3}" @@ -27755,7 +27767,7 @@ [(match_operand:V16SF 1 "register_operand" "0") (match_operand:V64SF 2 "register_operand" "v") (match_operand:V4SF 3 "memory_operand" "m")] UNSPEC_VP4FNMADD) - (match_operand:V16SF 4 "const0_operand" "C") + (match_operand:V16SF 4 "const0_operand") (match_operand:HI 5 "register_operand" "Yk")))] "TARGET_AVX5124FMAPS" "v4fnmaddps\t{%3, %g2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %g2, %3}" @@ -27796,7 +27808,7 @@ [(match_operand:V4SF 1 "register_operand" "0") (match_operand:V64SF 2 "register_operand" "v") (match_operand:V4SF 3 "memory_operand" "m")] UNSPEC_VP4FNMADD) - (match_operand:V4SF 4 "const0_operand" "C") + (match_operand:V4SF 4 "const0_operand") (match_operand:QI 5 "register_operand" "Yk")))] "TARGET_AVX5124FMAPS" "v4fnmaddss\t{%3, %x2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %x2, %3}" @@ -27837,7 +27849,7 @@ [(match_operand:V16SI 1 "register_operand" "0") (match_operand:V64SI 2 "register_operand" "v") (match_operand:V4SI 3 "memory_operand" "m")] UNSPEC_VP4DPWSSD) - (match_operand:V16SI 4 "const0_operand" "C") + (match_operand:V16SI 4 "const0_operand") (match_operand:HI 5 "register_operand" "Yk")))] "TARGET_AVX5124VNNIW" "vp4dpwssd\t{%3, %g2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %g2, %3}" @@ -27878,7 +27890,7 @@ [(match_operand:V16SI 1 "register_operand" "0") (match_operand:V64SI 2 "register_operand" "v") (match_operand:V4SI 3 "memory_operand" "m")] UNSPEC_VP4DPWSSDS) - (match_operand:V16SI 4 "const0_operand" "C") + (match_operand:V16SI 4 "const0_operand") (match_operand:HI 5 "register_operand" "Yk")))] "TARGET_AVX5124VNNIW" "vp4dpwssds\t{%3, %g2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %g2, %3}" @@ -27954,7 +27966,7 @@ (unspec:VI1_AVX512F [(match_operand:VI1_AVX512F 1 "register_operand" "0,v") (match_operand:VI1_AVX512F 2 "vector_operand" "xBm,vm") - (match_operand 3 "const_0_to_255_operand" "n,n")] + (match_operand 3 "const_0_to_255_operand")] UNSPEC_GF2P8AFFINEINV))] "TARGET_GFNI" "@ @@ -27971,7 +27983,7 @@ (unspec:VI1_AVX512F [(match_operand:VI1_AVX512F 1 "register_operand" "0,v") (match_operand:VI1_AVX512F 2 "vector_operand" "xBm,vm") - (match_operand 3 "const_0_to_255_operand" "n,n")] + (match_operand 3 "const_0_to_255_operand")] UNSPEC_GF2P8AFFINE))] "TARGET_GFNI" "@ @@ -28004,7 +28016,7 @@ (unspec:VI248_AVX512VL [(match_operand:VI248_AVX512VL 1 "register_operand" "v") (match_operand:VI248_AVX512VL 2 "nonimmediate_operand" "vm") - (match_operand:SI 3 "const_0_to_255_operand" "n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_VPSHRD))] "TARGET_AVX512VBMI2" "vpshrd<ssemodesuffix>\t{%3, %2, %1, %0<mask_operand4>|%0<mask_operand4>, %1, %2, %3 }" @@ -28015,7 +28027,7 @@ (unspec:VI248_AVX512VL [(match_operand:VI248_AVX512VL 1 "register_operand" "v") (match_operand:VI248_AVX512VL 2 "nonimmediate_operand" "vm") - (match_operand:SI 3 "const_0_to_255_operand" "n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_VPSHLD))] "TARGET_AVX512VBMI2" "vpshld<ssemodesuffix>\t{%3, %2, %1, %0<mask_operand4>|%0<mask_operand4>, %1, %2, %3 }" @@ -28071,7 +28083,7 @@ (match_operand:VI248_AVX512VL 2 "register_operand" "v") (match_operand:VI248_AVX512VL 3 "nonimmediate_operand" "vm")] UNSPEC_VPSHRDV) - (match_operand:VI248_AVX512VL 4 "const0_operand" "C") + (match_operand:VI248_AVX512VL 4 "const0_operand") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] "TARGET_AVX512VBMI2" "vpshrdv<ssemodesuffix>\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" @@ -28128,7 +28140,7 @@ (match_operand:VI248_AVX512VL 2 "register_operand" "v") (match_operand:VI248_AVX512VL 3 "nonimmediate_operand" "vm")] UNSPEC_VPSHLDV) - (match_operand:VI248_AVX512VL 4 "const0_operand" "C") + (match_operand:VI248_AVX512VL 4 "const0_operand") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] "TARGET_AVX512VBMI2" "vpshldv<ssemodesuffix>\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" @@ -28224,7 +28236,7 @@ (match_operand:VI4_AVX512VL 2 "register_operand" "v") (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm") ] UNSPEC_VPMADDUBSWACCD) - (match_operand:VI4_AVX512VL 4 "const0_operand" "C") + (match_operand:VI4_AVX512VL 4 "const0_operand") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] "TARGET_AVX512VNNI" "vpdpbusd\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" @@ -28292,7 +28304,7 @@ (match_operand:VI4_AVX512VL 2 "register_operand" "v") (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] UNSPEC_VPMADDUBSWACCSSD) - (match_operand:VI4_AVX512VL 4 "const0_operand" "C") + (match_operand:VI4_AVX512VL 4 "const0_operand") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] "TARGET_AVX512VNNI" "vpdpbusds\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" @@ -28360,7 +28372,7 @@ (match_operand:VI4_AVX512VL 2 "register_operand" "v") (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] UNSPEC_VPMADDWDACCD) - (match_operand:VI4_AVX512VL 4 "const0_operand" "C") + (match_operand:VI4_AVX512VL 4 "const0_operand") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] "TARGET_AVX512VNNI" "vpdpwssd\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" @@ -28428,7 +28440,7 @@ (match_operand:VI4_AVX512VL 2 "register_operand" "v") (match_operand:VI4_AVX512VL 3 "nonimmediate_operand" "vm")] UNSPEC_VPMADDWDACCSSD) - (match_operand:VI4_AVX512VL 4 "const0_operand" "C") + (match_operand:VI4_AVX512VL 4 "const0_operand") (match_operand:<avx512fmaskmode> 5 "register_operand" "Yk")))] "TARGET_AVX512VNNI" "vpdpwssds\t{%3, %2, %0%{%5%}%{z%}|%0%{%5%}%{z%}, %2, %3 }" @@ -28478,7 +28490,7 @@ [(set (match_operand:VI8_FVL 0 "register_operand" "=v") (unspec:VI8_FVL [(match_operand:VI8_FVL 1 "register_operand" "v") (match_operand:VI8_FVL 2 "vector_operand" "vm") - (match_operand:SI 3 "const_0_to_255_operand" "n")] + (match_operand:SI 3 "const_0_to_255_operand")] UNSPEC_VPCLMULQDQ))] "TARGET_VPCLMULQDQ" "vpclmulqdq\t{%3, %2, %1, %0|%0, %1, %2, %3}" diff --git a/gcc/config/i386/subst.md b/gcc/config/i386/subst.md index bb86f82..0b75882 100644 --- a/gcc/config/i386/subst.md +++ b/gcc/config/i386/subst.md @@ -137,7 +137,7 @@ [(set (match_dup 0) (vec_merge:SUBST_V (match_dup 1) - (match_operand:SUBST_V 2 "const0_operand" "C") + (match_operand:SUBST_V 2 "const0_operand") (match_operand:<avx512fmaskmode> 3 "register_operand" "Yk"))) ]) @@ -155,7 +155,7 @@ (vec_merge:SUBST_V (vec_merge:SUBST_V (match_dup 1) - (match_operand:SUBST_V 3 "const0_operand" "C") + (match_operand:SUBST_V 3 "const0_operand") (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")) (match_dup 2) (const_int 1)))]) @@ -171,7 +171,7 @@ [(set (match_dup 0) (vec_merge:SUBST_CV (match_dup 1) - (match_operand:SUBST_CV 2 "const0_operand" "C") + (match_operand:SUBST_CV 2 "const0_operand") (unspec:<avx512fmaskmode> [(match_operand:<avx512fmaskcmode> 3 "register_operand" "Yk")] UNSPEC_COMPLEX_MASK))) @@ -372,7 +372,7 @@ (vec_merge:SUBST_CV (vec_merge:SUBST_CV (match_dup 1) - (match_operand:SUBST_CV 3 "const0_operand" "C") + (match_operand:SUBST_CV 3 "const0_operand") (unspec:<avx512fmaskmode> [(match_operand:<avx512fmaskcmode> 4 "register_operand" "Yk")] UNSPEC_COMPLEX_MASK)) @@ -478,5 +478,5 @@ [(set (match_dup 0) (vec_merge:SUBST_V (match_dup 1) - (match_operand:SUBST_V 2 "const0_operand" "C") + (match_operand:SUBST_V 2 "const0_operand") (match_operand:<avx512fmaskhalfmode> 3 "register_operand" "Yk")))]) diff --git a/gcc/config/i386/sync.md b/gcc/config/i386/sync.md index 820e9ca..92634d5 100644 --- a/gcc/config/i386/sync.md +++ b/gcc/config/i386/sync.md @@ -745,10 +745,10 @@ [(match_operand:SWI 0 "memory_operand" "+m") (match_operand:SI 3 "const_int_operand")] ;; model UNSPECV_XCHG) - (match_operand:SWI 2 "const_int_operand" "i"))) + (match_operand:SWI 2 "const_int_operand"))) (set (match_dup 0) (plus:SWI (match_dup 0) - (match_operand:SWI 1 "const_int_operand" "i")))] + (match_operand:SWI 1 "const_int_operand")))] "(unsigned HOST_WIDE_INT) INTVAL (operands[1]) == -(unsigned HOST_WIDE_INT) INTVAL (operands[2])" { diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index f83dc79..2e83ca0 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -420,6 +420,15 @@ riscv_build_integer_1 (struct riscv_integer_op codes[RISCV_MAX_INTEGER_OPS], /* Simply BSETI. */ codes[0].code = UNKNOWN; codes[0].value = value; + + /* RISC-V sign-extends all 32bit values that live in a 32bit + register. To avoid paradoxes, we thus need to use the + sign-extended (negative) representation (-1 << 31) for the + value, if we want to build (1 << 31) in SImode. This will + then expand to an LUI instruction. */ + if (mode == SImode && value == (HOST_WIDE_INT_1U << 31)) + codes[0].value = (HOST_WIDE_INT_M1U << 31); + return 1; } diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h index 5083a1c..6f7f4d3 100644 --- a/gcc/config/riscv/riscv.h +++ b/gcc/config/riscv/riscv.h @@ -528,13 +528,10 @@ enum reg_class (((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH) \ || ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0) -/* If this is a single bit mask, then we can load it with bseti. But this - is not useful for any of the low 31 bits because we can use addi or lui - to load them. It is wrong for loading SImode 0x80000000 on rv64 because it - needs to be sign-extended. So we restrict this to the upper 32-bits - only. */ -#define SINGLE_BIT_MASK_OPERAND(VALUE) \ - (pow2p_hwi (VALUE) && (ctz_hwi (VALUE) >= 32)) +/* If this is a single bit mask, then we can load it with bseti. Special + handling of SImode 0x80000000 on RV64 is done in riscv_build_integer_1. */ +#define SINGLE_BIT_MASK_OPERAND(VALUE) \ + (pow2p_hwi (VALUE)) /* Stack layout; function entry, exit and calling. */ diff --git a/gcc/configure b/gcc/configure index ba3a998..095065e 100755 --- a/gcc/configure +++ b/gcc/configure @@ -733,6 +733,8 @@ gcc_cv_readelf gcc_cv_objdump ORIGINAL_NM_FOR_TARGET gcc_cv_nm +ORIGINAL_OBJCOPY_FOR_TARGET +gcc_cv_objcopy ORIGINAL_LD_GOLD_FOR_TARGET ORIGINAL_LD_BFD_FOR_TARGET ORIGINAL_LD_FOR_TARGET @@ -23436,6 +23438,83 @@ case "$ORIGINAL_NM_FOR_TARGET" in ;; esac +# Figure out what objcopy we will be using. +if ${gcc_cv_objcopy+:} false; then : + +else + +if test -f $gcc_cv_binutils_srcdir/configure.ac \ + && test -f ../binutils/Makefile \ + && test x$build = x$host; then + gcc_cv_objcopy=../binutils/objcopy$build_exeext +elif test -x objcopy$build_exeext; then + gcc_cv_objcopy=./objcopy$build_exeext +elif ( set dummy $OBJCOPY_FOR_TARGET; test -x $2 ); then + gcc_cv_objcopy="$OBJCOPY_FOR_TARGET" +else + # Extract the first word of "$OBJCOPY_FOR_TARGET", so it can be a program name with args. +set dummy $OBJCOPY_FOR_TARGET; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_gcc_cv_objcopy+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $gcc_cv_objcopy in + [\\/]* | ?:[\\/]*) + ac_cv_path_gcc_cv_objcopy="$gcc_cv_objcopy" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_gcc_cv_objcopy="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +gcc_cv_objcopy=$ac_cv_path_gcc_cv_objcopy +if test -n "$gcc_cv_objcopy"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_objcopy" >&5 +$as_echo "$gcc_cv_objcopy" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what objcopy to use" >&5 +$as_echo_n "checking what objcopy to use... " >&6; } +if test "$gcc_cv_objcopy" = ../binutils/objcopy$build_exeext; then + # Single tree build which includes binutils. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: newly built objcopy" >&5 +$as_echo "newly built objcopy" >&6; } + in_tree_objcopy=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_objcopy" >&5 +$as_echo "$gcc_cv_objcopy" >&6; } + in_tree_objcopy=no +fi + +ORIGINAL_OBJCOPY_FOR_TARGET=$gcc_cv_objcopy + +case "$ORIGINAL_OBJCOPY_FOR_TARGET" in + ./objcopy | ./objcopy$build_exeext) ;; + *) ac_config_files="$ac_config_files objcopy:exec-tool.in" + ;; +esac # Figure out what objdump we will be using. if ${gcc_cv_objdump+:} false; then : @@ -31725,7 +31804,7 @@ fi ;; *) if test x$build = x$host; then - export_sym_check="objdump${exeext} -T" + export_sym_check="$ac_cv_prog_OBJDUMP -T" elif test x$host = x$target; then export_sym_check="$gcc_cv_objdump -T" else @@ -33176,6 +33255,7 @@ do "as") CONFIG_FILES="$CONFIG_FILES as:exec-tool.in" ;; "collect-ld") CONFIG_FILES="$CONFIG_FILES collect-ld:exec-tool.in" ;; "nm") CONFIG_FILES="$CONFIG_FILES nm:exec-tool.in" ;; + "objcopy") CONFIG_FILES="$CONFIG_FILES objcopy:exec-tool.in" ;; "dsymutil") CONFIG_FILES="$CONFIG_FILES dsymutil:exec-tool.in" ;; "clearcap.map") CONFIG_LINKS="$CONFIG_LINKS clearcap.map:${srcdir}/config/$clearcap_map" ;; "$all_outputs") CONFIG_FILES="$CONFIG_FILES $all_outputs" ;; @@ -33811,6 +33891,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} "as":F) chmod +x as ;; "collect-ld":F) chmod +x collect-ld ;; "nm":F) chmod +x nm ;; + "objcopy":F) chmod +x objcopy ;; "dsymutil":F) chmod +x dsymutil ;; "default":C) case ${CONFIG_HEADERS} in diff --git a/gcc/configure.ac b/gcc/configure.ac index 4cd48b4..e098b905 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2815,6 +2815,36 @@ case "$ORIGINAL_NM_FOR_TARGET" in *) AC_CONFIG_FILES(nm:exec-tool.in, [chmod +x nm]) ;; esac +# Figure out what objcopy we will be using. +AS_VAR_SET_IF(gcc_cv_objcopy,, [ +if test -f $gcc_cv_binutils_srcdir/configure.ac \ + && test -f ../binutils/Makefile \ + && test x$build = x$host; then + gcc_cv_objcopy=../binutils/objcopy$build_exeext +elif test -x objcopy$build_exeext; then + gcc_cv_objcopy=./objcopy$build_exeext +elif ( set dummy $OBJCOPY_FOR_TARGET; test -x $[2] ); then + gcc_cv_objcopy="$OBJCOPY_FOR_TARGET" +else + AC_PATH_PROG(gcc_cv_objcopy, $OBJCOPY_FOR_TARGET) +fi]) + +AC_MSG_CHECKING(what objcopy to use) +if test "$gcc_cv_objcopy" = ../binutils/objcopy$build_exeext; then + # Single tree build which includes binutils. + AC_MSG_RESULT(newly built objcopy) + in_tree_objcopy=yes +else + AC_MSG_RESULT($gcc_cv_objcopy) + in_tree_objcopy=no +fi + +ORIGINAL_OBJCOPY_FOR_TARGET=$gcc_cv_objcopy +AC_SUBST(ORIGINAL_OBJCOPY_FOR_TARGET) +case "$ORIGINAL_OBJCOPY_FOR_TARGET" in + ./objcopy | ./objcopy$build_exeext) ;; + *) AC_CONFIG_FILES(objcopy:exec-tool.in, [chmod +x objcopy]) ;; +esac # Figure out what objdump we will be using. AS_VAR_SET_IF(gcc_cv_objdump,, [ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8575393..b2e31fb 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,173 @@ +2022-06-04 Marek Polacek <polacek@redhat.com> + + PR c++/102399 + PR c++/69585 + * parser.cc (cp_parser_attributes_opt): Accept GNU attributes + followed by [[]] attributes and vice versa. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/105756 + * typeck.cc (cp_build_binary_op): Don't fold operands + when c_inhibit_evaluation_warnings. + +2022-06-03 Jason Merrill <jason@redhat.com> + + PR c++/105761 + * decl.cc (duplicate_decls): Don't copy DECL_TEMPLATE_INFO + from a hidden friend. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/105637 + * tree.cc (maybe_dummy_object): When returning a dummy + object, respect the cv-quals of 'this' if available. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/100374 + * pt.cc (determine_specialization): Compare overall constraints + not just the trailing constraints. + (tsubst_each_template_parm_constraints): Define. + (tsubst_friend_function): Use it. + (tsubst_friend_class): Use it. + (tsubst_template_parm): Don't substitute TEMPLATE_PARM_CONSTRAINTS. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/105797 + * pt.cc (for_each_template_parm_r) <case FUNCTION_DECL, VAR_DECL>: + Don't walk DECL_CONTEXT. + <case PARM_DECL>: Likewise. Walk TREE_TYPE. + <case CONST_DECL>: Simplify. + (any_template_parm_r) <case PARM_DECL>: Don't walk TREE_TYPE. + +2022-06-02 Marek Polacek <polacek@redhat.com> + + * constexpr.cc (potential_constant_expression_1): Treat + {,VEC_}NEW_EXPR and {,VEC_}DELETE_EXPRas potentially constant in C++20. + +2022-06-02 Marek Polacek <polacek@redhat.com> + + PR c++/105803 + * pt.cc (value_dependent_expression_p): Handle {,VEC_}NEW_EXPR + in the switch. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * cp-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + (cp_get_sarif_source_language): New. + +2022-06-02 Jason Merrill <jason@redhat.com> + + PR c++/105795 + * constexpr.cc (init_subob_ctx): Clear ctx->ctor for empty subob. + (cxx_eval_store_expression): Likewise. + (cxx_eval_bare_aggregate): Handle null ctx->ctor. + +2022-06-02 Jason Merrill <jason@redhat.com> + + PR c++/105795 + * constexpr.cc (cxx_eval_bare_aggregate): Always call + init_subob_ctx. + +2022-06-01 Jason Merrill <jason@redhat.com> + + PR c++/105734 + * parser.cc (cp_parser_postfix_dot_deref_expression): Use typeof + if the expression has auto type. + +2022-06-01 Jason Merrill <jason@redhat.com> + + PR c++/105779 + * call.cc (resolve_args): Call mark_single_function here. + * pt.cc (unify_one_argument): Not here. + +2022-06-01 Nathan Sidwell <nathan@acm.org> + + * decl2.cc (fix_temporary_vars_context_r): Use data argument + for new context. + (one_static_initialization_or_destruction): Adjust tree walk + call. Refactor guard generation. + +2022-06-01 Nathan Sidwell <nathan@acm.org> + + * decl2.cc (ssdf_decl): Delete global. + (start_static_storage_duration_function): Use some RAII. + (do_static_initialization_or_destruction): Likewise. + (c_parse_final_cleanups): Likewise. Avoid rechecking 'vars'. + +2022-06-01 Nathan Sidwell <nathan@acm.org> + + * decl2.cc (start_objects): Replace 'method_type' parameter + with 'initp' boolean, rename and retype 'priority' parameter. + (finish_objects): Likewise. Do not expand here. + (one_static_initialization_or_destruction): Move 'initp' + parameter first. + (do_static_initialization_or_destruction): Likewise. + (generate_ctor_or_dtor_function): Rename 'initp' parameter. + Adjust start_objects/finish_obects calls and expand here. + (generate_ctor_and_dtor_functions_for_priority): Adjust calls. + (c_parse_final_cleanups): Likewise. + (vtv_start_verification_constructor_init): Adjust. + (vtv_finish_verification_constructor_init): Use finish_objects. + +2022-05-31 Patrick Palka <ppalka@redhat.com> + + PR c++/105758 + * call.cc (build_over_call): Use z_candidate::conversion_path + and ::access_path instead of TYPE_BINFO when building the + BASELINK for the templated form. + +2022-05-31 Patrick Palka <ppalka@redhat.com> + + * parser.cc: Use auto_timevar instead of timevar_push/pop. + Remove wrapper functions. + * pt.cc: Likewise. + +2022-05-31 Patrick Palka <ppalka@redhat.com> + + * cp-tree.h (cp_build_qualified_type_real): Rename to ... + (cp_build_qualified_type): ... this. Give its last parameter + a default argument. Remove macro of the same name. + * decl.cc (grokdeclarator): Adjust accordingly. + * pt.cc (tsubst_aggr_type): Likewise. + (rebuild_function_or_method_type): Likewise. + (tsubst): Likewise. + (maybe_dependent_member_ref): Likewise. + (unify): Likewise. + * tree.cc (cp_build_qualified_type_real): Rename to ... + (cp_build_qualified_type): ... this. Adjust accordingly. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (c++.tags): Just look at *.cc. + +2022-05-31 Patrick Palka <ppalka@redhat.com> + + * cp-tree.h (comp_template_args): Change return type to bool. + * pt.cc (comp_template_args): Document default arguments. + Change return type to bool and adjust returns accordingly. + +2022-05-31 Patrick Palka <ppalka@redhat.com> + + * decl.cc (grokvardecl): Use current_template_constraints. + (grokdeclarator): Likewise. + (xref_tag): Likewise. + * semantics.cc (finish_template_template_parm): Likewise. + +2022-05-31 Jakub Jelinek <jakub@redhat.com> + + * parser.cc (OMP_SCOPE_CLAUSE_MASK): Add firstprivate and allocate + clauses. + +2022-05-30 Marek Polacek <polacek@redhat.com> + + PR c++/99080 + * pt.cc (type_dependent_expression_p): Assert !TYPE_P. + * semantics.cc (finish_id_expression_1): Handle UNBOUND_CLASS_TEMPLATE + specifically. + 2022-05-28 Jakub Jelinek <jakub@redhat.com> * parser.cc (handle_omp_declare_target_clause): If OMP_CLAUSE_LINK was diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index 2de4e47..23d98c8 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -174,7 +174,7 @@ c++.srcinfo: c++.srcextra: c++.tags: force - cd $(srcdir)/cp; $(ETAGS) -o TAGS.sub *.c *.cc *.h --language=none \ + cd $(srcdir)/cp; $(ETAGS) -o TAGS.sub *.cc *.h --language=none \ --regex='/DEFTREECODE [(]\([A-Z_]+\)/\1/' cp-tree.def; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 14c6037..4710c37 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -4672,6 +4672,11 @@ resolve_args (vec<tree, va_gc> *args, tsubst_flags_t complain) } else if (invalid_nonstatic_memfn_p (EXPR_LOCATION (arg), arg, complain)) return NULL; + + /* Force auto deduction now. Omit tf_warning to avoid redundant + deprecated warning on deprecated-14.C. */ + if (!mark_single_function (arg, tf_error)) + return NULL; } return args; } @@ -9244,8 +9249,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) } else { - tree binfo = TYPE_BINFO (TREE_TYPE (first_arg)); - callee = build_baselink (binfo, binfo, fn, NULL_TREE); + callee = build_baselink (cand->conversion_path, cand->access_path, + fn, NULL_TREE); callee = build_min (COMPONENT_REF, TREE_TYPE (fn), first_arg, callee, NULL_TREE); } diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 4520847..6842388 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -4695,9 +4695,17 @@ init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx, else new_ctx.object = build_ctor_subob_ref (index, type, ctx->object); } - tree elt = build_constructor (type, NULL); - CONSTRUCTOR_NO_CLEARING (elt) = true; - new_ctx.ctor = elt; + + if (is_empty_class (type)) + /* Leave ctor null for an empty subobject, they aren't represented in the + result of evaluation. */ + new_ctx.ctor = NULL_TREE; + else + { + tree elt = build_constructor (type, NULL); + CONSTRUCTOR_NO_CLEARING (elt) = true; + new_ctx.ctor = elt; + } if (TREE_CODE (value) == TARGET_EXPR) /* Avoid creating another CONSTRUCTOR when we expand the TARGET_EXPR. */ @@ -4762,11 +4770,14 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, ctx = &new_ctx; }; verify_ctor_sanity (ctx, type); - vec<constructor_elt, va_gc> **p = &CONSTRUCTOR_ELTS (ctx->ctor); - vec_alloc (*p, vec_safe_length (v)); - - if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (t)) - CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor) = 1; + vec<constructor_elt, va_gc> **p = nullptr; + if (ctx->ctor) + { + p = &CONSTRUCTOR_ELTS (ctx->ctor); + vec_alloc (*p, vec_safe_length (v)); + if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (t)) + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (ctx->ctor) = 1; + } unsigned i; tree index, value; @@ -4777,12 +4788,9 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, tree orig_value = value; /* Like in cxx_eval_store_expression, omit entries for empty fields. */ bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index); - if (no_slot) - new_ctx = *ctx; - else - init_subob_ctx (ctx, new_ctx, index, value); + init_subob_ctx (ctx, new_ctx, index, value); int pos_hint = -1; - if (new_ctx.ctor != ctx->ctor) + if (new_ctx.ctor != ctx->ctor && !no_slot) { /* If we built a new CONSTRUCTOR, attach it now so that other initializers can refer to it. */ @@ -4817,17 +4825,19 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, inner->value = elt; changed = true; } + else if (no_slot) + /* This is an initializer for an empty field; now that we've + checked that it's constant, we can ignore it. */ + changed = true; else if (index && (TREE_CODE (index) == NOP_EXPR || TREE_CODE (index) == POINTER_PLUS_EXPR)) { - /* This is an initializer for an empty base; now that we've - checked that it's constant, we can ignore it. */ + /* Old representation of empty bases. FIXME remove. */ + gcc_checking_assert (false); gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index)))); changed = true; } - else if (no_slot) - changed = true; else { if (TREE_CODE (type) == UNION_TYPE @@ -4852,6 +4862,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, if (*non_constant_p || !changed) return t; t = ctx->ctor; + if (!t) + t = build_constructor (type, NULL); /* We're done building this CONSTRUCTOR, so now we can interpret an element without an explicit initializer as value-initialized. */ CONSTRUCTOR_NO_CLEARING (t) = false; @@ -5836,6 +5848,16 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, valp = &cep->value; } + /* For initialization of an empty base, the original target will be + *(base*)this, evaluation of which resolves to the object + argument, which has the derived type rather than the base type. */ + if (!empty_base && !(same_type_ignoring_top_level_qualifiers_p + (initialized_type (init), type))) + { + gcc_assert (is_empty_class (TREE_TYPE (target))); + empty_base = true; + } + /* Detect modifying a constant object in constexpr evaluation. We have found a const object that is being modified. Figure out if we need to issue an error. Consider @@ -5904,7 +5926,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, *valp = build_constructor (type, NULL); CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init; } - new_ctx.ctor = *valp; + new_ctx.ctor = empty_base ? NULL_TREE : *valp; new_ctx.object = target; /* Avoid temporary materialization when initializing from a TARGET_EXPR. We don't need to mess with AGGR_EXPR_SLOT/VEC_INIT_EXPR_SLOT because @@ -5934,16 +5956,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, gcc_checking_assert (!*valp || (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (*valp), type))); - if (empty_base || !(same_type_ignoring_top_level_qualifiers_p - (initialized_type (init), type))) - { - /* For initialization of an empty base, the original target will be - *(base*)this, evaluation of which resolves to the object - argument, which has the derived type rather than the base type. In - this situation, just evaluate the initializer and return, since - there's no actual data to store, and we didn't build a CONSTRUCTOR. */ - gcc_assert (is_empty_class (TREE_TYPE (target))); - empty_base = true; + if (empty_base) + { + /* Just evaluate the initializer and return, since there's no actual data + to store, and we didn't build a CONSTRUCTOR. */ if (!*valp) { /* But do make sure we have something in *valp. */ @@ -9023,12 +9039,20 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, "before C++17"); return false; - case DYNAMIC_CAST_EXPR: - case PSEUDO_DTOR_EXPR: case NEW_EXPR: case VEC_NEW_EXPR: case DELETE_EXPR: case VEC_DELETE_EXPR: + if (cxx_dialect >= cxx20) + /* In C++20, new-expressions are potentially constant. */ + return true; + else if (flags & tf_error) + error_at (loc, "new-expression is not a constant expression " + "before C++20"); + return false; + + case DYNAMIC_CAST_EXPR: + case PSEUDO_DTOR_EXPR: case THROW_EXPR: case OMP_PARALLEL: case OMP_TASK: diff --git a/gcc/cp/cp-lang.cc b/gcc/cp/cp-lang.cc index 7c8b947..c3cfde5 100644 --- a/gcc/cp/cp-lang.cc +++ b/gcc/cp/cp-lang.cc @@ -36,6 +36,7 @@ static tree get_template_argument_pack_elems_folded (const_tree); static tree cxx_enum_underlying_base_type (const_tree); static tree *cxx_omp_get_decl_init (tree); static void cxx_omp_finish_decl_inits (void); +static const char *cp_get_sarif_source_language (const char *); /* Lang hooks common to C++ and ObjC++ are declared in cp/cp-objcp-common.h; consequently, there should be very few hooks below. */ @@ -100,6 +101,9 @@ static void cxx_omp_finish_decl_inits (void); #undef LANG_HOOKS_OMP_FINISH_DECL_INITS #define LANG_HOOKS_OMP_FINISH_DECL_INITS cxx_omp_finish_decl_inits +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE cp_get_sarif_source_language + /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; @@ -265,6 +269,15 @@ cxx_omp_finish_decl_inits (void) dynamic_initializers = NULL; } +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +static const char * +cp_get_sarif_source_language (const char *) +{ + return "cplusplus"; +} + #if CHECKING_P namespace selftest { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d77fd1e..cc13809 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7327,7 +7327,7 @@ extern tree get_template_info (const_tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); extern bool is_specialization_of_friend (tree, tree); -extern int comp_template_args (tree, tree, tree * = NULL, +extern bool comp_template_args (tree, tree, tree * = NULL, tree * = NULL, bool = false); extern int template_args_equal (tree, tree, bool = false); extern tree maybe_process_partial_specialization (tree); @@ -7877,9 +7877,8 @@ extern tree make_ptrmem_cst (tree, tree); extern tree cp_build_type_attribute_variant (tree, tree); extern tree cp_build_reference_type (tree, bool); extern tree move (tree); -extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t); -#define cp_build_qualified_type(TYPE, QUALS) \ - cp_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) +extern tree cp_build_qualified_type (tree, int, + tsubst_flags_t = tf_warning_or_error); extern bool cv_qualified_p (const_tree); extern tree cv_unqualified (tree); extern special_function_kind special_function_p (const_tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 892e4a4..90b12d6 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -2654,7 +2654,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) if (LANG_DECL_HAS_MIN (newdecl)) { DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl); - if (DECL_TEMPLATE_INFO (newdecl)) + if (new_defines_function + && DECL_TEMPLATE_INFO (olddecl) + && DECL_UNIQUE_FRIEND_P (DECL_TEMPLATE_RESULT + (DECL_TI_TEMPLATE (olddecl)))) + /* Don't copy template info from a non-template friend declaration + in a class template (PR105761). */; + else if (DECL_TEMPLATE_INFO (newdecl)) { new_template_info = DECL_TEMPLATE_INFO (newdecl); if (DECL_TEMPLATE_INSTANTIATION (olddecl) @@ -2662,8 +2668,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) /* Remember the presence of explicit specialization args. */ TINFO_USED_TEMPLATE_ID (DECL_TEMPLATE_INFO (olddecl)) = TINFO_USED_TEMPLATE_ID (new_template_info); + DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); } - DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); + else + DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl); } if (DECL_DECLARES_FUNCTION_P (newdecl)) @@ -10789,9 +10797,7 @@ grokvardecl (tree type, else if (flag_concepts && current_template_depth > template_class_depth (scope)) { - tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); - tree ci = build_constraints (reqs, NULL_TREE); - + tree ci = current_template_constraints (); set_constraints (decl, ci); } @@ -12377,7 +12383,7 @@ grokdeclarator (const cp_declarator *declarator, type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); type_quals |= cp_type_quals (type); - type = cp_build_qualified_type_real + type = cp_build_qualified_type (type, type_quals, ((((typedef_decl && !DECL_ARTIFICIAL (typedef_decl)) || declspecs->decltype_p) ? tf_ignore_bad_quals : 0) | tf_warning_or_error)); @@ -14227,9 +14233,7 @@ grokdeclarator (const cp_declarator *declarator, > template_class_depth (current_class_type)); if (memtmpl) { - tree tmpl_reqs - = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); - tree ci = build_constraints (tmpl_reqs, NULL_TREE); + tree ci = current_template_constraints (); set_constraints (decl, ci); } } @@ -15852,13 +15856,8 @@ xref_tag (enum tag_types tag_code, tree name, { /* Check that we aren't trying to overload a class with different constraints. */ - tree constr = NULL_TREE; - if (current_template_parms) - { - tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); - constr = build_constraints (reqs, NULL_TREE); - } - if (!redeclare_class_template (t, current_template_parms, constr)) + if (!redeclare_class_template (t, current_template_parms, + current_template_constraints ())) return error_mark_node; } else if (!processing_template_decl diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index e72fdf0..974afe7 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -66,14 +66,14 @@ typedef struct priority_info_s { int destructions_p; } *priority_info; -static tree start_objects (int, int); -static void finish_objects (int, int, tree); +static tree start_objects (bool, unsigned); +static tree finish_objects (bool, unsigned, tree); static tree start_static_storage_duration_function (unsigned); static void finish_static_storage_duration_function (tree); static priority_info get_priority_info (int); -static void do_static_initialization_or_destruction (tree, bool); -static void one_static_initialization_or_destruction (tree, tree, bool); -static void generate_ctor_or_dtor_function (bool, int, location_t *); +static void do_static_initialization_or_destruction (bool, tree); +static void one_static_initialization_or_destruction (bool, tree, tree); +static void generate_ctor_or_dtor_function (bool, unsigned, location_t *); static int generate_ctor_and_dtor_functions_for_priority (splay_tree_node, void *); static tree prune_vars_needing_no_initialization (tree *); @@ -3813,17 +3813,14 @@ generate_tls_wrapper (tree fn) expand_or_defer_fn (finish_function (/*inline_p=*/false)); } -/* Start the process of running a particular set of global constructors - or destructors. Subroutine of do_[cd]tors. Also called from - vtv_start_verification_constructor_init_function. */ +/* Start a global constructor or destructor function. */ static tree -start_objects (int method_type, int initp) +start_objects (bool initp, unsigned priority) { - /* Make ctor or dtor function. METHOD_TYPE may be 'I' or 'D'. */ int module_init = 0; - if (initp == DEFAULT_INIT_PRIORITY && method_type == 'I') + if (priority == DEFAULT_INIT_PRIORITY && initp) module_init = module_initializer_kind (); tree name = NULL_TREE; @@ -3833,15 +3830,17 @@ start_objects (int method_type, int initp) { char type[14]; - unsigned len = sprintf (type, "sub_%c", method_type); - if (initp != DEFAULT_INIT_PRIORITY) + /* We use `I' to indicate initialization and `D' to indicate + destruction. */ + unsigned len = sprintf (type, "sub_%c", initp ? 'I' : 'D'); + if (priority != DEFAULT_INIT_PRIORITY) { char joiner = '_'; #ifdef JOINER joiner = JOINER; #endif type[len++] = joiner; - sprintf (type + len, "%.5u", initp); + sprintf (type + len, "%.5u", priority); } name = get_file_function_name (type); } @@ -3867,7 +3866,7 @@ start_objects (int method_type, int initp) TREE_USED (current_function_decl) = 1; /* Mark this function as a global constructor or destructor. */ - if (method_type == 'I') + if (initp) DECL_GLOBAL_CTOR_P (current_function_decl) = 1; else DECL_GLOBAL_DTOR_P (current_function_decl) = 1; @@ -3905,28 +3904,27 @@ start_objects (int method_type, int initp) return body; } -/* Finish the process of running a particular set of global constructors - or destructors. Subroutine of do_[cd]tors. */ +/* Finish a global constructor or destructor. */ -static void -finish_objects (int method_type, int initp, tree body) +static tree +finish_objects (bool initp, unsigned priority, tree body) { /* Finish up. */ finish_compound_stmt (body); tree fn = finish_function (/*inline_p=*/false); - if (method_type == 'I') + if (initp) { DECL_STATIC_CONSTRUCTOR (fn) = 1; - decl_init_priority_insert (fn, initp); + decl_init_priority_insert (fn, priority); } else { DECL_STATIC_DESTRUCTOR (fn) = 1; - decl_fini_priority_insert (fn, initp); + decl_fini_priority_insert (fn, priority); } - expand_or_defer_fn (fn); + return fn; } /* The names of the parameters to the function created to handle @@ -3945,9 +3943,6 @@ static GTY(()) tree initialize_p_decl; /* The declaration for the __PRIORITY argument. */ static GTY(()) tree priority_decl; -/* The declaration for the static storage duration function. */ -static GTY(()) tree ssdf_decl; - /* All the static storage duration functions created in this translation unit. */ static GTY(()) vec<tree, va_gc> *ssdf_decls; @@ -3972,24 +3967,20 @@ static splay_tree priority_info_map; static tree start_static_storage_duration_function (unsigned count) { - tree type; - tree body; char id[sizeof (SSDF_IDENTIFIER) + 1 /* '\0' */ + 32]; /* Create the identifier for this function. It will be of the form SSDF_IDENTIFIER_<number>. */ sprintf (id, "%s_%u", SSDF_IDENTIFIER, count); - type = build_function_type_list (void_type_node, - integer_type_node, integer_type_node, - NULL_TREE); + tree type = build_function_type_list (void_type_node, + integer_type_node, integer_type_node, + NULL_TREE); /* Create the FUNCTION_DECL itself. */ - ssdf_decl = build_lang_decl (FUNCTION_DECL, - get_identifier (id), - type); - TREE_PUBLIC (ssdf_decl) = 0; - DECL_ARTIFICIAL (ssdf_decl) = 1; + tree fn = build_lang_decl (FUNCTION_DECL, get_identifier (id), type); + TREE_PUBLIC (fn) = 0; + DECL_ARTIFICIAL (fn) = 1; /* Put this function in the list of functions to be called from the static constructors and destructors. */ @@ -4011,21 +4002,21 @@ start_static_storage_duration_function (unsigned count) get_priority_info (DEFAULT_INIT_PRIORITY); } - vec_safe_push (ssdf_decls, ssdf_decl); + vec_safe_push (ssdf_decls, fn); /* Create the argument list. */ initialize_p_decl = cp_build_parm_decl - (ssdf_decl, get_identifier (INITIALIZE_P_IDENTIFIER), integer_type_node); + (fn, get_identifier (INITIALIZE_P_IDENTIFIER), integer_type_node); TREE_USED (initialize_p_decl) = 1; priority_decl = cp_build_parm_decl - (ssdf_decl, get_identifier (PRIORITY_IDENTIFIER), integer_type_node); + (fn, get_identifier (PRIORITY_IDENTIFIER), integer_type_node); TREE_USED (priority_decl) = 1; DECL_CHAIN (initialize_p_decl) = priority_decl; - DECL_ARGUMENTS (ssdf_decl) = initialize_p_decl; + DECL_ARGUMENTS (fn) = initialize_p_decl; /* Put the function in the global scope. */ - pushdecl (ssdf_decl); + pushdecl (fn); /* Start the function itself. This is equivalent to declaring the function as: @@ -4034,14 +4025,10 @@ start_static_storage_duration_function (unsigned count) It is static because we only need to call this function from the various constructor and destructor functions for this module. */ - start_preparsed_function (ssdf_decl, - /*attrs=*/NULL_TREE, - SF_PRE_PARSED); + start_preparsed_function (fn, /*attrs=*/NULL_TREE, SF_PRE_PARSED); /* Set up the scope of the outermost block in the function. */ - body = begin_compound_stmt (BCS_FN_BODY); - - return body; + return begin_compound_stmt (BCS_FN_BODY); } /* Finish the generation of the function which performs initialization @@ -4098,34 +4085,25 @@ get_priority_info (int priority) || DECL_ONE_ONLY (decl) \ || DECL_WEAK (decl))) -/* Called from one_static_initialization_or_destruction(), - via walk_tree. - Walks the initializer list of a global variable and looks for +/* Walks the initializer list of a global variable and looks for temporary variables (DECL_NAME() == NULL and DECL_ARTIFICIAL != 0) - and that have their DECL_CONTEXT() == NULL. - For each such temporary variable, set their DECL_CONTEXT() to - the current function. This is necessary because otherwise - some optimizers (enabled by -O2 -fprofile-arcs) might crash - when trying to refer to a temporary variable that does not have - it's DECL_CONTECT() properly set. */ + and that have their DECL_CONTEXT() == NULL. For each such + temporary variable, set their DECL_CONTEXT() to CTX -- the + initializing function. This is necessary because otherwise some + optimizers (enabled by -O2 -fprofile-arcs) might crash when trying + to refer to a temporary variable that does not have its + DECL_CONTEXT() properly set. */ + static tree fix_temporary_vars_context_r (tree *node, int * /*unused*/, - void * /*unused1*/) + void *ctx) { - gcc_assert (current_function_decl); - if (TREE_CODE (*node) == BIND_EXPR) - { - tree var; - - for (var = BIND_EXPR_VARS (*node); var; var = DECL_CHAIN (var)) - if (VAR_P (var) - && !DECL_NAME (var) - && DECL_ARTIFICIAL (var) - && !DECL_CONTEXT (var)) - DECL_CONTEXT (var) = current_function_decl; - } + for (tree var = BIND_EXPR_VARS (*node); var; var = DECL_CHAIN (var)) + if (VAR_P (var) && !DECL_NAME (var) + && DECL_ARTIFICIAL (var) && !DECL_CONTEXT (var)) + DECL_CONTEXT (var) = tree (ctx); return NULL_TREE; } @@ -4135,11 +4113,8 @@ fix_temporary_vars_context_r (tree *node, are destroying it. */ static void -one_static_initialization_or_destruction (tree decl, tree init, bool initp) +one_static_initialization_or_destruction (bool initp, tree decl, tree init) { - tree guard_if_stmt = NULL_TREE; - tree guard; - /* If we are supposed to destruct and there's a trivial destructor, nothing has to be done. */ if (!initp @@ -4163,7 +4138,7 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) of the temporaries are set to the current function decl. */ cp_walk_tree_without_duplicates (&init, fix_temporary_vars_context_r, - NULL); + current_function_decl); /* Because of: @@ -4184,63 +4159,50 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) } /* Assume we don't need a guard. */ - guard = NULL_TREE; + tree guard_if_stmt = NULL_TREE; + /* We need a guard if this is an object with external linkage that might be initialized in more than one place. (For example, a static data member of a template, when the data member requires construction.) */ if (NEEDS_GUARD_P (decl)) { + tree guard = get_guard (decl); tree guard_cond; - guard = get_guard (decl); - - /* When using __cxa_atexit, we just check the GUARD as we would - for a local static. */ if (flag_use_cxa_atexit) { - /* When using __cxa_atexit, we never try to destroy + /* When using __cxa_atexit, we just check the GUARD as we + would for a local static. We never try to destroy anything from a static destructor. */ gcc_assert (initp); guard_cond = get_guard_cond (guard, false); } - /* If we don't have __cxa_atexit, then we will be running - destructors from .fini sections, or their equivalents. So, - we need to know how many times we've tried to initialize this - object. We do initializations only if the GUARD is zero, - i.e., if we are the first to initialize the variable. We do - destructions only if the GUARD is one, i.e., if we are the - last to destroy the variable. */ - else if (initp) - guard_cond - = cp_build_binary_op (input_location, - EQ_EXPR, - cp_build_unary_op (PREINCREMENT_EXPR, - guard, - /*noconvert=*/true, - tf_warning_or_error), - integer_one_node, - tf_warning_or_error); else - guard_cond - = cp_build_binary_op (input_location, - EQ_EXPR, - cp_build_unary_op (PREDECREMENT_EXPR, - guard, - /*noconvert=*/true, - tf_warning_or_error), - integer_zero_node, - tf_warning_or_error); + { + /* If we don't have __cxa_atexit, then we will be running + destructors from .fini sections, or their equivalents. + So, we need to know how many times we've tried to + initialize this object. We do initializations only if + the GUARD was or becomes zero (initp vs !initp + respectively). */ + guard_cond = cp_build_unary_op (initp ? POSTINCREMENT_EXPR + : PREDECREMENT_EXPR, + guard, + /*noconvert=*/true, + tf_warning_or_error); + guard_cond = cp_build_binary_op (input_location, EQ_EXPR, guard_cond, + integer_zero_node, + tf_warning_or_error); + } guard_if_stmt = begin_if_stmt (); finish_if_stmt_cond (guard_cond, guard_if_stmt); - } - - /* If we're using __cxa_atexit, we have not already set the GUARD, - so we must do so now. */ - if (guard && initp && flag_use_cxa_atexit) - finish_expr_stmt (set_guard (guard)); + if (flag_use_cxa_atexit) + /* Set the GUARD now. */ + finish_expr_stmt (set_guard (guard)); + } /* Perform the initialization or destruction. */ if (initp) @@ -4249,11 +4211,8 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) { finish_expr_stmt (init); if (sanitize_flags_p (SANITIZE_ADDRESS, decl)) - { - varpool_node *vnode = varpool_node::get (decl); - if (vnode) - vnode->dynamically_initialized = 1; - } + if (varpool_node *vnode = varpool_node::get (decl)) + vnode->dynamically_initialized = 1; } /* If we're using __cxa_atexit, register a function that calls the @@ -4265,7 +4224,7 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) finish_expr_stmt (build_cleanup (decl)); /* Finish the guard if-stmt, if necessary. */ - if (guard) + if (guard_if_stmt) { finish_then_clause (guard_if_stmt); finish_if_stmt (guard_if_stmt); @@ -4282,13 +4241,11 @@ one_static_initialization_or_destruction (tree decl, tree init, bool initp) Whether initialization or destruction is performed is specified by INITP. */ static void -do_static_initialization_or_destruction (tree vars, bool initp) +do_static_initialization_or_destruction (bool initp, tree vars) { - tree node, init_if_stmt, cond; - /* Build the outer if-stmt to check for initialization or destruction. */ - init_if_stmt = begin_if_stmt (); - cond = initp ? integer_one_node : integer_zero_node; + tree init_if_stmt = begin_if_stmt (); + tree cond = initp ? integer_one_node : integer_zero_node; cond = cp_build_binary_op (input_location, EQ_EXPR, initialize_p_decl, @@ -4306,12 +4263,9 @@ do_static_initialization_or_destruction (tree vars, bool initp) if (initp && (flag_sanitize & SANITIZE_ADDRESS)) finish_expr_stmt (asan_dynamic_init_call (/*after_p=*/false)); - node = vars; + tree node = vars; do { tree decl = TREE_VALUE (node); - tree priority_if_stmt; - int priority; - priority_info pi; /* If we don't need a destructor, there's nothing to do. Avoid creating a possibly empty if-stmt. */ @@ -4323,8 +4277,8 @@ do_static_initialization_or_destruction (tree vars, bool initp) /* Remember that we had an initialization or finalization at this priority. */ - priority = DECL_EFFECTIVE_INIT_PRIORITY (decl); - pi = get_priority_info (priority); + int priority = DECL_EFFECTIVE_INIT_PRIORITY (decl); + priority_info pi = get_priority_info (priority); if (initp) pi->initializations_p = 1; else @@ -4332,7 +4286,7 @@ do_static_initialization_or_destruction (tree vars, bool initp) /* Conditionalize this initialization on being in the right priority and being initializing/finalizing appropriately. */ - priority_if_stmt = begin_if_stmt (); + tree priority_if_stmt = begin_if_stmt (); cond = cp_build_binary_op (input_location, EQ_EXPR, priority_decl, @@ -4345,8 +4299,8 @@ do_static_initialization_or_destruction (tree vars, bool initp) && DECL_EFFECTIVE_INIT_PRIORITY (TREE_VALUE (node)) == priority; node = TREE_CHAIN (node)) /* Do one initialization or destruction. */ - one_static_initialization_or_destruction (TREE_VALUE (node), - TREE_PURPOSE (node), initp); + one_static_initialization_or_destruction (initp, TREE_VALUE (node), + TREE_PURPOSE (node)); /* Finish up the priority if-stmt body. */ finish_then_clause (priority_if_stmt); @@ -4445,27 +4399,22 @@ write_out_vars (tree vars) storage duration having the indicated PRIORITY. */ static void -generate_ctor_or_dtor_function (bool constructor_p, int priority, - location_t *locus) +generate_ctor_or_dtor_function (bool initp, unsigned priority, location_t *locus) { input_location = *locus; - /* We use `I' to indicate initialization and `D' to indicate - destruction. */ - char function_key = constructor_p ? 'I' : 'D'; - /* We emit the function lazily, to avoid generating empty global constructors and destructors. */ tree body = NULL_TREE; - if (constructor_p && priority == DEFAULT_INIT_PRIORITY) + if (initp && priority == DEFAULT_INIT_PRIORITY) { bool objc = c_dialect_objc () && objc_static_init_needed_p (); /* We may have module initialization to emit and/or insert before other intializations. */ if (module_initializer_kind () || objc) - body = start_objects (function_key, priority); + body = start_objects (initp, priority); /* For Objective-C++, we may need to initialize metadata found in this module. This must be done _before_ any other static @@ -4484,11 +4433,11 @@ generate_ctor_or_dtor_function (bool constructor_p, int priority, if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE))) { if (! body) - body = start_objects (function_key, priority); + body = start_objects (initp, priority); tree call = cp_build_function_call_nary (fndecl, tf_warning_or_error, build_int_cst (NULL_TREE, - constructor_p), + initp), build_int_cst (NULL_TREE, priority), NULL_TREE); @@ -4498,7 +4447,7 @@ generate_ctor_or_dtor_function (bool constructor_p, int priority, /* Close out the function. */ if (body) - finish_objects (function_key, priority, body); + expand_or_defer_fn (finish_objects (initp, priority, body)); } /* Generate constructor and destructor functions for the priority @@ -4514,9 +4463,9 @@ generate_ctor_and_dtor_functions_for_priority (splay_tree_node n, void * data) /* Generate the functions themselves, but only if they are really needed. */ if (pi->initializations_p) - generate_ctor_or_dtor_function (/*constructor_p=*/true, priority, locus); + generate_ctor_or_dtor_function (/*initp=*/true, priority, locus); if (pi->destructions_p) - generate_ctor_or_dtor_function (/*constructor_p=*/false, priority, locus); + generate_ctor_or_dtor_function (/*initp=*/false, priority, locus); /* Keep iterating. */ return 0; @@ -4800,7 +4749,7 @@ handle_tls_init (void) { tree var = TREE_VALUE (vars); tree init = TREE_PURPOSE (vars); - one_static_initialization_or_destruction (var, init, true); + one_static_initialization_or_destruction (/*initp=*/true, var, init); /* Output init aliases even with -fno-extern-tls-init. */ if (TARGET_SUPPORTS_ALIASES && TREE_PUBLIC (var)) @@ -5172,6 +5121,9 @@ c_parse_final_cleanups (void) hash_map_safe_put<hm_ggc> (dynamic_initializers, TREE_VALUE (t), TREE_PURPOSE (t)); + /* Make sure the back end knows about all the variables. */ + write_out_vars (vars); + /* We need to start a new initialization function each time through the loop. That's because we need to know which vtables have been referenced, and TREE_SYMBOL_REFERENCED @@ -5179,19 +5131,14 @@ c_parse_final_cleanups (void) out. That's a deficiency in the back end. When this is fixed, these initialization functions could all become inline, with resulting performance improvements. */ - tree ssdf_body; - - /* Make sure the back end knows about all the variables. */ - write_out_vars (vars); /* Set the line and file, so that it is obviously not from the source file. */ input_location = locus_at_end_of_parsing; - ssdf_body = start_static_storage_duration_function (ssdf_count); + tree ssdf_body = start_static_storage_duration_function (ssdf_count); /* First generate code to do all the initializations. */ - if (vars) - do_static_initialization_or_destruction (vars, /*initp=*/true); + do_static_initialization_or_destruction (/*initp=*/true, vars); /* Then, generate code to do all the destructions. Do these in reverse order so that the most recently constructed @@ -5199,13 +5146,11 @@ c_parse_final_cleanups (void) __cxa_atexit, then we don't need to do this; functions were registered at initialization time to destroy the local statics. */ - if (!flag_use_cxa_atexit && vars) + if (!flag_use_cxa_atexit) { vars = nreverse (vars); - do_static_initialization_or_destruction (vars, /*initp=*/false); + do_static_initialization_or_destruction (/*initp=*/false, vars); } - else - vars = NULL_TREE; /* Finish up the static storage duration function for this round. */ @@ -6038,20 +5983,13 @@ mark_used (tree decl) tree vtv_start_verification_constructor_init_function (void) { - return start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1); + return start_objects (/*initp=*/true, MAX_RESERVED_INIT_PRIORITY - 1); } tree -vtv_finish_verification_constructor_init_function (tree function_body) +vtv_finish_verification_constructor_init_function (tree body) { - tree fn; - - finish_compound_stmt (function_body); - fn = finish_function (/*inline_p=*/false); - DECL_STATIC_CONSTRUCTOR (fn) = 1; - decl_init_priority_insert (fn, MAX_RESERVED_INIT_PRIORITY - 1); - - return fn; + return finish_objects (/*initp=*/true, MAX_RESERVED_INIT_PRIORITY - 1, body); } #include "gt-cp-decl2.h" diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index b3a6c9a..535bf7e 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -8262,7 +8262,7 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser, tree type = TREE_TYPE (postfix_expression); /* If we don't have a (type-dependent) object of class type, use typeof to figure out the type of the object. */ - if (type == NULL_TREE) + if (type == NULL_TREE || is_auto (type)) type = finish_typeof (postfix_expression); parser->context->object_type = type; } @@ -19106,7 +19106,7 @@ cp_parser_explicit_instantiation (cp_parser* parser) cp_decl_specifier_seq decl_specifiers; tree extension_specifier = NULL_TREE; - timevar_push (TV_TEMPLATE_INST); + auto_timevar tv (TV_TEMPLATE_INST); /* Look for an (optional) storage-class-specifier or function-specifier. */ @@ -19207,8 +19207,6 @@ cp_parser_explicit_instantiation (cp_parser* parser) cp_parser_consume_semicolon_at_end_of_statement (parser); - timevar_pop (TV_TEMPLATE_INST); - cp_finalize_omp_declare_simd (parser, &odsd); } @@ -20966,7 +20964,8 @@ cp_parser_enum_specifier (cp_parser* parser) elaborated-type-specifier. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - timevar_push (TV_PARSE_ENUM); + auto_timevar tv (TV_PARSE_ENUM); + if (nested_name_specifier && nested_name_specifier != error_mark_node) { @@ -21072,7 +21071,6 @@ cp_parser_enum_specifier (cp_parser* parser) if (scoped_enum_p) finish_scope (); - timevar_pop (TV_PARSE_ENUM); } else { @@ -25927,9 +25925,11 @@ pop_injected_parms (void) Returns the TREE_TYPE representing the class. */ -static tree -cp_parser_class_specifier_1 (cp_parser* parser) +tree +cp_parser_class_specifier (cp_parser* parser) { + auto_timevar tv (TV_PARSE_STRUCT); + tree type; tree attributes = NULL_TREE; bool nested_name_specifier_p; @@ -26321,16 +26321,6 @@ cp_parser_class_specifier_1 (cp_parser* parser) return type; } -static tree -cp_parser_class_specifier (cp_parser* parser) -{ - tree ret; - timevar_push (TV_PARSE_STRUCT); - ret = cp_parser_class_specifier_1 (parser); - timevar_pop (TV_PARSE_STRUCT); - return ret; -} - /* Parse a class-head. class-head: @@ -28737,9 +28727,17 @@ cp_nth_tokens_can_be_attribute_p (cp_parser *parser, size_t n) static tree cp_parser_attributes_opt (cp_parser *parser) { - if (cp_next_tokens_can_be_gnu_attribute_p (parser)) - return cp_parser_gnu_attributes_opt (parser); - return cp_parser_std_attribute_spec_seq (parser); + tree attrs = NULL_TREE; + while (true) + { + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + attrs = attr_chainon (attrs, cp_parser_gnu_attributes_opt (parser)); + else if (cp_next_tokens_can_be_std_attribute_p (parser)) + attrs = attr_chainon (attrs, cp_parser_std_attribute_spec_seq (parser)); + else + break; + } + return attrs; } /* Parse an (optional) series of attributes. @@ -31276,15 +31274,10 @@ cp_parser_function_definition_from_specifiers_and_declarator } else { - timevar_id_t tv; - if (DECL_DECLARED_INLINE_P (current_function_decl)) - tv = TV_PARSE_INLINE; - else - tv = TV_PARSE_FUNC; - timevar_push (tv); + auto_timevar tv (DECL_DECLARED_INLINE_P (current_function_decl) + ? TV_PARSE_INLINE : TV_PARSE_FUNC); fn = cp_parser_function_definition_after_declarator (parser, /*inline_p=*/false); - timevar_pop (tv); } return fn; @@ -32276,7 +32269,8 @@ cp_parser_enclosed_template_argument_list (cp_parser* parser) static void cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) { - timevar_push (TV_PARSE_INMETH); + auto_timevar tv (TV_PARSE_INMETH); + /* If this member is a template, get the underlying FUNCTION_DECL. */ if (DECL_FUNCTION_TEMPLATE_P (member_function)) @@ -32346,7 +32340,6 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function) /* Restore the queue. */ pop_unparsed_function_queues (parser); - timevar_pop (TV_PARSE_INMETH); } /* If DECL contains any default args, remember it on the unparsed @@ -43747,7 +43740,9 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) #define OMP_SCOPE_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static tree diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f1f0805..59b9431 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -184,6 +184,7 @@ static int unify_pack_expansion (tree, tree, tree, tree, unification_kind_t, bool, bool); static tree copy_template_args (tree); static tree tsubst_template_parms (tree, tree, tsubst_flags_t); +static void tsubst_each_template_parm_constraints (tree, tree, tsubst_flags_t); tree most_specialized_partial_spec (tree, tsubst_flags_t); static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int); static tree tsubst_arg_types (tree, tree, tree, tsubst_flags_t, tree); @@ -2323,8 +2324,8 @@ determine_specialization (tree template_id, if (!compparms (fn_arg_types, decl_arg_types)) continue; - tree freq = get_trailing_function_requirements (fn); - tree dreq = get_trailing_function_requirements (decl); + tree freq = get_constraints (fn); + tree dreq = get_constraints (decl); if (!freq != !dreq) continue; if (freq) @@ -2333,7 +2334,7 @@ determine_specialization (tree template_id, constraint-expression. */ tree fargs = DECL_TI_ARGS (fn); tsubst_flags_t complain = tf_none; - freq = tsubst_constraint (freq, fargs, complain, fn); + freq = tsubst_constraint_info (freq, fargs, complain, fn); if (!cp_tree_equal (freq, dreq)) continue; } @@ -9367,27 +9368,25 @@ template_args_equal (tree ot, tree nt, bool partial_order /* = false */) } } -/* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of - template arguments. Returns 0 otherwise, and updates OLDARG_PTR and +/* Returns true iff the OLDARGS and NEWARGS are in fact identical sets of + template arguments. Returns false otherwise, and updates OLDARG_PTR and NEWARG_PTR with the offending arguments if they are non-NULL. */ -int +bool comp_template_args (tree oldargs, tree newargs, - tree *oldarg_ptr, tree *newarg_ptr, - bool partial_order) + tree *oldarg_ptr /* = NULL */, tree *newarg_ptr /* = NULL */, + bool partial_order /* = false */) { - int i; - if (oldargs == newargs) - return 1; + return true; if (!oldargs || !newargs) - return 0; + return false; if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs)) - return 0; + return false; - for (i = 0; i < TREE_VEC_LENGTH (oldargs); ++i) + for (int i = 0; i < TREE_VEC_LENGTH (oldargs); ++i) { tree nt = TREE_VEC_ELT (newargs, i); tree ot = TREE_VEC_ELT (oldargs, i); @@ -9398,10 +9397,10 @@ comp_template_args (tree oldargs, tree newargs, *oldarg_ptr = ot; if (newarg_ptr != NULL) *newarg_ptr = nt; - return 0; + return false; } } - return 1; + return true; } inline bool @@ -9814,10 +9813,12 @@ maybe_get_template_decl_from_type_decl (tree decl) that we want to avoid. It also causes some problems with argument coercion (see convert_nontype_argument for more information on this). */ -static tree -lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, - int entering_scope, tsubst_flags_t complain) +tree +lookup_template_class (tree d1, tree arglist, tree in_decl, tree context, + int entering_scope, tsubst_flags_t complain) { + auto_timevar tv (TV_TEMPLATE_INST); + tree templ = NULL_TREE, parmlist; tree t; spec_entry **slot; @@ -10355,20 +10356,6 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, } } -/* Wrapper for lookup_template_class_1. */ - -tree -lookup_template_class (tree d1, tree arglist, tree in_decl, tree context, - int entering_scope, tsubst_flags_t complain) -{ - tree ret; - timevar_push (TV_TEMPLATE_INST); - ret = lookup_template_class_1 (d1, arglist, in_decl, context, - entering_scope, complain); - timevar_pop (TV_TEMPLATE_INST); - return ret; -} - /* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. */ tree @@ -10575,11 +10562,14 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) case VAR_DECL: if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)) WALK_SUBTREE (DECL_TI_ARGS (t)); - /* Fall through. */ + break; case PARM_DECL: + WALK_SUBTREE (TREE_TYPE (t)); + break; + case CONST_DECL: - if (TREE_CODE (t) == CONST_DECL && DECL_TEMPLATE_PARM_P (t)) + if (DECL_TEMPLATE_PARM_P (t)) WALK_SUBTREE (DECL_INITIAL (t)); if (DECL_CONTEXT (t) && pfd->include_nondeduced_p) @@ -10838,9 +10828,6 @@ any_template_parm_r (tree t, void *data) break; case TEMPLATE_PARM_INDEX: - case PARM_DECL: - /* A parameter or constraint variable may also depend on a template - parameter without explicitly naming it. */ WALK_SUBTREE (TREE_TYPE (t)); break; @@ -11254,7 +11241,13 @@ tsubst_friend_function (tree decl, tree args) tree parms = DECL_TEMPLATE_PARMS (new_friend); tree treqs = TEMPLATE_PARMS_CONSTRAINTS (parms); treqs = maybe_substitute_reqs_for (treqs, new_friend); - TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs; + if (treqs != TEMPLATE_PARMS_CONSTRAINTS (parms)) + { + TEMPLATE_PARMS_CONSTRAINTS (parms) = treqs; + /* As well as each TEMPLATE_PARM_CONSTRAINTS. */ + tsubst_each_template_parm_constraints (parms, args, + tf_warning_or_error); + } } /* The mangled name for the NEW_FRIEND is incorrect. The function @@ -11500,6 +11493,8 @@ tsubst_friend_class (tree friend_tmpl, tree args) { tree parms = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend_tmpl), args, tf_warning_or_error); + tsubst_each_template_parm_constraints (parms, args, + tf_warning_or_error); location_t saved_input_location = input_location; input_location = DECL_SOURCE_LOCATION (friend_tmpl); tree cons = get_constraints (tmpl); @@ -11534,6 +11529,8 @@ tsubst_friend_class (tree friend_tmpl, tree args) DECL_FRIEND_CONTEXT (friend_tmpl)); --processing_template_decl; set_constraints (tmpl, ci); + tsubst_each_template_parm_constraints (DECL_TEMPLATE_PARMS (tmpl), + args, tf_warning_or_error); } /* Inject this template into the enclosing namspace scope. */ @@ -11873,9 +11870,11 @@ perform_instantiation_time_access_checks (tree tmpl, tree targs) } } -static tree -instantiate_class_template_1 (tree type) +tree +instantiate_class_template (tree type) { + auto_timevar tv (TV_TEMPLATE_INST); + tree templ, args, pattern, t, member; tree typedecl; tree pbinfo; @@ -12397,18 +12396,6 @@ instantiate_class_template_1 (tree type) return type; } -/* Wrapper for instantiate_class_template_1. */ - -tree -instantiate_class_template (tree type) -{ - tree ret; - timevar_push (TV_TEMPLATE_INST); - ret = instantiate_class_template_1 (type); - timevar_pop (TV_TEMPLATE_INST); - return ret; -} - tree tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl) { @@ -13656,7 +13643,6 @@ tsubst_template_parm (tree t, tree args, tsubst_flags_t complain) default_value = TREE_PURPOSE (t); parm_decl = TREE_VALUE (t); - tree constraint = TEMPLATE_PARM_CONSTRAINTS (t); parm_decl = tsubst (parm_decl, args, complain, NULL_TREE); if (TREE_CODE (parm_decl) == PARM_DECL @@ -13664,13 +13650,31 @@ tsubst_template_parm (tree t, tree args, tsubst_flags_t complain) parm_decl = error_mark_node; default_value = tsubst_template_arg (default_value, args, complain, NULL_TREE); - constraint = tsubst_constraint (constraint, args, complain, NULL_TREE); tree r = build_tree_list (default_value, parm_decl); - TEMPLATE_PARM_CONSTRAINTS (r) = constraint; + TEMPLATE_PARM_CONSTRAINTS (r) = TEMPLATE_PARM_CONSTRAINTS (t); return r; } +/* Substitute in-place the TEMPLATE_PARM_CONSTRAINTS of each template + parameter in PARMS for sake of declaration matching. */ + +static void +tsubst_each_template_parm_constraints (tree parms, tree args, + tsubst_flags_t complain) +{ + ++processing_template_decl; + for (; parms; parms = TREE_CHAIN (parms)) + { + tree level = TREE_VALUE (parms); + for (tree parm : tree_vec_range (level)) + TEMPLATE_PARM_CONSTRAINTS (parm) + = tsubst_constraint (TEMPLATE_PARM_CONSTRAINTS (parm), args, + complain, NULL_TREE); + } + --processing_template_decl; +} + /* Substitute the ARGS into the indicated aggregate (or enumeration) type T. If T is not an aggregate or enumeration type, it is handled as if by tsubst. IN_DECL is as for tsubst. If @@ -13742,7 +13746,7 @@ tsubst_aggr_type (tree t, { r = lookup_template_class (t, argvec, in_decl, context, entering_scope, complain); - r = cp_build_qualified_type_real (r, cp_type_quals (t), complain); + r = cp_build_qualified_type (r, cp_type_quals (t), complain); } return r; @@ -13938,7 +13942,7 @@ rebuild_function_or_method_type (tree t, tree return_type, tree arg_types, { tree r = TREE_TYPE (TREE_VALUE (arg_types)); /* Don't pick up extra function qualifiers from the basetype. */ - r = cp_build_qualified_type_real (r, type_memfn_quals (t), complain); + r = cp_build_qualified_type (r, type_memfn_quals (t), complain); if (! MAYBE_CLASS_TYPE_P (r)) { /* [temp.deduct] @@ -15626,7 +15630,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (r) { r = TREE_TYPE (r); - r = cp_build_qualified_type_real + r = cp_build_qualified_type (r, cp_type_quals (t) | cp_type_quals (r), complain | tf_ignore_bad_quals); return r; @@ -15636,8 +15640,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) /* We don't have an instantiation yet, so drop the typedef. */ int quals = cp_type_quals (t); t = DECL_ORIGINAL_TYPE (decl); - t = cp_build_qualified_type_real (t, quals, - complain | tf_ignore_bad_quals); + t = cp_build_qualified_type (t, quals, + complain | tf_ignore_bad_quals); } } @@ -15784,7 +15788,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) quals = cp_type_quals (arg) | cp_type_quals (t); - return cp_build_qualified_type_real + return cp_build_qualified_type (arg, quals, complain | tf_ignore_bad_quals); } else if (code == BOUND_TEMPLATE_TEMPLATE_PARM) @@ -15849,7 +15853,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) DECL_CONTEXT (arg), /*entering_scope=*/0, complain); - return cp_build_qualified_type_real + return cp_build_qualified_type (r, cp_type_quals (t) | cp_type_quals (r), complain); } else if (code == TEMPLATE_TEMPLATE_PARM) @@ -15884,7 +15888,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (cp_type_quals (t)) { r = tsubst (TYPE_MAIN_VARIANT (t), args, complain, in_decl); - r = cp_build_qualified_type_real + r = cp_build_qualified_type (r, cp_type_quals (t), complain | (code == TEMPLATE_TYPE_PARM ? tf_ignore_bad_quals : 0)); @@ -16054,7 +16058,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) TYPE_REF_IS_RVALUE (t) && TYPE_REF_IS_RVALUE (type)); else r = cp_build_reference_type (type, TYPE_REF_IS_RVALUE (t)); - r = cp_build_qualified_type_real (r, cp_type_quals (t), complain); + r = cp_build_qualified_type (r, cp_type_quals (t), complain); if (r != error_mark_node) /* Will this ever be needed for TYPE_..._TO values? */ @@ -16100,13 +16104,13 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) = build_memfn_type (type, r, type_memfn_quals (type), type_memfn_rqual (type)); memptr = build_ptrmemfunc_type (build_pointer_type (method_type)); - return cp_build_qualified_type_real (memptr, cp_type_quals (t), - complain); + return cp_build_qualified_type (memptr, cp_type_quals (t), + complain); } else - return cp_build_qualified_type_real (build_ptrmem_type (r, type), - cp_type_quals (t), - complain); + return cp_build_qualified_type (build_ptrmem_type (r, type), + cp_type_quals (t), + complain); } case FUNCTION_TYPE: case METHOD_TYPE: @@ -16257,7 +16261,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) } } - return cp_build_qualified_type_real + return cp_build_qualified_type (f, cp_type_quals (f) | cp_type_quals (t), complain); } @@ -16291,10 +16295,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) --c_inhibit_evaluation_warnings; type = finish_typeof (type); - return cp_build_qualified_type_real (type, - cp_type_quals (t) - | cp_type_quals (type), - complain); + return cp_build_qualified_type (type, + cp_type_quals (t) + | cp_type_quals (type), + complain); } case DECLTYPE_TYPE: @@ -16330,10 +16334,10 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) id = false; type = finish_decltype_type (type, id, complain); } - return cp_build_qualified_type_real (type, - cp_type_quals (t) - | cp_type_quals (type), - complain | tf_ignore_bad_quals); + return cp_build_qualified_type (type, + cp_type_quals (t) + | cp_type_quals (type), + complain | tf_ignore_bad_quals); } case UNDERLYING_TYPE: @@ -16833,8 +16837,8 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain, decl = maybe_dependent_member_ref (decl, args, complain, in_decl); if (!decl) return NULL_TREE; - return cp_build_qualified_type_real (TREE_TYPE (decl), cp_type_quals (t), - complain); + return cp_build_qualified_type (TREE_TYPE (decl), cp_type_quals (t), + complain); } tree name = DECL_NAME (t); @@ -21547,9 +21551,11 @@ recheck_decl_substitution (tree d, tree tmpl, tree args) /* Instantiate the indicated variable, function, or alias template TMPL with the template arguments in TARG_PTR. */ -static tree -instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) +tree +instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) { + auto_timevar tv (TV_TEMPLATE_INST); + tree targ_ptr = orig_args; tree fndecl; tree gen_tmpl; @@ -21721,18 +21727,6 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) return fndecl; } -/* Wrapper for instantiate_template_1. */ - -tree -instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) -{ - tree ret; - timevar_push (TV_TEMPLATE_INST); - ret = instantiate_template_1 (tmpl, orig_args, complain); - timevar_pop (TV_TEMPLATE_INST); - return ret; -} - /* Instantiate the alias template TMPL with ARGS. Also push a template instantiation level, which instantiate_template doesn't do because functions and variables have sufficient context established by the @@ -22658,10 +22652,6 @@ unify_one_argument (tree tparms, tree targs, tree parm, tree arg, return unify_success (explain_p); } - /* Force auto deduction now. Use tf_none to avoid redundant - deprecated warning on deprecated-14.C. */ - mark_single_function (arg, tf_none); - arg_expr = arg; arg = unlowered_expr_type (arg); if (arg == error_mark_node) @@ -24206,7 +24196,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, /* Consider the case where ARG is `const volatile int' and PARM is `const T'. Then, T should be `volatile int'. */ - arg = cp_build_qualified_type_real + arg = cp_build_qualified_type (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none); if (arg == error_mark_node) return unify_invalid (explain_p); @@ -26570,7 +26560,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) if (! push_tinst_level (d)) return d; - timevar_push (TV_TEMPLATE_INST); + auto_timevar tv (TV_TEMPLATE_INST); /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern for the instantiation. */ @@ -26736,7 +26726,6 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) } pop_deferring_access_checks (); - timevar_pop (TV_TEMPLATE_INST); pop_tinst_level (); input_location = saved_loc; cp_unevaluated_operand = saved_unevaluated_operand; @@ -27682,6 +27671,14 @@ value_dependent_expression_p (tree expression) under instantiate_non_dependent_expr; it can't be constant. */ return true; + case NEW_EXPR: + case VEC_NEW_EXPR: + /* The second operand is a type, which type_dependent_expression_p + (and therefore value_dependent_expression_p) doesn't want to see. */ + return (value_dependent_expression_p (TREE_OPERAND (expression, 0)) + || value_dependent_expression_p (TREE_OPERAND (expression, 2)) + || value_dependent_expression_p (TREE_OPERAND (expression, 3))); + default: /* A constant expression is value-dependent if any subexpression is value-dependent. */ @@ -27734,6 +27731,8 @@ type_dependent_expression_p (tree expression) if (expression == NULL_TREE || expression == error_mark_node) return false; + gcc_checking_assert (!TYPE_P (expression)); + STRIP_ANY_LOCATION_WRAPPER (expression); /* An unresolved name is always dependent. */ diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cdc91a3..3600d27 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -3387,8 +3387,7 @@ finish_template_template_parm (tree aggr, tree identifier) /* Associate the constraints with the underlying declaration, not the template. */ - tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); - tree constr = build_constraints (reqs, NULL_TREE); + tree constr = current_template_constraints (); set_constraints (decl, constr); end_template_decl (); @@ -4139,6 +4138,15 @@ finish_id_expression_1 (tree id_expression, } return r; } + else if (TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE) + { + gcc_checking_assert (scope); + *idk = CP_ID_KIND_QUALIFIED; + cp_warn_deprecated_use_scopes (scope); + decl = finish_qualified_id_expr (scope, decl, done, address_p, + template_p, template_arg_p, + tf_warning_or_error); + } else { bool dependent_p = type_dependent_expression_p (decl); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 0916279..c678e3b 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -1359,9 +1359,8 @@ c_build_qualified_type (tree type, int type_quals, tree /* orig_qual_type */, in a similar manner for restricting non-pointer types. */ tree -cp_build_qualified_type_real (tree type, - int type_quals, - tsubst_flags_t complain) +cp_build_qualified_type (tree type, int type_quals, + tsubst_flags_t complain /* = tf_warning_or_error */) { tree result; int bad_quals = TYPE_UNQUALIFIED; @@ -1378,9 +1377,7 @@ cp_build_qualified_type_real (tree type, type. Obtain the appropriately qualified element type. */ tree t; tree element_type - = cp_build_qualified_type_real (TREE_TYPE (type), - type_quals, - complain); + = cp_build_qualified_type (TREE_TYPE (type), type_quals, complain); if (element_type == error_mark_node) return error_mark_node; @@ -1431,7 +1428,7 @@ cp_build_qualified_type_real (tree type, { tree t = PACK_EXPANSION_PATTERN (type); - t = cp_build_qualified_type_real (t, type_quals, complain); + t = cp_build_qualified_type (t, type_quals, complain); return make_pack_expansion (t, complain); } @@ -4322,15 +4319,31 @@ maybe_dummy_object (tree type, tree* binfop) if (binfop) *binfop = binfo; - if (current_class_ref - /* current_class_ref might not correspond to current_class_type if - we're in tsubst_default_argument or a lambda-declarator; in either - case, we want to use current_class_ref if it matches CONTEXT. */ - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (current_class_ref), context))) + /* current_class_ref might not correspond to current_class_type if + we're in tsubst_default_argument or a lambda-declarator; in either + case, we want to use current_class_ref if it matches CONTEXT. */ + tree ctype = current_class_ref ? TREE_TYPE (current_class_ref) : NULL_TREE; + if (ctype + && same_type_ignoring_top_level_qualifiers_p (ctype, context)) decl = current_class_ref; else - decl = build_dummy_object (context); + { + /* Return a dummy object whose cv-quals are consistent with (the + non-lambda) 'this' if available. */ + if (ctype) + { + int quals = TYPE_UNQUALIFIED; + if (tree lambda = CLASSTYPE_LAMBDA_EXPR (ctype)) + { + if (tree cap = lambda_expr_this_capture (lambda, false)) + quals = cp_type_quals (TREE_TYPE (TREE_TYPE (cap))); + } + else + quals = cp_type_quals (ctype); + context = cp_build_qualified_type (context, quals); + } + decl = build_dummy_object (context); + } return decl; } diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 190d710..f9ce14f 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -4939,7 +4939,7 @@ cp_build_binary_op (const op_location_t &location, convert it to this type. */ tree final_type = 0; - tree result, result_ovl; + tree result; /* Nonzero if this is an operation like MIN or MAX which can safely be computed in short if both args are promoted shorts. @@ -6263,25 +6263,29 @@ cp_build_binary_op (const op_location_t &location, result = build2 (COMPOUND_EXPR, TREE_TYPE (result), instrument_expr, result); - if (!processing_template_decl) + if (resultcode == SPACESHIP_EXPR && !processing_template_decl) + result = get_target_expr_sfinae (result, complain); + + if (!c_inhibit_evaluation_warnings) { - if (resultcode == SPACESHIP_EXPR) - result = get_target_expr_sfinae (result, complain); - op0 = cp_fully_fold (op0); - /* Only consider the second argument if the first isn't overflowed. */ - if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0)) - return result; - op1 = cp_fully_fold (op1); - if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1)) + if (!processing_template_decl) + { + op0 = cp_fully_fold (op0); + /* Only consider the second argument if the first isn't overflowed. */ + if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0)) + return result; + op1 = cp_fully_fold (op1); + if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1)) + return result; + } + else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1) + || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1)) return result; - } - else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1) - || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1)) - return result; - result_ovl = fold_build2 (resultcode, build_type, op0, op1); - if (TREE_OVERFLOW_P (result_ovl)) - overflow_warning (location, result_ovl); + tree result_ovl = fold_build2 (resultcode, build_type, op0, op1); + if (TREE_OVERFLOW_P (result_ovl)) + overflow_warning (location, result_ovl); + } return result; } diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index a629a4d..99e1089 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,18 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * d-lang.cc (d_get_sarif_source_language): New. + (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (d.tags): Just look at *.cc. + +2022-05-31 Iain Buclaw <ibuclaw@gdcproject.org> + + PR d/105544 + * d-lang.cc (d_parse_file): Zero padding past the end of the stdin + buffer so the D lexer has a sentinel to stop parsing at. + 2022-05-27 Iain Buclaw <ibuclaw@gdcproject.org> * dmd/MERGE: Merge upstream dmd 4d07f22f2 diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index f3e34c5..9f13437 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -279,7 +279,7 @@ d.srcextra: d.tags: force cd $(srcdir)/d; \ - $(ETAGS) -o TAGS.sub *.c *.cc *.h dmd/*.h dmd/root/*.h; \ + $(ETAGS) -o TAGS.sub *.cc *.h dmd/*.h dmd/root/*.h; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub d.man: doc/gdc.1 diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index ef0fe0b..6e4350f 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1077,6 +1077,10 @@ d_parse_file (void) global.params.dihdr.doOutput); modules.push (m); + /* Zero the padding past the end of the buffer so the D lexer has a + sentinel. The lexer only reads up to 4 bytes at a time. */ + memset (buffer + len, '\0', 16); + /* Overwrite the source file for the module, the one created by Module::create would have a forced a `.d' suffix. */ m->src.length = len; @@ -1929,6 +1933,15 @@ d_enum_underlying_base_type (const_tree type) return TREE_TYPE (type); } +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +static const char * +d_get_sarif_source_language (const char *) +{ + return "d"; +} + /* Definitions for our language-specific hooks. */ #undef LANG_HOOKS_NAME @@ -1962,6 +1975,7 @@ d_enum_underlying_base_type (const_tree type) #undef LANG_HOOKS_TYPE_FOR_MODE #undef LANG_HOOKS_TYPE_FOR_SIZE #undef LANG_HOOKS_TYPE_PROMOTES_TO +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE #define LANG_HOOKS_NAME "GNU D" #define LANG_HOOKS_INIT d_init @@ -1994,6 +2008,7 @@ d_enum_underlying_base_type (const_tree type) #define LANG_HOOKS_TYPE_FOR_MODE d_type_for_mode #define LANG_HOOKS_TYPE_FOR_SIZE d_type_for_size #define LANG_HOOKS_TYPE_PROMOTES_TO d_type_promotes_to +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE d_get_sarif_source_language struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/df-core.cc b/gcc/df-core.cc index a901b84..e3a56bf 100644 --- a/gcc/df-core.cc +++ b/gcc/df-core.cc @@ -2009,6 +2009,47 @@ df_reg_used (rtx_insn *insn, rtx reg) return df_find_use (insn, reg) != NULL; } +/* If REG has a single definition, return its known value, otherwise return + null. */ + +rtx +df_find_single_def_src (rtx reg) +{ + rtx src = NULL_RTX; + + /* Don't look through unbounded number of single definition REG copies, + there might be loops for sources with uninitialized variables. */ + for (int cnt = 0; cnt < 128; cnt++) + { + df_ref adef = DF_REG_DEF_CHAIN (REGNO (reg)); + if (adef == NULL || DF_REF_NEXT_REG (adef) != NULL + || DF_REF_IS_ARTIFICIAL (adef) + || (DF_REF_FLAGS (adef) + & (DF_REF_PARTIAL | DF_REF_CONDITIONAL))) + return NULL_RTX; + + rtx set = single_set (DF_REF_INSN (adef)); + if (set == NULL || !rtx_equal_p (SET_DEST (set), reg)) + return NULL_RTX; + + rtx note = find_reg_equal_equiv_note (DF_REF_INSN (adef)); + if (note && function_invariant_p (XEXP (note, 0))) + return XEXP (note, 0); + src = SET_SRC (set); + + if (REG_P (src)) + { + reg = src; + continue; + } + break; + } + if (!function_invariant_p (src)) + return NULL_RTX; + + return src; +} + /*---------------------------------------------------------------------------- Debugging and printing functions. @@ -991,6 +991,7 @@ extern df_ref df_find_def (rtx_insn *, rtx); extern bool df_reg_defined (rtx_insn *, rtx); extern df_ref df_find_use (rtx_insn *, rtx); extern bool df_reg_used (rtx_insn *, rtx); +extern rtx df_find_single_def_src (rtx); extern void df_worklist_dataflow (struct dataflow *,bitmap, int *, int); extern void df_print_regset (FILE *file, const_bitmap r); extern void df_print_word_regset (FILE *file, const_bitmap r); diff --git a/gcc/diagnostic-client-data-hooks.h b/gcc/diagnostic-client-data-hooks.h new file mode 100644 index 0000000..ba78546 --- /dev/null +++ b/gcc/diagnostic-client-data-hooks.h @@ -0,0 +1,105 @@ +/* Additional metadata about a client for a diagnostic context. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H +#define GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H + +class client_version_info; + +/* A bundle of additional metadata, owned by the diagnostic_context, + for querying things about the client, like version data. */ + +class diagnostic_client_data_hooks +{ + public: + virtual ~diagnostic_client_data_hooks () {} + + /* Get version info for this client, or NULL. */ + virtual const client_version_info *get_any_version_info () const = 0; + + /* Get the current logical_location for this client, or NULL. */ + virtual const logical_location *get_current_logical_location () const = 0; + + /* Get a sourceLanguage value for FILENAME, or return NULL. + See SARIF v2.1.0 Appendix J for suggested values. */ + virtual const char * + maybe_get_sarif_source_language (const char *filename) const = 0; +}; + +/* Factory function for making an instance of diagnostic_client_data_hooks + for use in the compiler (i.e. with knowledge of "tree", access to + langhooks, etc). */ + +extern diagnostic_client_data_hooks *make_compiler_data_hooks (); + +class diagnostic_client_plugin_info; + +/* Abstract base class for a diagnostic_context to get at + version information about the client. */ + +class client_version_info +{ +public: + class plugin_visitor + { + public: + virtual void on_plugin (const diagnostic_client_plugin_info &) = 0; + }; + + virtual ~client_version_info () {} + + /* Get a string suitable for use as the value of the "name" property + (SARIF v2.1.0 section 3.19.8). */ + virtual const char *get_tool_name () const = 0; + + /* Create a string suitable for use as the value of the "fullName" property + (SARIF v2.1.0 section 3.19.9). */ + virtual char *maybe_make_full_name () const = 0; + + /* Get a string suitable for use as the value of the "version" property + (SARIF v2.1.0 section 3.19.13). */ + virtual const char *get_version_string () const = 0; + + /* Create a string suitable for use as the value of the "informationUri" + property (SARIF v2.1.0 section 3.19.17). */ + virtual char *maybe_make_version_url () const = 0; + + virtual void for_each_plugin (plugin_visitor &v) const = 0; +}; + +/* Abstract base class for a diagnostic_context to get at + information about a specific plugin within a client. */ + +class diagnostic_client_plugin_info +{ +public: + /* For use e.g. by SARIF "name" property (SARIF v2.1.0 section 3.19.8). */ + virtual const char *get_short_name () const = 0; + + /* For use e.g. by SARIF "fullName" property + (SARIF v2.1.0 section 3.19.9). */ + virtual const char *get_full_name () const = 0; + + /* For use e.g. by SARIF "version" property + (SARIF v2.1.0 section 3.19.13). */ + virtual const char *get_version () const = 0; +}; + +#endif /* ! GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H */ diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc index 62594eb..051fa6c 100644 --- a/gcc/diagnostic-format-json.cc +++ b/gcc/diagnostic-format-json.cc @@ -285,57 +285,93 @@ json_end_group (diagnostic_context *) cur_children_array = NULL; } -/* Callback for final cleanup for JSON output. */ +/* Flush the top-level array to OUTF. */ static void -json_final_cb (diagnostic_context *) +json_flush_to_file (FILE *outf) { - /* Flush the top-level array. */ - toplevel_array->dump (stderr); - fprintf (stderr, "\n"); + toplevel_array->dump (outf); + fprintf (outf, "\n"); delete toplevel_array; toplevel_array = NULL; } -/* Set the output format for CONTEXT to FORMAT. */ +/* Callback for final cleanup for JSON output to stderr. */ -void -diagnostic_output_format_init (diagnostic_context *context, - enum diagnostics_output_format format) +static void +json_stderr_final_cb (diagnostic_context *) +{ + json_flush_to_file (stderr); +} + +static char *json_output_base_file_name; + +/* Callback for final cleanup for JSON output to a file. */ + +static void +json_file_final_cb (diagnostic_context *) { - switch (format) + char *filename = concat (json_output_base_file_name, ".gcc.json", NULL); + FILE *outf = fopen (filename, "w"); + if (!outf) { - default: - gcc_unreachable (); - case DIAGNOSTICS_OUTPUT_FORMAT_TEXT: - /* The default; do nothing. */ - break; - - case DIAGNOSTICS_OUTPUT_FORMAT_JSON: - { - /* Set up top-level JSON array. */ - if (toplevel_array == NULL) - toplevel_array = new json::array (); - - /* Override callbacks. */ - context->begin_diagnostic = json_begin_diagnostic; - context->end_diagnostic = json_end_diagnostic; - context->begin_group_cb = json_begin_group; - context->end_group_cb = json_end_group; - context->final_cb = json_final_cb; - context->print_path = NULL; /* handled in json_end_diagnostic. */ - - /* The metadata is handled in JSON format, rather than as text. */ - context->show_cwe = false; - - /* The option is handled in JSON format, rather than as text. */ - context->show_option_requested = false; - - /* Don't colorize the text. */ - pp_show_color (context->printer) = false; - } - break; + const char *errstr = xstrerror (errno); + fnotice (stderr, "error: unable to open '%s' for writing: %s\n", + filename, errstr); + free (filename); + return; } + json_flush_to_file (outf); + fclose (outf); + free (filename); +} + +/* Populate CONTEXT in preparation for JSON output (either to stderr, or + to a file). */ + +static void +diagnostic_output_format_init_json (diagnostic_context *context) +{ + /* Set up top-level JSON array. */ + if (toplevel_array == NULL) + toplevel_array = new json::array (); + + /* Override callbacks. */ + context->begin_diagnostic = json_begin_diagnostic; + context->end_diagnostic = json_end_diagnostic; + context->begin_group_cb = json_begin_group; + context->end_group_cb = json_end_group; + context->print_path = NULL; /* handled in json_end_diagnostic. */ + + /* The metadata is handled in JSON format, rather than as text. */ + context->show_cwe = false; + + /* The option is handled in JSON format, rather than as text. */ + context->show_option_requested = false; + + /* Don't colorize the text. */ + pp_show_color (context->printer) = false; +} + +/* Populate CONTEXT in preparation for JSON output to stderr. */ + +void +diagnostic_output_format_init_json_stderr (diagnostic_context *context) +{ + diagnostic_output_format_init_json (context); + context->final_cb = json_stderr_final_cb; +} + +/* Populate CONTEXT in preparation for JSON output to a file named + BASE_FILE_NAME.gcc.json. */ + +void +diagnostic_output_format_init_json_file (diagnostic_context *context, + const char *base_file_name) +{ + diagnostic_output_format_init_json (context); + context->final_cb = json_file_final_cb; + json_output_base_file_name = xstrdup (base_file_name); } #if CHECKING_P diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc new file mode 100644 index 0000000..0c33179 --- /dev/null +++ b/gcc/diagnostic-format-sarif.cc @@ -0,0 +1,1586 @@ +/* SARIF output for diagnostics + Copyright (C) 2018-2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "diagnostic.h" +#include "diagnostic-metadata.h" +#include "diagnostic-path.h" +#include "json.h" +#include "cpplib.h" +#include "logical-location.h" +#include "diagnostic-client-data-hooks.h" + +class sarif_builder; + +/* Subclass of json::object for SARIF result objects + (SARIF v2.1.0 section 3.27. */ + +class sarif_result : public json::object +{ +public: + sarif_result () : m_related_locations_arr (NULL) {} + + void + on_nested_diagnostic (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind, + sarif_builder *builder); + +private: + json::array *m_related_locations_arr; +}; + +/* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr + and -fdiagnostics-format=sarif-file). + + As diagnostics occur, we build "result" JSON objects, and + accumulate state: + - which source files are referenced + - which warnings are emitted + - which CWEs are used + + At the end of the compile, we use the above to build the full SARIF + object tree, adding the result objects to the correct place, and + creating objects for the various source files, warnings and CWEs + referenced. + + Implemented: + - fix-it hints + - CWE metadata + - diagnostic groups (see limitations below) + - logical locations (e.g. cfun) + + Known limitations: + - GCC supports one-deep nesting of diagnostics (via auto_diagnostic_group), + but we only capture location and message information from such nested + diagnostics (e.g. we ignore fix-it hints on them) + - doesn't yet capture command-line arguments: would be run.invocations + property (SARIF v2.1.0 section 3.14.11), as invocation objects + (SARIF v2.1.0 section 3.20), but we'd want to capture the arguments to + toplev::main, and the response files. + - doesn't capture escape_on_output_p + - doesn't capture secondary locations within a rich_location + (perhaps we should use the "relatedLocations" property: SARIF v2.1.0 + section 3.27.22) + - doesn't capture "artifact.encoding" property + (SARIF v2.1.0 section 3.24.9). + - doesn't capture hashes of the source files + ("artifact.hashes" property (SARIF v2.1.0 section 3.24.11). + - doesn't capture the "analysisTarget" property + (SARIF v2.1.0 section 3.27.13). + - doesn't capture labelled ranges + - doesn't capture -Werror cleanly + - doesn't capture inlining information (can SARIF handle this?) + - doesn't capture macro expansion information (can SARIF handle this?). */ + +class sarif_builder +{ +public: + sarif_builder (diagnostic_context *context); + + void end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind); + + void end_group (); + + void flush_to_file (FILE *outf); + + json::object *make_location_object (const rich_location &rich_loc, + const logical_location *logical_loc); + json::object *make_message_object (const char *msg) const; + +private: + sarif_result *make_result_object (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind); + void set_any_logical_locs_arr (json::object *location_obj, + const logical_location *logical_loc); + json::object *make_location_object (const diagnostic_event &event); + json::object * + make_logical_location_object (const logical_location &logical_loc) const; + json::object *make_code_flow_object (const diagnostic_path &path); + json::object *make_thread_flow_object (const diagnostic_path &path); + json::object * + make_thread_flow_location_object (const diagnostic_event &event); + json::array *maybe_make_kinds_array (diagnostic_event::meaning m) const; + json::object *maybe_make_physical_location_object (location_t loc); + json::object *make_artifact_location_object (location_t loc); + json::object *make_artifact_location_object (const char *filename); + json::object *make_artifact_location_object_for_pwd () const; + json::object *maybe_make_region_object (location_t loc) const; + json::object *maybe_make_region_object_for_context (location_t loc) const; + json::object *make_region_object_for_hint (const fixit_hint &hint) const; + json::object *make_multiformat_message_string (const char *msg) const; + json::object *make_top_level_object (json::array *results); + json::object *make_run_object (json::array *results); + json::object *make_tool_object () const; + json::object *make_driver_tool_component_object () const; + json::array *maybe_make_taxonomies_array () const; + json::object *maybe_make_cwe_taxonomy_object () const; + json::object *make_tool_component_reference_object_for_cwe () const; + json::object * + make_reporting_descriptor_object_for_warning (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind, + const char *option_text); + json::object *make_reporting_descriptor_object_for_cwe_id (int cwe_id) const; + json::object * + make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id); + json::object *make_artifact_object (const char *filename); + json::object *maybe_make_artifact_content_object (const char *filename) const; + json::object *maybe_make_artifact_content_object (const char *filename, + int start_line, + int end_line) const; + json::object *make_fix_object (const rich_location &rich_loc); + json::object *make_artifact_change_object (const rich_location &richloc); + json::object *make_replacement_object (const fixit_hint &hint) const; + json::object *make_artifact_content_object (const char *text) const; + int get_sarif_column (expanded_location exploc) const; + + diagnostic_context *m_context; + + /* The JSON array of pending diagnostics. */ + json::array *m_results_array; + + /* The JSON object for the result object (if any) in the current + diagnostic group. */ + sarif_result *m_cur_group_result; + + hash_set <const char *> m_filenames; + bool m_seen_any_relative_paths; + hash_set <free_string_hash> m_rule_id_set; + json::array *m_rules_arr; + + /* The set of all CWE IDs we've seen, if any. */ + hash_set <int_hash <int, 0, 1> > m_cwe_id_set; + + int m_tabstop; +}; + +static sarif_builder *the_builder; + +/* class sarif_result : public json::object. */ + +/* Handle secondary diagnostics that occur within a diagnostic group. + The closest SARIF seems to have to nested diagnostics is the + "relatedLocations" property of result objects (SARIF v2.1.0 section 3.27.22), + so we lazily set this property and populate the array if and when + secondary diagnostics occur (such as notes to a warning). */ + +void +sarif_result::on_nested_diagnostic (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t /*orig_diag_kind*/, + sarif_builder *builder) +{ + if (!m_related_locations_arr) + { + m_related_locations_arr = new json::array (); + set ("relatedLocations", m_related_locations_arr); + } + + /* We don't yet generate meaningful logical locations for notes; + sometimes these will related to current_function_decl, but + often they won't. */ + json::object *location_obj + = builder->make_location_object (*diagnostic->richloc, NULL); + json::object *message_obj + = builder->make_message_object (pp_formatted_text (context->printer)); + pp_clear_output_area (context->printer); + location_obj->set ("message", message_obj); + + m_related_locations_arr->append (location_obj); +} + +/* class sarif_builder. */ + +/* sarif_builder's ctor. */ + +sarif_builder::sarif_builder (diagnostic_context *context) +: m_context (context), + m_results_array (new json::array ()), + m_cur_group_result (NULL), + m_seen_any_relative_paths (false), + m_rule_id_set (), + m_rules_arr (new json::array ()), + m_tabstop (context->tabstop) +{ +} + +/* Implementation of "end_diagnostic" for SARIF output. */ + +void +sarif_builder::end_diagnostic (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind) +{ + + if (m_cur_group_result) + /* Nested diagnostic. */ + m_cur_group_result->on_nested_diagnostic (context, + diagnostic, + orig_diag_kind, + this); + else + { + /* Top-level diagnostic. */ + sarif_result *result_obj + = make_result_object (context, diagnostic, orig_diag_kind); + m_results_array->append (result_obj); + m_cur_group_result = result_obj; + } +} + +/* Implementation of "end_group_cb" for SARIF output. */ + +void +sarif_builder::end_group () +{ + m_cur_group_result = NULL; +} + +/* Create a top-level object, and add it to all the results + (and other entities) we've seen so far. + + Flush it all to OUTF. */ + +void +sarif_builder::flush_to_file (FILE *outf) +{ + json::object *top = make_top_level_object (m_results_array); + top->dump (outf); + m_results_array = NULL; + fprintf (outf, "\n"); + delete top; +} + +/* Attempt to convert DIAG_KIND to a suitable value for the "level" + property (SARIF v2.1.0 section 3.27.10). + + Return NULL if there isn't one. */ + +static const char * +maybe_get_sarif_level (diagnostic_t diag_kind) +{ + switch (diag_kind) + { + case DK_WARNING: + return "warning"; + case DK_ERROR: + return "error"; + case DK_NOTE: + case DK_ANACHRONISM: + return "note"; + default: + return NULL; + } +} + +/* Make a string for DIAG_KIND suitable for use a ruleId + (SARIF v2.1.0 section 3.27.5) as a fallback for when we don't + have anything better to use. */ + +static char * +make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind) +{ + static const char *const diagnostic_kind_text[] = { +#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T), +#include "diagnostic.def" +#undef DEFINE_DIAGNOSTIC_KIND + "must-not-happen" + }; + /* Lose the trailing ": ". */ + const char *kind_text = diagnostic_kind_text[diag_kind]; + size_t len = strlen (kind_text); + gcc_assert (len > 2); + gcc_assert (kind_text[len - 2] == ':'); + gcc_assert (kind_text[len - 1] == ' '); + char *rstrip = xstrdup (kind_text); + rstrip[len - 2] = '\0'; + return rstrip; +} + +/* Make a result object (SARIF v2.1.0 section 3.27) for DIAGNOSTIC. */ + +sarif_result * +sarif_builder::make_result_object (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind) +{ + sarif_result *result_obj = new sarif_result (); + + /* "ruleId" property (SARIF v2.1.0 section 3.27.5). */ + /* Ideally we'd have an option_name for these. */ + if (char *option_text + = context->option_name (context, diagnostic->option_index, + orig_diag_kind, diagnostic->kind)) + { + /* Lazily create reportingDescriptor objects for and add to m_rules_arr. + Set ruleId referencing them. */ + result_obj->set ("ruleId", new json::string (option_text)); + if (m_rule_id_set.contains (option_text)) + free (option_text); + else + { + /* This is the first time we've seen this ruleId. */ + /* Add to set, taking ownership. */ + m_rule_id_set.add (option_text); + + json::object *reporting_desc_obj + = make_reporting_descriptor_object_for_warning (context, + diagnostic, + orig_diag_kind, + option_text); + m_rules_arr->append (reporting_desc_obj); + } + } + else + { + /* Otherwise, we have an "error" or a stray "note"; use the + diagnostic kind as the ruleId, so that the result object at least + has a ruleId. + We don't bother creating reportingDescriptor objects for these. */ + char *rule_id = make_rule_id_for_diagnostic_kind (orig_diag_kind); + result_obj->set ("ruleId", new json::string (rule_id)); + free (rule_id); + } + + /* "taxa" property (SARIF v2.1.0 section 3.27.8). */ + if (diagnostic->metadata) + if (int cwe_id = diagnostic->metadata->get_cwe ()) + { + json::array *taxa_arr = new json::array (); + json::object *cwe_id_obj + = make_reporting_descriptor_reference_object_for_cwe_id (cwe_id); + taxa_arr->append (cwe_id_obj); + result_obj->set ("taxa", taxa_arr); + } + + /* "level" property (SARIF v2.1.0 section 3.27.10). */ + if (const char *sarif_level = maybe_get_sarif_level (diagnostic->kind)) + result_obj->set ("level", new json::string (sarif_level)); + + /* "message" property (SARIF v2.1.0 section 3.27.11). */ + json::object *message_obj + = make_message_object (pp_formatted_text (context->printer)); + pp_clear_output_area (context->printer); + result_obj->set ("message", message_obj); + + /* "locations" property (SARIF v2.1.0 section 3.27.12). */ + json::array *locations_arr = new json::array (); + const logical_location *logical_loc = NULL; + if (m_context->m_client_data_hooks) + logical_loc + = m_context->m_client_data_hooks->get_current_logical_location (); + + json::object *location_obj + = make_location_object (*diagnostic->richloc, logical_loc); + locations_arr->append (location_obj); + result_obj->set ("locations", locations_arr); + + /* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */ + if (const diagnostic_path *path = diagnostic->richloc->get_path ()) + { + json::array *code_flows_arr = new json::array (); + json::object *code_flow_obj = make_code_flow_object (*path); + code_flows_arr->append (code_flow_obj); + result_obj->set ("codeFlows", code_flows_arr); + } + + /* The "relatedLocations" property (SARIF v2.1.0 section 3.27.22) is + set up later, if any nested diagnostics occur within this diagnostic + group. */ + + /* "fixes" property (SARIF v2.1.0 section 3.27.30). */ + const rich_location *richloc = diagnostic->richloc; + if (richloc->get_num_fixit_hints ()) + { + json::array *fix_arr = new json::array (); + json::object *fix_obj = make_fix_object (*richloc); + fix_arr->append (fix_obj); + result_obj->set ("fixes", fix_arr); + } + + return result_obj; +} + +/* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49) + for a GCC warning. */ + +json::object * +sarif_builder:: +make_reporting_descriptor_object_for_warning (diagnostic_context *context, + diagnostic_info *diagnostic, + diagnostic_t /*orig_diag_kind*/, + const char *option_text) +{ + json::object *reporting_desc = new json::object (); + + /* "id" property (SARIF v2.1.0 section 3.49.3). */ + reporting_desc->set ("id", new json::string (option_text)); + + /* We don't implement "name" property (SARIF v2.1.0 section 3.49.7), since + it seems redundant compared to "id". */ + + /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */ + if (context->get_option_url) + { + char *option_url + = context->get_option_url (context, diagnostic->option_index); + if (option_url) + { + reporting_desc->set ("helpUri", new json::string (option_url)); + free (option_url); + } + } + + return reporting_desc; +} + +/* Make a reportingDescriptor object (SARIF v2.1.0 section 3.49) + for CWE_ID, for use within the CWE taxa array. */ + +json::object * +sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id) const +{ + json::object *reporting_desc = new json::object (); + + /* "id" property (SARIF v2.1.0 section 3.49.3). */ + { + pretty_printer pp; + pp_printf (&pp, "%i", cwe_id); + reporting_desc->set ("id", new json::string (pp_formatted_text (&pp))); + } + + /* "helpUri" property (SARIF v2.1.0 section 3.49.12). */ + { + char *url = get_cwe_url (cwe_id); + reporting_desc->set ("helpUri", new json::string (url)); + free (url); + } + + return reporting_desc; +} + +/* Make a reportingDescriptorReference object (SARIF v2.1.0 section 3.52) + referencing CWE_ID, for use within a result object. + Also, add CWE_ID to m_cwe_id_set. */ + +json::object * +sarif_builder:: +make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id) +{ + json::object *desc_ref_obj = new json::object (); + + /* "id" property (SARIF v2.1.0 section 3.52.4). */ + { + pretty_printer pp; + pp_printf (&pp, "%i", cwe_id); + desc_ref_obj->set ("id", new json::string (pp_formatted_text (&pp))); + } + + /* "toolComponent" property (SARIF v2.1.0 section 3.52.7). */ + json::object *comp_ref_obj = make_tool_component_reference_object_for_cwe (); + desc_ref_obj->set ("toolComponent", comp_ref_obj); + + /* Add CWE_ID to our set. */ + gcc_assert (cwe_id > 0); + m_cwe_id_set.add (cwe_id); + + return desc_ref_obj; +} + +/* Make a toolComponentReference object (SARIF v2.1.0 section 3.54) that + references the CWE taxonomy. */ + +json::object * +sarif_builder:: +make_tool_component_reference_object_for_cwe () const +{ + json::object *comp_ref_obj = new json::object (); + + /* "name" property (SARIF v2.1.0 section 3.54.3). */ + comp_ref_obj->set ("name", new json::string ("cwe")); + + return comp_ref_obj; +} + +/* If LOGICAL_LOC is non-NULL, use it to create a "logicalLocations" property + within LOCATION_OBJ (SARIF v2.1.0 section 3.28.4). */ + +void +sarif_builder:: +set_any_logical_locs_arr (json::object *location_obj, + const logical_location *logical_loc) +{ + if (!logical_loc) + return; + json::object *logical_loc_obj = make_logical_location_object (*logical_loc); + json::array *location_locs_arr = new json::array (); + location_locs_arr->append (logical_loc_obj); + location_obj->set ("logicalLocations", location_locs_arr); +} + +/* Make a location object (SARIF v2.1.0 section 3.28) for RICH_LOC + and LOGICAL_LOC. */ + +json::object * +sarif_builder::make_location_object (const rich_location &rich_loc, + const logical_location *logical_loc) +{ + json::object *location_obj = new json::object (); + + /* Get primary loc from RICH_LOC. */ + location_t loc = rich_loc.get_loc (); + + /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */ + if (json::object *phs_loc_obj = maybe_make_physical_location_object (loc)) + location_obj->set ("physicalLocation", phs_loc_obj); + + /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */ + set_any_logical_locs_arr (location_obj, logical_loc); + + return location_obj; +} + +/* Make a location object (SARIF v2.1.0 section 3.28) for EVENT + within a diagnostic_path. */ + +json::object * +sarif_builder::make_location_object (const diagnostic_event &event) +{ + json::object *location_obj = new json::object (); + + /* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */ + location_t loc = event.get_location (); + if (json::object *phs_loc_obj = maybe_make_physical_location_object (loc)) + location_obj->set ("physicalLocation", phs_loc_obj); + + /* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */ + const logical_location *logical_loc = event.get_logical_location (); + set_any_logical_locs_arr (location_obj, logical_loc); + + /* "message" property (SARIF v2.1.0 section 3.28.5). */ + label_text ev_desc = event.get_desc (false); + json::object *message_obj = make_message_object (ev_desc.m_buffer); + location_obj->set ("message", message_obj); + ev_desc.maybe_free (); + + return location_obj; +} + +/* Make a physicalLocation object (SARIF v2.1.0 section 3.29) for LOC, + or return NULL; + Add any filename to the m_artifacts. */ + +json::object * +sarif_builder::maybe_make_physical_location_object (location_t loc) +{ + if (loc <= BUILTINS_LOCATION) + return NULL; + + json::object *phys_loc_obj = new json::object (); + + /* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */ + json::object *artifact_loc_obj = make_artifact_location_object (loc); + phys_loc_obj->set ("artifactLocation", artifact_loc_obj); + m_filenames.add (LOCATION_FILE (loc)); + + /* "region" property (SARIF v2.1.0 section 3.29.4). */ + if (json::object *region_obj = maybe_make_region_object (loc)) + phys_loc_obj->set ("region", region_obj); + + /* "contextRegion" property (SARIF v2.1.0 section 3.29.5). */ + if (json::object *context_region_obj + = maybe_make_region_object_for_context (loc)) + phys_loc_obj->set ("contextRegion", context_region_obj); + + /* Instead, we add artifacts to the run as a whole, + with artifact.contents. + Could do both, though. */ + + return phys_loc_obj; +} + +/* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for LOC, + or return NULL. */ + +json::object * +sarif_builder::make_artifact_location_object (location_t loc) +{ + return make_artifact_location_object (LOCATION_FILE (loc)); +} + +/* The ID value for use in "uriBaseId" properties (SARIF v2.1.0 section 3.4.4) + for when we need to express paths relative to PWD. */ + +#define PWD_PROPERTY_NAME ("PWD") + +/* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for FILENAME, + or return NULL. */ + +json::object * +sarif_builder::make_artifact_location_object (const char *filename) +{ + json::object *artifact_loc_obj = new json::object (); + + /* "uri" property (SARIF v2.1.0 section 3.4.3). */ + artifact_loc_obj->set ("uri", new json::string (filename)); + + if (filename[0] != '/') + { + /* If we have a relative path, set the "uriBaseId" property + (SARIF v2.1.0 section 3.4.4). */ + artifact_loc_obj->set ("uriBaseId", new json::string (PWD_PROPERTY_NAME)); + m_seen_any_relative_paths = true; + } + + return artifact_loc_obj; +} + +/* Get the PWD, or NULL, as an absolute file-based URI, + adding a trailing forward slash (as required by SARIF v2.1.0 + section 3.14.14). */ + +static char * +make_pwd_uri_str () +{ + /* The prefix of a file-based URI, up to, but not including the path. */ +#define FILE_PREFIX ("file://") + + const char *pwd = getpwd (); + if (!pwd) + return NULL; + size_t len = strlen (pwd); + if (len == 0 || pwd[len - 1] != '/') + return concat (FILE_PREFIX, pwd, "/", NULL); + else + { + gcc_assert (pwd[len - 1] == '/'); + return concat (FILE_PREFIX, pwd, NULL); + } +} + +/* Make an artifactLocation object (SARIF v2.1.0 section 3.4) for the pwd, + for use in the "run.originalUriBaseIds" property (SARIF v2.1.0 + section 3.14.14) when we have any relative paths. */ + +json::object * +sarif_builder::make_artifact_location_object_for_pwd () const +{ + json::object *artifact_loc_obj = new json::object (); + + /* "uri" property (SARIF v2.1.0 section 3.4.3). */ + if (char *pwd = make_pwd_uri_str ()) + { + gcc_assert (strlen (pwd) > 0); + gcc_assert (pwd[strlen (pwd) - 1] == '/'); + artifact_loc_obj->set ("uri", new json::string (pwd)); + free (pwd); + } + + return artifact_loc_obj; +} + +/* Get the column number within EXPLOC. */ + +int +sarif_builder::get_sarif_column (expanded_location exploc) const +{ + cpp_char_column_policy policy (m_tabstop, cpp_wcwidth); + return location_compute_display_column (exploc, policy); +} + +/* Make a region object (SARIF v2.1.0 section 3.30) for LOC, + or return NULL. */ + +json::object * +sarif_builder::maybe_make_region_object (location_t loc) const +{ + location_t caret_loc = get_pure_location (loc); + + if (caret_loc <= BUILTINS_LOCATION) + return NULL; + + location_t start_loc = get_start (loc); + location_t finish_loc = get_finish (loc); + + expanded_location exploc_caret = expand_location (caret_loc); + expanded_location exploc_start = expand_location (start_loc); + expanded_location exploc_finish = expand_location (finish_loc); + + if (exploc_start.file !=exploc_caret.file) + return NULL; + if (exploc_finish.file !=exploc_caret.file) + return NULL; + + json::object *region_obj = new json::object (); + + /* "startLine" property (SARIF v2.1.0 section 3.30.5) */ + region_obj->set ("startLine", new json::integer_number (exploc_start.line)); + + /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */ + region_obj->set ("startColumn", + new json::integer_number (get_sarif_column (exploc_start))); + + /* "endLine" property (SARIF v2.1.0 section 3.30.7) */ + if (exploc_finish.line != exploc_start.line) + region_obj->set ("endLine", new json::integer_number (exploc_finish.line)); + + /* "endColumn" property (SARIF v2.1.0 section 3.30.8). + This expresses the column immediately beyond the range. */ + { + int next_column = sarif_builder::get_sarif_column (exploc_finish) + 1; + region_obj->set ("endColumn", new json::integer_number (next_column)); + } + + return region_obj; +} + +/* Make a region object (SARIF v2.1.0 section 3.30) for the "contextRegion" + property (SARIF v2.1.0 section 3.29.5) of a physicalLocation. + + This is similar to maybe_make_region_object, but ignores column numbers, + covering the line(s) as a whole, and including a "snippet" property + embedding those source lines, making it easier for consumers to show + the pertinent source. */ + +json::object * +sarif_builder::maybe_make_region_object_for_context (location_t loc) const +{ + location_t caret_loc = get_pure_location (loc); + + if (caret_loc <= BUILTINS_LOCATION) + return NULL; + + location_t start_loc = get_start (loc); + location_t finish_loc = get_finish (loc); + + expanded_location exploc_caret = expand_location (caret_loc); + expanded_location exploc_start = expand_location (start_loc); + expanded_location exploc_finish = expand_location (finish_loc); + + if (exploc_start.file !=exploc_caret.file) + return NULL; + if (exploc_finish.file !=exploc_caret.file) + return NULL; + + json::object *region_obj = new json::object (); + + /* "startLine" property (SARIF v2.1.0 section 3.30.5) */ + region_obj->set ("startLine", new json::integer_number (exploc_start.line)); + + /* "endLine" property (SARIF v2.1.0 section 3.30.7) */ + if (exploc_finish.line != exploc_start.line) + region_obj->set ("endLine", new json::integer_number (exploc_finish.line)); + + /* "snippet" property (SARIF v2.1.0 section 3.30.13). */ + if (json::object *artifact_content_obj + = maybe_make_artifact_content_object (exploc_start.file, + exploc_start.line, + exploc_finish.line)) + region_obj->set ("snippet", artifact_content_obj); + + return region_obj; +} + +/* Make a region object (SARIF v2.1.0 section 3.30) for the deletion region + of HINT (as per SARIF v2.1.0 section 3.57.3). */ + +json::object * +sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const +{ + location_t start_loc = hint.get_start_loc (); + location_t next_loc = hint.get_next_loc (); + + expanded_location exploc_start = expand_location (start_loc); + expanded_location exploc_next = expand_location (next_loc); + + json::object *region_obj = new json::object (); + + /* "startLine" property (SARIF v2.1.0 section 3.30.5) */ + region_obj->set ("startLine", new json::integer_number (exploc_start.line)); + + /* "startColumn" property (SARIF v2.1.0 section 3.30.6) */ + int start_col = get_sarif_column (exploc_start); + region_obj->set ("startColumn", + new json::integer_number (start_col)); + + /* "endLine" property (SARIF v2.1.0 section 3.30.7) */ + if (exploc_next.line != exploc_start.line) + region_obj->set ("endLine", new json::integer_number (exploc_next.line)); + + /* "endColumn" property (SARIF v2.1.0 section 3.30.8). + This expresses the column immediately beyond the range. */ + int next_col = get_sarif_column (exploc_next); + region_obj->set ("endColumn", new json::integer_number (next_col)); + + return region_obj; +} + +/* Attempt to get a string for a logicalLocation's "kind" property + (SARIF v2.1.0 section 3.33.7). + Return NULL if unknown. */ + +static const char * +maybe_get_sarif_kind (enum logical_location_kind kind) +{ + switch (kind) + { + default: + gcc_unreachable (); + case LOGICAL_LOCATION_KIND_UNKNOWN: + return NULL; + + case LOGICAL_LOCATION_KIND_FUNCTION: + return "function"; + case LOGICAL_LOCATION_KIND_MEMBER: + return "member"; + case LOGICAL_LOCATION_KIND_MODULE: + return "module"; + case LOGICAL_LOCATION_KIND_NAMESPACE: + return "namespace"; + case LOGICAL_LOCATION_KIND_TYPE: + return "type"; + case LOGICAL_LOCATION_KIND_RETURN_TYPE: + return "returnType"; + case LOGICAL_LOCATION_KIND_PARAMETER: + return "parameter"; + case LOGICAL_LOCATION_KIND_VARIABLE: + return "variable"; + } +} + +/* Make a logicalLocation object (SARIF v2.1.0 section 3.33) for LOGICAL_LOC, + or return NULL. */ + +json::object * +sarif_builder:: +make_logical_location_object (const logical_location &logical_loc) const +{ + json::object *logical_loc_obj = new json::object (); + + /* "name" property (SARIF v2.1.0 section 3.33.4). */ + if (const char *short_name = logical_loc.get_short_name ()) + logical_loc_obj->set ("name", new json::string (short_name)); + + /* "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */ + if (const char *name_with_scope = logical_loc.get_name_with_scope ()) + logical_loc_obj->set ("fullyQualifiedName", + new json::string (name_with_scope)); + + /* "decoratedName" property (SARIF v2.1.0 section 3.33.6). */ + if (const char *internal_name = logical_loc.get_internal_name ()) + logical_loc_obj->set ("decoratedName", new json::string (internal_name)); + + /* "kind" property (SARIF v2.1.0 section 3.33.7). */ + enum logical_location_kind kind = logical_loc.get_kind (); + if (const char *sarif_kind_str = maybe_get_sarif_kind (kind)) + logical_loc_obj->set ("kind", new json::string (sarif_kind_str)); + + return logical_loc_obj; +} + +/* Make a codeFlow object (SARIF v2.1.0 section 3.36) for PATH. */ + +json::object * +sarif_builder::make_code_flow_object (const diagnostic_path &path) +{ + json::object *code_flow_obj = new json::object (); + + /* "threadFlows" property (SARIF v2.1.0 section 3.36.3). + Currently we only support one thread per result. */ + json::array *thread_flows_arr = new json::array (); + json::object *thread_flow_obj = make_thread_flow_object (path); + thread_flows_arr->append (thread_flow_obj); + code_flow_obj->set ("threadFlows", thread_flows_arr); + + return code_flow_obj; +} + +/* Make a threadFlow object (SARIF v2.1.0 section 3.37) for PATH. */ + +json::object * +sarif_builder::make_thread_flow_object (const diagnostic_path &path) +{ + json::object *thread_flow_obj = new json::object (); + + /* "locations" property (SARIF v2.1.0 section 3.37.6). */ + json::array *locations_arr = new json::array (); + for (unsigned i = 0; i < path.num_events (); i++) + { + const diagnostic_event &event = path.get_event (i); + json::object *thread_flow_loc_obj + = make_thread_flow_location_object (event); + locations_arr->append (thread_flow_loc_obj); + } + thread_flow_obj->set ("locations", locations_arr); + + return thread_flow_obj; +} + +/* Make a threadFlowLocation object (SARIF v2.1.0 section 3.38) for EVENT. */ + +json::object * +sarif_builder::make_thread_flow_location_object (const diagnostic_event &ev) +{ + json::object *thread_flow_loc_obj = new json::object (); + + /* "location" property (SARIF v2.1.0 section 3.38.3). */ + json::object *location_obj = make_location_object (ev); + thread_flow_loc_obj->set ("location", location_obj); + + /* "kinds" property (SARIF v2.1.0 section 3.38.8). */ + diagnostic_event::meaning m = ev.get_meaning (); + if (json::array *kinds_arr = maybe_make_kinds_array (m)) + thread_flow_loc_obj->set ("kinds", kinds_arr); + + /* "nestingLevel" property (SARIF v2.1.0 section 3.38.10). */ + thread_flow_loc_obj->set ("nestingLevel", + new json::integer_number (ev.get_stack_depth ())); + + /* It might be nice to eventually implement the following for -fanalyzer: + - the "stack" property (SARIF v2.1.0 section 3.38.5) + - the "state" property (SARIF v2.1.0 section 3.38.9) + - the "importance" property (SARIF v2.1.0 section 3.38.13). */ + + return thread_flow_loc_obj; +} + +/* If M has any known meaning, make a json array suitable for the "kinds" + property of a threadFlowLocation object (SARIF v2.1.0 section 3.38.8). + + Otherwise, return NULL. */ + +json::array * +sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const +{ + if (m.m_verb == diagnostic_event::VERB_unknown + && m.m_noun == diagnostic_event::NOUN_unknown + && m.m_property == diagnostic_event::PROPERTY_unknown) + return NULL; + + json::array *kinds_arr = new json::array (); + if (const char *verb_str + = diagnostic_event::meaning::maybe_get_verb_str (m.m_verb)) + kinds_arr->append (new json::string (verb_str)); + if (const char *noun_str + = diagnostic_event::meaning::maybe_get_noun_str (m.m_noun)) + kinds_arr->append (new json::string (noun_str)); + if (const char *property_str + = diagnostic_event::meaning::maybe_get_property_str (m.m_property)) + kinds_arr->append (new json::string (property_str)); + return kinds_arr; +} + +/* Make a message object (SARIF v2.1.0 section 3.11) for MSG. */ + +json::object * +sarif_builder::make_message_object (const char *msg) const +{ + json::object *message_obj = new json::object (); + + /* "text" property (SARIF v2.1.0 section 3.11.8). */ + message_obj->set ("text", new json::string (msg)); + + return message_obj; +} + +/* Make a multiformatMessageString object (SARIF v2.1.0 section 3.12) + for MSG. */ + +json::object * +sarif_builder::make_multiformat_message_string (const char *msg) const +{ + json::object *message_obj = new json::object (); + + /* "text" property (SARIF v2.1.0 section 3.12.3). */ + message_obj->set ("text", new json::string (msg)); + + return message_obj; +} + +#define SARIF_SCHEMA "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json" +#define SARIF_VERSION "2.1.0" + +/* Make a top-level sarifLog object (SARIF v2.1.0 section 3.13). + Take ownership of RESULTS. */ + +json::object * +sarif_builder::make_top_level_object (json::array *results) +{ + json::object *log_obj = new json::object (); + + /* "$schema" property (SARIF v2.1.0 section 3.13.3) . */ + log_obj->set ("$schema", new json::string (SARIF_SCHEMA)); + + /* "version" property (SARIF v2.1.0 section 3.13.2). */ + log_obj->set ("version", new json::string (SARIF_VERSION)); + + /* "runs" property (SARIF v2.1.0 section 3.13.4). */ + json::array *run_arr = new json::array (); + json::object *run_obj = make_run_object (results); + run_arr->append (run_obj); + log_obj->set ("runs", run_arr); + + return log_obj; +} + +/* Make a run object (SARIF v2.1.0 section 3.14). + Take ownership of RESULTS. */ + +json::object * +sarif_builder::make_run_object (json::array *results) +{ + json::object *run_obj = new json::object (); + + /* "tool" property (SARIF v2.1.0 section 3.14.6). */ + json::object *tool_obj = make_tool_object (); + run_obj->set ("tool", tool_obj); + + /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */ + if (json::array *taxonomies_arr = maybe_make_taxonomies_array ()) + run_obj->set ("taxonomies", taxonomies_arr); + + /* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */ + if (m_seen_any_relative_paths) + { + json::object *orig_uri_base_ids = new json::object (); + run_obj->set ("originalUriBaseIds", orig_uri_base_ids); + json::object *pwd_art_loc_obj = make_artifact_location_object_for_pwd (); + orig_uri_base_ids->set (PWD_PROPERTY_NAME, pwd_art_loc_obj); + } + + /* "artifacts" property (SARIF v2.1.0 section 3.14.15). */ + json::array *artifacts_arr = new json::array (); + for (auto iter : m_filenames) + { + json::object *artifact_obj = make_artifact_object (iter); + artifacts_arr->append (artifact_obj); + } + run_obj->set ("artifacts", artifacts_arr); + + /* "results" property (SARIF v2.1.0 section 3.14.23). */ + run_obj->set ("results", results); + + return run_obj; +} + +/* Make a tool object (SARIF v2.1.0 section 3.18). */ + +json::object * +sarif_builder::make_tool_object () const +{ + json::object *tool_obj = new json::object (); + + /* "driver" property (SARIF v2.1.0 section 3.18.2). */ + json::object *driver_obj = make_driver_tool_component_object (); + tool_obj->set ("driver", driver_obj); + + /* Report plugins via the "extensions" property + (SARIF v2.1.0 section 3.18.3). */ + if (m_context->m_client_data_hooks) + if (const client_version_info *vinfo + = m_context->m_client_data_hooks->get_any_version_info ()) + { + class my_plugin_visitor : public client_version_info :: plugin_visitor + { + public: + void on_plugin (const diagnostic_client_plugin_info &p) final override + { + /* Create a toolComponent object (SARIF v2.1.0 section 3.19) + for the plugin. */ + json::object *plugin_obj = new json::object (); + m_plugin_objs.safe_push (plugin_obj); + + /* "name" property (SARIF v2.1.0 section 3.19.8). */ + if (const char *short_name = p.get_short_name ()) + plugin_obj->set ("name", new json::string (short_name)); + + /* "fullName" property (SARIF v2.1.0 section 3.19.9). */ + if (const char *full_name = p.get_full_name ()) + plugin_obj->set ("fullName", new json::string (full_name)); + + /* "version" property (SARIF v2.1.0 section 3.19.13). */ + if (const char *version = p.get_version ()) + plugin_obj->set ("version", new json::string (version)); + } + auto_vec <json::object *> m_plugin_objs; + }; + my_plugin_visitor v; + vinfo->for_each_plugin (v); + if (v.m_plugin_objs.length () > 0) + { + json::array *extensions_arr = new json::array (); + tool_obj->set ("extensions", extensions_arr); + for (auto iter : v.m_plugin_objs) + extensions_arr->append (iter); + } + } + + /* Perhaps we could also show GMP, MPFR, MPC, isl versions as other + "extensions" (see toplev.cc: print_version). */ + + return tool_obj; +} + +/* Make a toolComponent object (SARIF v2.1.0 section 3.19) for what SARIF + calls the "driver" (see SARIF v2.1.0 section 3.18.1). */ + +json::object * +sarif_builder::make_driver_tool_component_object () const +{ + json::object *driver_obj = new json::object (); + + if (m_context->m_client_data_hooks) + if (const client_version_info *vinfo + = m_context->m_client_data_hooks->get_any_version_info ()) + { + /* "name" property (SARIF v2.1.0 section 3.19.8). */ + if (const char *name = vinfo->get_tool_name ()) + driver_obj->set ("name", new json::string (name)); + + /* "fullName" property (SARIF v2.1.0 section 3.19.9). */ + if (char *full_name = vinfo->maybe_make_full_name ()) + { + driver_obj->set ("fullName", new json::string (full_name)); + free (full_name); + } + + /* "version" property (SARIF v2.1.0 section 3.19.13). */ + if (const char *version = vinfo->get_version_string ()) + driver_obj->set ("version", new json::string (version)); + + /* "informationUri" property (SARIF v2.1.0 section 3.19.17). */ + if (char *version_url = vinfo->maybe_make_version_url ()) + { + driver_obj->set ("informationUri", new json::string (version_url)); + free (version_url); + } + } + + /* "rules" property (SARIF v2.1.0 section 3.19.23). */ + driver_obj->set ("rules", m_rules_arr); + + return driver_obj; +} + +/* If we've seen any CWE IDs, make an array for the "taxonomies" property + (SARIF v2.1.0 section 3.14.8) of a run object, containting a singl + toolComponent (3.19) as per 3.19.3, representing the CWE. + + Otherwise return NULL. */ + +json::array * +sarif_builder::maybe_make_taxonomies_array () const +{ + json::object *cwe_obj = maybe_make_cwe_taxonomy_object (); + if (!cwe_obj) + return NULL; + + /* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */ + json::array *taxonomies_arr = new json::array (); + taxonomies_arr->append (cwe_obj); + return taxonomies_arr; +} + +/* If we've seen any CWE IDs, make a toolComponent object + (SARIF v2.1.0 section 3.19) representing the CWE taxonomy, as per 3.19.3. + Populate the "taxa" property with all of the CWE IDs in m_cwe_id_set. + + Otherwise return NULL. */ + +json::object * +sarif_builder::maybe_make_cwe_taxonomy_object () const +{ + if (m_cwe_id_set.is_empty ()) + return NULL; + + json::object *taxonomy_obj = new json::object (); + + /* "name" property (SARIF v2.1.0 section 3.19.8). */ + taxonomy_obj->set ("name", new json::string ("CWE")); + + /* "version" property (SARIF v2.1.0 section 3.19.13). */ + taxonomy_obj->set ("version", new json::string ("4.7")); + + /* "organization" property (SARIF v2.1.0 section 3.19.18). */ + taxonomy_obj->set ("organization", new json::string ("MITRE")); + + /* "shortDescription" property (SARIF v2.1.0 section 3.19.19). */ + json::object *short_desc + = make_multiformat_message_string ("The MITRE" + " Common Weakness Enumeration"); + taxonomy_obj->set ("shortDescription", short_desc); + + /* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */ + json::array *taxa_arr = new json::array (); + for (auto cwe_id : m_cwe_id_set) + { + json::object *cwe_taxon + = make_reporting_descriptor_object_for_cwe_id (cwe_id); + taxa_arr->append (cwe_taxon); + } + taxonomy_obj->set ("taxa", taxa_arr); + + return taxonomy_obj; +} + +/* Make an artifact object (SARIF v2.1.0 section 3.24). */ + +json::object * +sarif_builder::make_artifact_object (const char *filename) +{ + json::object *artifact_obj = new json::object (); + + /* "location" property (SARIF v2.1.0 section 3.24.2). */ + json::object *artifact_loc_obj = make_artifact_location_object (filename); + artifact_obj->set ("location", artifact_loc_obj); + + /* "contents" property (SARIF v2.1.0 section 3.24.8). */ + if (json::object *artifact_content_obj + = maybe_make_artifact_content_object (filename)) + artifact_obj->set ("contents", artifact_content_obj); + + /* "sourceLanguage" property (SARIF v2.1.0 section 3.24.10). */ + if (m_context->m_client_data_hooks) + if (const char *source_lang + = m_context->m_client_data_hooks->maybe_get_sarif_source_language + (filename)) + artifact_obj->set ("sourceLanguage", new json::string (source_lang)); + + return artifact_obj; +} + +/* Read all data from F_IN until EOF. + Return a NULL-terminated buffer containing the data, which must be + freed by the caller. + Return NULL on errors. */ + +static char * +read_until_eof (FILE *f_in) +{ + /* Read content, allocating a buffer for it. */ + char *result = NULL; + size_t total_sz = 0; + size_t alloc_sz = 0; + char buf[4096]; + size_t iter_sz_in; + + while ( (iter_sz_in = fread (buf, 1, sizeof (buf), f_in)) ) + { + gcc_assert (alloc_sz >= total_sz); + size_t old_total_sz = total_sz; + total_sz += iter_sz_in; + /* Allow 1 extra byte for 0-termination. */ + if (alloc_sz < (total_sz + 1)) + { + size_t new_alloc_sz = alloc_sz ? alloc_sz * 2: total_sz + 1; + result = (char *)xrealloc (result, new_alloc_sz); + alloc_sz = new_alloc_sz; + } + memcpy (result + old_total_sz, buf, iter_sz_in); + } + + if (!feof (f_in)) + return NULL; + + /* 0-terminate the buffer. */ + gcc_assert (total_sz < alloc_sz); + result[total_sz] = '\0'; + + return result; +} + +/* Read all data from FILENAME until EOF. + Return a NULL-terminated buffer containing the data, which must be + freed by the caller. + Return NULL on errors. */ + +static char * +maybe_read_file (const char *filename) +{ + FILE *f_in = fopen (filename, "r"); + if (!f_in) + return NULL; + char *result = read_until_eof (f_in); + fclose (f_in); + return result; +} + +/* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the + full contents of FILENAME. */ + +json::object * +sarif_builder::maybe_make_artifact_content_object (const char *filename) const +{ + char *text_utf8 = maybe_read_file (filename); + if (!text_utf8) + return NULL; + + json::object *artifact_content_obj = new json::object (); + artifact_content_obj->set ("text", new json::string (text_utf8)); + free (text_utf8); + + return artifact_content_obj; +} + +/* Attempt to read the given range of lines from FILENAME; return + a freshly-allocated 0-terminated buffer containing them, or NULL. */ + +static char * +get_source_lines (const char *filename, + int start_line, + int end_line) +{ + auto_vec<char> result; + + for (int line = start_line; line <= end_line; line++) + { + char_span line_content = location_get_source_line (filename, line); + if (!line_content.get_buffer ()) + return NULL; + result.reserve (line_content.length () + 1); + for (size_t i = 0; i < line_content.length (); i++) + result.quick_push (line_content[i]); + result.quick_push ('\n'); + } + result.safe_push ('\0'); + + return xstrdup (result.address ()); +} + +/* Make an artifactContent object (SARIF v2.1.0 section 3.3) for the given + run of lines within FILENAME (including the endpoints). */ + +json::object * +sarif_builder::maybe_make_artifact_content_object (const char *filename, + int start_line, + int end_line) const +{ + char *text_utf8 = get_source_lines (filename, start_line, end_line); + + if (!text_utf8) + return NULL; + + json::object *artifact_content_obj = new json::object (); + artifact_content_obj->set ("text", new json::string (text_utf8)); + free (text_utf8); + + return artifact_content_obj; +} + +/* Make a fix object (SARIF v2.1.0 section 3.55) for RICHLOC. */ + +json::object * +sarif_builder::make_fix_object (const rich_location &richloc) +{ + json::object *fix_obj = new json::object (); + + /* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */ + /* We assume that all fix-it hints in RICHLOC affect the same file. */ + json::array *artifact_change_arr = new json::array (); + json::object *artifact_change_obj = make_artifact_change_object (richloc); + artifact_change_arr->append (artifact_change_obj); + fix_obj->set ("artifactChanges", artifact_change_arr); + + return fix_obj; +} + +/* Make an artifactChange object (SARIF v2.1.0 section 3.56) for RICHLOC. */ + +json::object * +sarif_builder::make_artifact_change_object (const rich_location &richloc) +{ + json::object *artifact_change_obj = new json::object (); + + /* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */ + json::object *artifact_location_obj + = make_artifact_location_object (richloc.get_loc ()); + artifact_change_obj->set ("artifactLocation", artifact_location_obj); + + /* "replacements" property (SARIF v2.1.0 section 3.56.3). */ + json::array *replacement_arr = new json::array (); + for (unsigned int i = 0; i < richloc.get_num_fixit_hints (); i++) + { + const fixit_hint *hint = richloc.get_fixit_hint (i); + json::object *replacement_obj = make_replacement_object (*hint); + replacement_arr->append (replacement_obj); + } + artifact_change_obj->set ("replacements", replacement_arr); + + return artifact_change_obj; +} + +/* Make a replacement object (SARIF v2.1.0 section 3.57) for HINT. */ + +json::object * +sarif_builder::make_replacement_object (const fixit_hint &hint) const +{ + json::object *replacement_obj = new json::object (); + + /* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */ + json::object *region_obj = make_region_object_for_hint (hint); + replacement_obj->set ("deletedRegion", region_obj); + + /* "insertedContent" property (SARIF v2.1.0 section 3.57.4). */ + json::object *content_obj = make_artifact_content_object (hint.get_string ()); + replacement_obj->set ("insertedContent", content_obj); + + return replacement_obj; +} + +/* Make an artifactContent object (SARIF v2.1.0 section 3.3) for TEXT. */ + +json::object * +sarif_builder::make_artifact_content_object (const char *text) const +{ + json::object *content_obj = new json::object (); + + /* "text" property (SARIF v2.1.0 section 3.3.2). */ + content_obj->set ("text", new json::string (text)); + + return content_obj; +} + +/* No-op implementation of "begin_diagnostic" for SARIF output. */ + +static void +sarif_begin_diagnostic (diagnostic_context *, diagnostic_info *) +{ +} + +/* Implementation of "end_diagnostic" for SARIF output. */ + +static void +sarif_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic, + diagnostic_t orig_diag_kind) +{ + gcc_assert (the_builder); + the_builder->end_diagnostic (context, diagnostic, orig_diag_kind); +} + +/* No-op implementation of "begin_group_cb" for SARIF output. */ + +static void +sarif_begin_group (diagnostic_context *) +{ +} + +/* Implementation of "end_group_cb" for SARIF output. */ + +static void +sarif_end_group (diagnostic_context *) +{ + gcc_assert (the_builder); + the_builder->end_group (); +} + +/* Flush the top-level array to OUTF. */ + +static void +sarif_flush_to_file (FILE *outf) +{ + gcc_assert (the_builder); + the_builder->flush_to_file (outf); + delete the_builder; + the_builder = NULL; +} + +/* Callback for final cleanup for SARIF output to stderr. */ + +static void +sarif_stderr_final_cb (diagnostic_context *) +{ + gcc_assert (the_builder); + sarif_flush_to_file (stderr); +} + +static char *sarif_output_base_file_name; + +/* Callback for final cleanup for SARIF output to a file. */ + +static void +sarif_file_final_cb (diagnostic_context *) +{ + char *filename = concat (sarif_output_base_file_name, ".sarif", NULL); + FILE *outf = fopen (filename, "w"); + if (!outf) + { + const char *errstr = xstrerror (errno); + fnotice (stderr, "error: unable to open '%s' for writing: %s\n", + filename, errstr); + free (filename); + return; + } + gcc_assert (the_builder); + sarif_flush_to_file (outf); + fclose (outf); + free (filename); +} + +/* Populate CONTEXT in preparation for SARIF output (either to stderr, or + to a file). */ + +static void +diagnostic_output_format_init_sarif (diagnostic_context *context) +{ + the_builder = new sarif_builder (context); + + /* Override callbacks. */ + context->begin_diagnostic = sarif_begin_diagnostic; + context->end_diagnostic = sarif_end_diagnostic; + context->begin_group_cb = sarif_begin_group; + context->end_group_cb = sarif_end_group; + context->print_path = NULL; /* handled in sarif_end_diagnostic. */ + + /* The metadata is handled in SARIF format, rather than as text. */ + context->show_cwe = false; + + /* The option is handled in SARIF format, rather than as text. */ + context->show_option_requested = false; + + /* Don't colorize the text. */ + pp_show_color (context->printer) = false; +} + +/* Populate CONTEXT in preparation for SARIF output to stderr. */ + +void +diagnostic_output_format_init_sarif_stderr (diagnostic_context *context) +{ + diagnostic_output_format_init_sarif (context); + context->final_cb = sarif_stderr_final_cb; +} + +/* Populate CONTEXT in preparation for SARIF output to a file named + BASE_FILE_NAME.sarif. */ + +void +diagnostic_output_format_init_sarif_file (diagnostic_context *context, + const char *base_file_name) +{ + diagnostic_output_format_init_sarif (context); + context->final_cb = sarif_file_final_cb; + sarif_output_base_file_name = xstrdup (base_file_name); +} diff --git a/gcc/diagnostic-path.h b/gcc/diagnostic-path.h index 6c1190d..8ce4ff7 100644 --- a/gcc/diagnostic-path.h +++ b/gcc/diagnostic-path.h @@ -69,6 +69,75 @@ along with GCC; see the file COPYING3. If not see class diagnostic_event { public: + /* Enums for giving a sense of what this event means. + Roughly corresponds to SARIF v2.1.0 section 3.38.8. */ + enum verb + { + VERB_unknown, + + VERB_acquire, + VERB_release, + VERB_enter, + VERB_exit, + VERB_call, + VERB_return, + VERB_branch, + + VERB_danger + }; + enum noun + { + NOUN_unknown, + + NOUN_taint, + NOUN_sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530 + NOUN_function, + NOUN_lock, + NOUN_memory, + NOUN_resource + }; + enum property + { + PROPERTY_unknown, + + PROPERTY_true, + PROPERTY_false + }; + /* A bundle of such enums, allowing for descriptions of the meaning of + an event, such as + - "acquire memory": meaning (VERB_acquire, NOUN_memory) + - "take true branch"": meaning (VERB_branch, PROPERTY_true) + - "return from function": meaning (VERB_return, NOUN_function) + etc, as per SARIF's threadFlowLocation "kinds" property + (SARIF v2.1.0 section 3.38.8). */ + struct meaning + { + meaning () + : m_verb (VERB_unknown), + m_noun (NOUN_unknown), + m_property (PROPERTY_unknown) + { + } + meaning (enum verb verb, enum noun noun) + : m_verb (verb), m_noun (noun), m_property (PROPERTY_unknown) + { + } + meaning (enum verb verb, enum property property) + : m_verb (verb), m_noun (NOUN_unknown), m_property (property) + { + } + + void dump_to_pp (pretty_printer *pp) const; + + static const char *maybe_get_verb_str (enum verb); + static const char *maybe_get_noun_str (enum noun); + static const char *maybe_get_property_str (enum property); + + enum verb m_verb; + enum noun m_noun; + enum property m_property; + }; + virtual ~diagnostic_event () {} virtual location_t get_location () const = 0; @@ -81,6 +150,11 @@ class diagnostic_event /* Get a localized (and possibly colorized) description of this event. */ virtual label_text get_desc (bool can_colorize) const = 0; + + /* Get a logical_location for this event, or NULL. */ + virtual const logical_location *get_logical_location () const = 0; + + virtual meaning get_meaning () const = 0; }; /* Abstract base class for getting at a sequence of events. */ @@ -113,6 +187,14 @@ class simple_diagnostic_event : public diagnostic_event { return label_text::borrow (m_desc); } + const logical_location *get_logical_location () const final override + { + return NULL; + } + meaning get_meaning () const final override + { + return meaning (); + } private: location_t m_loc; diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index fef1146..f2a82ff 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-url.h" #include "diagnostic-metadata.h" #include "diagnostic-path.h" +#include "diagnostic-client-data-hooks.h" #include "edit-context.h" #include "selftest.h" #include "selftest-diagnostic.h" @@ -240,6 +241,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts) context->end_group_cb = NULL; context->final_cb = default_diagnostic_final_cb; context->includes_seen = NULL; + context->m_client_data_hooks = NULL; } /* Maybe initialize the color support. We require clients to do this @@ -338,6 +340,12 @@ diagnostic_finish (diagnostic_context *context) delete context->includes_seen; context->includes_seen = nullptr; } + + if (context->m_client_data_hooks) + { + delete context->m_client_data_hooks; + context->m_client_data_hooks = NULL; + } } /* Initialize DIAGNOSTIC, where the message MSG has already been @@ -820,6 +828,116 @@ diagnostic_show_any_path (diagnostic_context *context, context->print_path (context, path); } +/* class diagnostic_event. */ + +/* struct diagnostic_event::meaning. */ + +void +diagnostic_event::meaning::dump_to_pp (pretty_printer *pp) const +{ + bool need_comma = false; + pp_character (pp, '{'); + if (const char *verb_str = maybe_get_verb_str (m_verb)) + { + pp_printf (pp, "verb: %qs", verb_str); + need_comma = true; + } + if (const char *noun_str = maybe_get_noun_str (m_noun)) + { + if (need_comma) + pp_string (pp, ", "); + pp_printf (pp, "noun: %qs", noun_str); + need_comma = true; + } + if (const char *property_str = maybe_get_property_str (m_property)) + { + if (need_comma) + pp_string (pp, ", "); + pp_printf (pp, "property: %qs", property_str); + need_comma = true; + } + pp_character (pp, '}'); +} + +/* Get a string (or NULL) for V suitable for use within a SARIF + threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */ + +const char * +diagnostic_event::meaning::maybe_get_verb_str (enum verb v) +{ + switch (v) + { + default: + gcc_unreachable (); + case VERB_unknown: + return NULL; + case VERB_acquire: + return "acquire"; + case VERB_release: + return "release"; + case VERB_enter: + return "enter"; + case VERB_exit: + return "exit"; + case VERB_call: + return "call"; + case VERB_return: + return "return"; + case VERB_branch: + return "branch"; + case VERB_danger: + return "danger"; + } +} + +/* Get a string (or NULL) for N suitable for use within a SARIF + threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */ + +const char * +diagnostic_event::meaning::maybe_get_noun_str (enum noun n) +{ + switch (n) + { + default: + gcc_unreachable (); + case NOUN_unknown: + return NULL; + case NOUN_taint: + return "taint"; + case NOUN_sensitive: + return "sensitive"; + case NOUN_function: + return "function"; + case NOUN_lock: + return "lock"; + case NOUN_memory: + return "memory"; + case NOUN_resource: + return "resource"; + } +} + +/* Get a string (or NULL) for P suitable for use within a SARIF + threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */ + +const char * +diagnostic_event::meaning::maybe_get_property_str (enum property p) +{ + switch (p) + { + default: + gcc_unreachable (); + case PROPERTY_unknown: + return NULL; + case PROPERTY_true: + return "true"; + case PROPERTY_false: + return "false"; + } +} + +/* class diagnostic_path. */ + /* Return true if the events in this path involve more than one function, or false if it is purely intraprocedural. */ @@ -1131,7 +1249,7 @@ update_effective_level_from_pragmas (diagnostic_context *context, /* Generate a URL string describing CWE. The caller is responsible for freeing the string. */ -static char * +char * get_cwe_url (int cwe) { return xasprintf ("https://cwe.mitre.org/data/definitions/%i.html", cwe); @@ -2072,6 +2190,40 @@ auto_diagnostic_group::~auto_diagnostic_group () } } +/* Set the output format for CONTEXT to FORMAT, using BASE_FILE_NAME for + file-based output formats. */ + +void +diagnostic_output_format_init (diagnostic_context *context, + const char *base_file_name, + enum diagnostics_output_format format) +{ + switch (format) + { + default: + gcc_unreachable (); + case DIAGNOSTICS_OUTPUT_FORMAT_TEXT: + /* The default; do nothing. */ + break; + + case DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR: + diagnostic_output_format_init_json_stderr (context); + break; + + case DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE: + diagnostic_output_format_init_json_file (context, base_file_name); + break; + + case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR: + diagnostic_output_format_init_sarif_stderr (context); + break; + + case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE: + diagnostic_output_format_init_sarif_file (context, base_file_name); + break; + } +} + /* Implementation of diagnostic_path::num_events vfunc for simple_diagnostic_path: simply get the number of events in the vec. */ diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 3ca3297..96c9a72 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -59,8 +59,17 @@ enum diagnostics_output_format /* The default: textual output. */ DIAGNOSTICS_OUTPUT_FORMAT_TEXT, - /* JSON-based output. */ - DIAGNOSTICS_OUTPUT_FORMAT_JSON + /* JSON-based output, to stderr. */ + DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR, + + /* JSON-based output, to a file. */ + DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE, + + /* SARIF-based output, to stderr. */ + DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR, + + /* SARIF-based output, to a file. */ + DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE }; /* An enum for controlling how diagnostic_paths should be printed. */ @@ -159,6 +168,8 @@ typedef void (*diagnostic_finalizer_fn) (diagnostic_context *, class edit_context; namespace json { class value; } +class diagnostic_client_data_hooks; +class logical_location; /* This data structure bundles altogether any information relevant to the context of a diagnostic message. */ @@ -394,6 +405,12 @@ struct diagnostic_context /* Include files that diagnostic_report_current_module has already listed the include path for. */ hash_set<location_t, false, location_hash> *includes_seen; + + /* A bundle of hooks for providing data to the context about its client + e.g. version information, plugins, etc. + Used by SARIF output to give metadata about the client that's + producing diagnostics. */ + diagnostic_client_data_hooks *m_client_data_hooks; }; static inline void @@ -577,7 +594,14 @@ extern char *file_name_as_prefix (diagnostic_context *, const char *); extern char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1; extern void diagnostic_output_format_init (diagnostic_context *, + const char *base_file_name, enum diagnostics_output_format); +extern void diagnostic_output_format_init_json_stderr (diagnostic_context *context); +extern void diagnostic_output_format_init_json_file (diagnostic_context *context, + const char *base_file_name); +extern void diagnostic_output_format_init_sarif_stderr (diagnostic_context *context); +extern void diagnostic_output_format_init_sarif_file (diagnostic_context *context, + const char *base_file_name); /* Compute the number of digits in the decimal representation of an integer. */ extern int num_digits (int); @@ -587,4 +611,6 @@ extern json::value *json_from_expanded_location (diagnostic_context *context, extern bool warning_enabled_at (location_t, int); +extern char *get_cwe_url (int cwe); + #endif /* ! GCC_DIAGNOSTIC_H */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 71098d8..8cd5bdd 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -301,7 +301,7 @@ Objective-C and Objective-C++ Dialects}. -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]} @gol -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]} @gol -fdiagnostics-urls=@r{[}auto@r{|}never@r{|}always@r{]} @gol --fdiagnostics-format=@r{[}text@r{|}json@r{]} @gol +-fdiagnostics-format=@r{[}text@r{|}sarif-stderr@r{|}sarif-file@r{|}json@r{|}json-stderr@r{|}json-file@r{]} @gol -fno-diagnostics-show-option -fno-diagnostics-show-caret @gol -fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers @gol -fno-diagnostics-show-cwe @gol @@ -5305,14 +5305,23 @@ Unicode characters. For the example above, the following will be printed: @item -fdiagnostics-format=@var{FORMAT} @opindex fdiagnostics-format Select a different format for printing diagnostics. -@var{FORMAT} is @samp{text} or @samp{json}. +@var{FORMAT} is @samp{text}, @samp{sarif-stderr}, @samp{sarif-file}, +@samp{json}, @samp{json-stderr}, or @samp{json-file}. + The default is @samp{text}. -The @samp{json} format consists of a top-level JSON array containing JSON -objects representing the diagnostics. +The @samp{sarif-stderr} and @samp{sarif-file} formats both emit +diagnostics in SARIF Version 2.1.0 format, either to stderr, or to a file +named @file{@var{source}.sarif}, respectively. + +The @samp{json} format is a synonym for @samp{json-stderr}. +The @samp{json-stderr} and @samp{json-file} formats are identical, apart from +where the JSON is emitted to - with the former, the JSON is emitted to stderr, +whereas with @samp{json-file} it is written to @file{@var{source}.gcc.json}. -The JSON is emitted as one line, without formatting; the examples below -have been formatted for clarity. +The emitted JSON consists of a top-level JSON array containing JSON objects +representing the diagnostics. The JSON is emitted as one line, without +formatting; the examples below have been formatted for clarity. Diagnostics can have child diagnostics. For example, this error and note: diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 7805e84..28faa7b 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -3157,6 +3157,12 @@ Passes if @var{regexp} matches in Fortran module @var{module}. @item dg-check-dot @var{filename} Passes if @var{filename} is a valid @file{.dot} file (by running @code{dot -Tpng} on it, and verifying the exit code is 0). +@item scan-sarif-file @var{regexp} [@{ target/xfail @var{selector} @}] +Passes if @var{regexp} matches text in the file generated by +@option{-fdiagnostics-format=sarif-file}. +@item scan-sarif-file-not @var{regexp} [@{ target/xfail @var{selector} @}] +Passes if @var{regexp} does not match text in the file generated by +@option{-fdiagnostics-format=sarif-file}. @end table @subsubsection Scan the assembly output @@ -1508,6 +1508,14 @@ record_store (rtx body, bb_info_t bb_info) if (tem && CONSTANT_P (tem)) const_rhs = tem; + else + { + /* If RHS is set only once to a constant, set CONST_RHS + to the constant. */ + rtx def_src = df_find_single_def_src (rhs); + if (def_src != nullptr && CONSTANT_P (def_src)) + const_rhs = def_src; + } } } diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index fccf59e..29f32ec 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -27479,7 +27479,7 @@ gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls) nml_item_ref_die = force_decl_die (value); nml_item_die = new_die (DW_TAG_namelist_item, nml_die, NULL); - add_AT_die_ref (nml_item_die, DW_AT_namelist_items, nml_item_ref_die); + add_AT_die_ref (nml_item_die, DW_AT_namelist_item, nml_item_ref_die); } return nml_die; } diff --git a/gcc/exec-tool.in b/gcc/exec-tool.in index cf72227..3a0fefa 100644 --- a/gcc/exec-tool.in +++ b/gcc/exec-tool.in @@ -17,7 +17,7 @@ # along with GCC; see the file COPYING3. If not see # <http://www.gnu.org/licenses/>. -# Invoke as, ld or nm from the build tree. +# Invoke as, ld, nm, or objcopy from the build tree. ORIGINAL_AS_FOR_TARGET="@ORIGINAL_AS_FOR_TARGET@" ORIGINAL_LD_FOR_TARGET="@ORIGINAL_LD_FOR_TARGET@" @@ -25,6 +25,7 @@ ORIGINAL_LD_BFD_FOR_TARGET="@ORIGINAL_LD_BFD_FOR_TARGET@" ORIGINAL_LD_GOLD_FOR_TARGET="@ORIGINAL_LD_GOLD_FOR_TARGET@" ORIGINAL_PLUGIN_LD_FOR_TARGET="@ORIGINAL_PLUGIN_LD_FOR_TARGET@" ORIGINAL_NM_FOR_TARGET="@ORIGINAL_NM_FOR_TARGET@" +ORIGINAL_OBJCOPY_FOR_TARGET="@ORIGINAL_OBJCOPY_FOR_TARGET@" ORIGINAL_DSYMUTIL_FOR_TARGET="@ORIGINAL_DSYMUTIL_FOR_TARGET@" exeext=@host_exeext@ fast_install=@enable_fast_install@ @@ -72,6 +73,11 @@ case "$invoked" in prog=nm-new$exeext dir=binutils ;; + objcopy) + original=$ORIGINAL_OBJCOPY_FOR_TARGET + prog=objcopy$exeext + dir=binutils + ;; dsymutil) original=$ORIGINAL_DSYMUTIL_FOR_TARGET # We do not build this in tree - but still want to be able to execute diff --git a/gcc/expr.cc b/gcc/expr.cc index 7197996..fb062dc 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -100,7 +100,7 @@ static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, profile_probability); static rtx const_vector_from_tree (tree); static tree tree_expr_size (const_tree); -static HOST_WIDE_INT int_expr_size (tree); +static HOST_WIDE_INT int_expr_size (const_tree); static void convert_mode_scalar (rtx, rtx, int); @@ -4867,7 +4867,22 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size, return false; } } - emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM); + + /* If source is a constant VAR_DECL with a simple constructor, + store the constructor to the stack instead of moving it. */ + const_tree decl; + if (partial == 0 + && MEM_P (xinner) + && SYMBOL_REF_P (XEXP (xinner, 0)) + && (decl = SYMBOL_REF_DECL (XEXP (xinner, 0))) != NULL_TREE + && VAR_P (decl) + && TREE_READONLY (decl) + && !TREE_SIDE_EFFECTS (decl) + && immediate_const_ctor_p (DECL_INITIAL (decl), 2)) + store_constructor (DECL_INITIAL (decl), target, 0, + int_expr_size (DECL_INITIAL (decl)), false); + else + emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM); } } else if (partial > 0) @@ -6576,6 +6591,25 @@ categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts, p_init_elts, p_complete); } +/* Return true if constructor CTOR is simple enough to be materialized + in an integer mode register. Limit the size to WORDS words, which + is 1 by default. */ + +bool +immediate_const_ctor_p (const_tree ctor, unsigned int words) +{ + /* Allow function to be called with a VAR_DECL's DECL_INITIAL. */ + if (!ctor || TREE_CODE (ctor) != CONSTRUCTOR) + return false; + + return TREE_CONSTANT (ctor) + && !TREE_ADDRESSABLE (ctor) + && CONSTRUCTOR_NELTS (ctor) + && TREE_CODE (TREE_TYPE (ctor)) != ARRAY_TYPE + && int_expr_size (ctor) <= words * UNITS_PER_WORD + && initializer_constant_valid_for_bitfield_p (ctor); +} + /* TYPE is initialized by a constructor with NUM_ELTS elements, the last of which had type LAST_TYPE. Each element was itself a complete initializer, in the sense that every meaningful byte was explicitly @@ -10567,6 +10601,21 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, if (temp) return temp; } + /* Expand const VAR_DECLs with CONSTRUCTOR initializers that + have scalar integer modes to a reg via store_constructor. */ + if (TREE_READONLY (exp) + && !TREE_SIDE_EFFECTS (exp) + && (modifier == EXPAND_NORMAL || modifier == EXPAND_STACK_PARM) + && immediate_const_ctor_p (DECL_INITIAL (exp)) + && SCALAR_INT_MODE_P (TYPE_MODE (TREE_TYPE (exp))) + && crtl->emit.regno_pointer_align_length + && !target) + { + target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp))); + store_constructor (DECL_INITIAL (exp), target, 0, + int_expr_size (DECL_INITIAL (exp)), false); + return target; + } /* ... fall through ... */ case PARM_DECL: @@ -13161,7 +13210,7 @@ expr_size (tree exp) if the size can vary or is larger than an integer. */ static HOST_WIDE_INT -int_expr_size (tree exp) +int_expr_size (const_tree exp) { tree size; @@ -338,6 +338,7 @@ extern unsigned HOST_WIDE_INT highest_pow2_factor (const_tree); extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *, bool *); +extern bool immediate_const_ctor_p (const_tree, unsigned int words = 1); extern void expand_operands (tree, tree, rtx, rtx*, rtx*, enum expand_modifier); diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d009192..fd1edc8 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,25 @@ +2022-06-03 Tobias Burnus <tobias@codesourcery.com> + + * openmp.cc (OMP_SCOPE_CLAUSES): Add firstprivate and allocate. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * f95-lang.cc (gfc_get_sarif_source_language): New. + (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (fortran.tags): Look at *.cc. + +2022-05-30 Harald Anlauf <anlauf@gmx.de> + + PR fortran/91300 + * libgfortran.h: Define new error code LIBERROR_NO_MEMORY. + * trans-stmt.cc (gfc_trans_allocate): Generate code for setting + ERRMSG depending on result of STAT result of ALLOCATE. + * trans.cc (gfc_allocate_using_malloc): Use STAT value of + LIBERROR_NO_MEMORY in case of failed malloc. + 2022-05-28 Tobias Burnus <tobias@codesourcery.com> * dump-parse-tree.cc (show_omp_clauses): Handle OMP_LIST_ENTER. diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in index a558fc8..1cb47cb 100644 --- a/gcc/fortran/Make-lang.in +++ b/gcc/fortran/Make-lang.in @@ -113,7 +113,7 @@ fortran.srcinfo: doc/gfortran.info -cp -p $^ $(srcdir)/fortran fortran.tags: force - cd $(srcdir)/fortran; $(ETAGS) -o TAGS.sub *.c *.h; \ + cd $(srcdir)/fortran; $(ETAGS) -o TAGS.sub *.cc *.h; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub fortran.info: doc/gfortran.info doc/gfc-internals.info diff --git a/gcc/fortran/f95-lang.cc b/gcc/fortran/f95-lang.cc index e83fef3..319cf8f 100644 --- a/gcc/fortran/f95-lang.cc +++ b/gcc/fortran/f95-lang.cc @@ -100,6 +100,15 @@ static const struct attribute_spec gfc_attribute_table[] = { NULL, 0, 0, false, false, false, false, NULL, NULL } }; +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +static const char * +gfc_get_sarif_source_language (const char *) +{ + return "fortran"; +} + #undef LANG_HOOKS_NAME #undef LANG_HOOKS_INIT #undef LANG_HOOKS_FINISH @@ -138,6 +147,7 @@ static const struct attribute_spec gfc_attribute_table[] = #undef LANG_HOOKS_BUILTIN_FUNCTION #undef LANG_HOOKS_GET_ARRAY_DESCR_INFO #undef LANG_HOOKS_ATTRIBUTE_TABLE +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE /* Define lang hooks. */ #define LANG_HOOKS_NAME "GNU Fortran" @@ -177,6 +187,7 @@ static const struct attribute_spec gfc_attribute_table[] = #define LANG_HOOKS_BUILTIN_FUNCTION gfc_builtin_function #define LANG_HOOKS_GET_ARRAY_DESCR_INFO gfc_get_array_descr_info #define LANG_HOOKS_ATTRIBUTE_TABLE gfc_attribute_table +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE gfc_get_sarif_source_language struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/fortran/libgfortran.h b/gcc/fortran/libgfortran.h index 064795e..4328447 100644 --- a/gcc/fortran/libgfortran.h +++ b/gcc/fortran/libgfortran.h @@ -133,6 +133,7 @@ typedef enum LIBERROR_CORRUPT_FILE, LIBERROR_INQUIRE_INTERNAL_UNIT, /* Must be different from STAT_STOPPED_IMAGE. */ LIBERROR_BAD_WAIT_ID, + LIBERROR_NO_MEMORY, LIBERROR_LAST /* Not a real error, the last error # + 1. */ } libgfortran_error_codes; diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index a1aa88c..d12cec4 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -3682,7 +3682,8 @@ cleanup: | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION) #define OMP_SCOPE_CLAUSES \ - (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_REDUCTION) + (omp_mask (OMP_CLAUSE_PRIVATE) |OMP_CLAUSE_FIRSTPRIVATE \ + | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_ALLOCATE) #define OMP_SECTIONS_CLAUSES \ (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE \ | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_ALLOCATE) diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc index 7909681..fd6d294 100644 --- a/gcc/fortran/trans-stmt.cc +++ b/gcc/fortran/trans-stmt.cc @@ -7130,7 +7130,8 @@ gfc_trans_allocate (gfc_code * code) if (code->expr1 && code->expr2) { const char *msg = "Attempt to allocate an allocated object"; - tree slen, dlen, errmsg_str; + const char *oommsg = "Insufficient virtual memory"; + tree slen, dlen, errmsg_str, oom_str, oom_loc; stmtblock_t errmsg_block; gfc_init_block (&errmsg_block); @@ -7151,8 +7152,34 @@ gfc_trans_allocate (gfc_code * code) gfc_default_character_kind); dlen = gfc_finish_block (&errmsg_block); - tmp = fold_build2_loc (input_location, NE_EXPR, logical_type_node, - stat, build_int_cst (TREE_TYPE (stat), 0)); + tmp = fold_build2_loc (input_location, EQ_EXPR, logical_type_node, + stat, build_int_cst (TREE_TYPE (stat), + LIBERROR_ALLOCATION)); + + tmp = build3_v (COND_EXPR, tmp, + dlen, build_empty_stmt (input_location)); + + gfc_add_expr_to_block (&block, tmp); + + oom_str = gfc_create_var (pchar_type_node, "OOMMSG"); + oom_loc = gfc_build_localized_cstring_const (oommsg); + gfc_add_modify (&errmsg_block, oom_str, + gfc_build_addr_expr (pchar_type_node, oom_loc)); + + slen = build_int_cst (gfc_charlen_type_node, strlen (oommsg)); + dlen = gfc_get_expr_charlen (code->expr2); + slen = fold_build2_loc (input_location, MIN_EXPR, + TREE_TYPE (slen), dlen, slen); + + gfc_trans_string_copy (&errmsg_block, dlen, errmsg, + code->expr2->ts.kind, + slen, oom_str, + gfc_default_character_kind); + dlen = gfc_finish_block (&errmsg_block); + + tmp = fold_build2_loc (input_location, EQ_EXPR, logical_type_node, + stat, build_int_cst (TREE_TYPE (stat), + LIBERROR_NO_MEMORY)); tmp = build3_v (COND_EXPR, tmp, dlen, build_empty_stmt (input_location)); diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc index f0a5dfb..912a206 100644 --- a/gcc/fortran/trans.cc +++ b/gcc/fortran/trans.cc @@ -772,7 +772,7 @@ gfc_call_malloc (stmtblock_t * block, tree type, tree size) if (newmem == NULL) { if (stat) - *stat = LIBERROR_ALLOCATION; + *stat = LIBERROR_NO_MEMORY; else runtime_error ("Allocation would exceed memory limit"); } @@ -807,7 +807,7 @@ gfc_allocate_using_malloc (stmtblock_t * block, tree pointer, if (status != NULL_TREE) { tmp = fold_build2_loc (input_location, MODIFY_EXPR, status_type, status, - build_int_cst (status_type, LIBERROR_ALLOCATION)); + build_int_cst (status_type, LIBERROR_NO_MEMORY)); gfc_add_expr_to_block (&on_error, tmp); } else @@ -4446,7 +4446,7 @@ driver_handle_option (struct gcc_options *opts, break; case OPT_fdiagnostics_format_: - diagnostic_output_format_init (dc, + diagnostic_output_format_init (dc, opts->x_dump_base_name, (enum diagnostics_output_format)value); break; diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 6e73ac7..f349436 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -44,11 +44,14 @@ along with GCC; see the file COPYING3. If not see class ssa_block_ranges { public: - virtual bool set_bb_range (const_basic_block bb, const irange &r) = 0; - virtual bool get_bb_range (irange &r, const_basic_block bb) = 0; + ssa_block_ranges (tree t) : m_type (t) { } + virtual bool set_bb_range (const_basic_block bb, const vrange &r) = 0; + virtual bool get_bb_range (vrange &r, const_basic_block bb) = 0; virtual bool bb_range_p (const_basic_block bb) = 0; void dump(FILE *f); +private: + tree m_type; }; // Print the list of known ranges for file F in a nice format. @@ -57,7 +60,7 @@ void ssa_block_ranges::dump (FILE *f) { basic_block bb; - int_range_max r; + Value_Range r (m_type); FOR_EACH_BB_FN (bb, cfun) if (get_bb_range (r, bb)) @@ -75,36 +78,40 @@ ssa_block_ranges::dump (FILE *f) class sbr_vector : public ssa_block_ranges { public: - sbr_vector (tree t, irange_allocator *allocator); + sbr_vector (tree t, vrange_allocator *allocator); - virtual bool set_bb_range (const_basic_block bb, const irange &r) override; - virtual bool get_bb_range (irange &r, const_basic_block bb) override; + virtual bool set_bb_range (const_basic_block bb, const vrange &r) override; + virtual bool get_bb_range (vrange &r, const_basic_block bb) override; virtual bool bb_range_p (const_basic_block bb) override; protected: - irange **m_tab; // Non growing vector. + vrange **m_tab; // Non growing vector. int m_tab_size; - int_range<2> m_varying; - int_range<2> m_undefined; + vrange *m_varying; + vrange *m_undefined; tree m_type; - irange_allocator *m_irange_allocator; + vrange_allocator *m_range_allocator; void grow (); }; // Initialize a block cache for an ssa_name of type T. -sbr_vector::sbr_vector (tree t, irange_allocator *allocator) +sbr_vector::sbr_vector (tree t, vrange_allocator *allocator) + : ssa_block_ranges (t) { gcc_checking_assert (TYPE_P (t)); m_type = t; - m_irange_allocator = allocator; + m_range_allocator = allocator; m_tab_size = last_basic_block_for_fn (cfun) + 1; - m_tab = (irange **)allocator->get_memory (m_tab_size * sizeof (irange *)); - memset (m_tab, 0, m_tab_size * sizeof (irange *)); + m_tab = static_cast <vrange **> + (allocator->alloc (m_tab_size * sizeof (vrange *))); + memset (m_tab, 0, m_tab_size * sizeof (vrange *)); // Create the cached type range. - m_varying.set_varying (t); - m_undefined.set_undefined (); + m_varying = m_range_allocator->alloc_vrange (t); + m_undefined = m_range_allocator->alloc_vrange (t); + m_varying->set_varying (t); + m_undefined->set_undefined (); } // Grow the vector when the CFG has increased in size. @@ -121,10 +128,10 @@ sbr_vector::grow () int new_size = inc + curr_bb_size; // Allocate new memory, copy the old vector and clear the new space. - irange **t = (irange **)m_irange_allocator->get_memory (new_size - * sizeof (irange *)); - memcpy (t, m_tab, m_tab_size * sizeof (irange *)); - memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *)); + vrange **t = static_cast <vrange **> + (m_range_allocator->alloc (new_size * sizeof (vrange *))); + memcpy (t, m_tab, m_tab_size * sizeof (vrange *)); + memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (vrange *)); m_tab = t; m_tab_size = new_size; @@ -133,17 +140,17 @@ sbr_vector::grow () // Set the range for block BB to be R. bool -sbr_vector::set_bb_range (const_basic_block bb, const irange &r) +sbr_vector::set_bb_range (const_basic_block bb, const vrange &r) { - irange *m; + vrange *m; if (bb->index >= m_tab_size) grow (); if (r.varying_p ()) - m = &m_varying; + m = m_varying; else if (r.undefined_p ()) - m = &m_undefined; + m = m_undefined; else - m = m_irange_allocator->allocate (r); + m = m_range_allocator->clone (r); m_tab[bb->index] = m; return true; } @@ -152,11 +159,11 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r) // there is no range. bool -sbr_vector::get_bb_range (irange &r, const_basic_block bb) +sbr_vector::get_bb_range (vrange &r, const_basic_block bb) { if (bb->index >= m_tab_size) return false; - irange *m = m_tab[bb->index]; + vrange *m = m_tab[bb->index]; if (m) { r = *m; @@ -191,38 +198,39 @@ sbr_vector::bb_range_p (const_basic_block bb) class sbr_sparse_bitmap : public ssa_block_ranges { public: - sbr_sparse_bitmap (tree t, irange_allocator *allocator, bitmap_obstack *bm); - virtual bool set_bb_range (const_basic_block bb, const irange &r) override; - virtual bool get_bb_range (irange &r, const_basic_block bb) override; + sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm); + virtual bool set_bb_range (const_basic_block bb, const vrange &r) override; + virtual bool get_bb_range (vrange &r, const_basic_block bb) override; virtual bool bb_range_p (const_basic_block bb) override; private: void bitmap_set_quad (bitmap head, int quad, int quad_value); int bitmap_get_quad (const_bitmap head, int quad); - irange_allocator *m_irange_allocator; - irange *m_range[SBR_NUM]; + vrange_allocator *m_range_allocator; + vrange *m_range[SBR_NUM]; bitmap_head bitvec; tree m_type; }; // Initialize a block cache for an ssa_name of type T. -sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, irange_allocator *allocator, - bitmap_obstack *bm) +sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator, + bitmap_obstack *bm) + : ssa_block_ranges (t) { gcc_checking_assert (TYPE_P (t)); m_type = t; bitmap_initialize (&bitvec, bm); bitmap_tree_view (&bitvec); - m_irange_allocator = allocator; + m_range_allocator = allocator; // Pre-cache varying. - m_range[0] = m_irange_allocator->allocate (2); + m_range[0] = m_range_allocator->alloc_vrange (t); m_range[0]->set_varying (t); // Pre-cache zero and non-zero values for pointers. if (POINTER_TYPE_P (t)) { - m_range[1] = m_irange_allocator->allocate (2); + m_range[1] = m_range_allocator->alloc_vrange (t); m_range[1]->set_nonzero (t); - m_range[2] = m_irange_allocator->allocate (2); + m_range[2] = m_range_allocator->alloc_vrange (t); m_range[2]->set_zero (t); } else @@ -254,7 +262,7 @@ sbr_sparse_bitmap::bitmap_get_quad (const_bitmap head, int quad) // Set the range on entry to basic block BB to R. bool -sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r) +sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const vrange &r) { if (r.undefined_p ()) { @@ -267,7 +275,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r) if (!m_range[x] || r == *(m_range[x])) { if (!m_range[x]) - m_range[x] = m_irange_allocator->allocate (r); + m_range[x] = m_range_allocator->clone (r); bitmap_set_quad (&bitvec, bb->index, x + 1); return true; } @@ -280,7 +288,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r) // there is no range. bool -sbr_sparse_bitmap::get_bb_range (irange &r, const_basic_block bb) +sbr_sparse_bitmap::get_bb_range (vrange &r, const_basic_block bb) { int value = bitmap_get_quad (&bitvec, bb->index); @@ -312,14 +320,14 @@ block_range_cache::block_range_cache () bitmap_obstack_initialize (&m_bitmaps); m_ssa_ranges.create (0); m_ssa_ranges.safe_grow_cleared (num_ssa_names); - m_irange_allocator = new irange_allocator; + m_range_allocator = new vrange_allocator; } // Remove any m_block_caches which have been created. block_range_cache::~block_range_cache () { - delete m_irange_allocator; + delete m_range_allocator; // Release the vector itself. m_ssa_ranges.release (); bitmap_obstack_release (&m_bitmaps); @@ -330,7 +338,7 @@ block_range_cache::~block_range_cache () bool block_range_cache::set_bb_range (tree name, const_basic_block bb, - const irange &r) + const vrange &r) { unsigned v = SSA_NAME_VERSION (name); if (v >= m_ssa_ranges.length ()) @@ -341,17 +349,17 @@ block_range_cache::set_bb_range (tree name, const_basic_block bb, // Use sparse representation if there are too many basic blocks. if (last_basic_block_for_fn (cfun) > param_evrp_sparse_threshold) { - void *r = m_irange_allocator->get_memory (sizeof (sbr_sparse_bitmap)); + void *r = m_range_allocator->alloc (sizeof (sbr_sparse_bitmap)); m_ssa_ranges[v] = new (r) sbr_sparse_bitmap (TREE_TYPE (name), - m_irange_allocator, + m_range_allocator, &m_bitmaps); } else { // Otherwise use the default vector implemntation. - void *r = m_irange_allocator->get_memory (sizeof (sbr_vector)); + void *r = m_range_allocator->alloc (sizeof (sbr_vector)); m_ssa_ranges[v] = new (r) sbr_vector (TREE_TYPE (name), - m_irange_allocator); + m_range_allocator); } } return m_ssa_ranges[v]->set_bb_range (bb, r); @@ -376,7 +384,7 @@ block_range_cache::query_block_ranges (tree name) // is one. bool -block_range_cache::get_bb_range (irange &r, tree name, const_basic_block bb) +block_range_cache::get_bb_range (vrange &r, tree name, const_basic_block bb) { ssa_block_ranges *ptr = query_block_ranges (name); if (ptr) @@ -420,12 +428,13 @@ void block_range_cache::dump (FILE *f, basic_block bb, bool print_varying) { unsigned x; - int_range_max r; bool summarize_varying = false; for (x = 1; x < m_ssa_ranges.length (); ++x) { if (!gimple_range_ssa_p (ssa_name (x))) continue; + + Value_Range r (TREE_TYPE (ssa_name (x))); if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb)) { if (!print_varying && r.varying_p ()) @@ -447,6 +456,8 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying) { if (!gimple_range_ssa_p (ssa_name (x))) continue; + + Value_Range r (TREE_TYPE (ssa_name (x))); if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb)) { if (r.varying_p ()) @@ -467,7 +478,7 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying) ssa_global_cache::ssa_global_cache () { m_tab.create (0); - m_irange_allocator = new irange_allocator; + m_range_allocator = new vrange_allocator; } // Deconstruct a global cache. @@ -475,20 +486,20 @@ ssa_global_cache::ssa_global_cache () ssa_global_cache::~ssa_global_cache () { m_tab.release (); - delete m_irange_allocator; + delete m_range_allocator; } // Retrieve the global range of NAME from cache memory if it exists. // Return the value in R. bool -ssa_global_cache::get_global_range (irange &r, tree name) const +ssa_global_cache::get_global_range (vrange &r, tree name) const { unsigned v = SSA_NAME_VERSION (name); if (v >= m_tab.length ()) return false; - irange *stow = m_tab[v]; + vrange *stow = m_tab[v]; if (!stow) return false; r = *stow; @@ -499,17 +510,17 @@ ssa_global_cache::get_global_range (irange &r, tree name) const // Return TRUE if there was already a range set, otherwise false. bool -ssa_global_cache::set_global_range (tree name, const irange &r) +ssa_global_cache::set_global_range (tree name, const vrange &r) { unsigned v = SSA_NAME_VERSION (name); if (v >= m_tab.length ()) m_tab.safe_grow_cleared (num_ssa_names + 1); - irange *m = m_tab[v]; + vrange *m = m_tab[v]; if (m && m->fits_p (r)) *m = r; else - m_tab[v] = m_irange_allocator->allocate (r); + m_tab[v] = m_range_allocator->clone (r); return m != NULL; } @@ -530,7 +541,7 @@ void ssa_global_cache::clear () { if (m_tab.address ()) - memset (m_tab.address(), 0, m_tab.length () * sizeof (irange *)); + memset (m_tab.address(), 0, m_tab.length () * sizeof (vrange *)); } // Dump the contents of the global cache to F. @@ -542,9 +553,10 @@ ssa_global_cache::dump (FILE *f) bool print_header = true; for (unsigned x = 1; x < num_ssa_names; x++) { - int_range_max r; - if (gimple_range_ssa_p (ssa_name (x)) && - get_global_range (r, ssa_name (x)) && !r.varying_p ()) + if (!gimple_range_ssa_p (ssa_name (x))) + continue; + Value_Range r (TREE_TYPE (ssa_name (x))); + if (get_global_range (r, ssa_name (x)) && !r.varying_p ()) { if (print_header) { @@ -806,11 +818,11 @@ ranger_cache::dump_bb (FILE *f, basic_block bb) // global range is not set, and return the legacy global value in R. bool -ranger_cache::get_global_range (irange &r, tree name) const +ranger_cache::get_global_range (vrange &r, tree name) const { if (m_globals.get_global_range (r, name)) return true; - r = gimple_range_global (name); + gimple_range_global (r, name); return false; } @@ -822,7 +834,7 @@ ranger_cache::get_global_range (irange &r, tree name) const // After this call, the global cache will have a value. bool -ranger_cache::get_global_range (irange &r, tree name, bool ¤t_p) +ranger_cache::get_global_range (vrange &r, tree name, bool ¤t_p) { bool had_global = get_global_range (r, name); @@ -844,7 +856,7 @@ ranger_cache::get_global_range (irange &r, tree name, bool ¤t_p) // Set the global range of NAME to R and give it a timestamp. void -ranger_cache::set_global_range (tree name, const irange &r) +ranger_cache::set_global_range (tree name, const vrange &r) { if (m_globals.set_global_range (name, r)) { @@ -879,7 +891,7 @@ ranger_cache::set_global_range (tree name, const irange &r) // get the best global value available. void -ranger_cache::range_of_def (irange &r, tree name, basic_block bb) +ranger_cache::range_of_def (vrange &r, tree name, basic_block bb) { gcc_checking_assert (gimple_range_ssa_p (name)); gcc_checking_assert (!bb || bb == gimple_bb (SSA_NAME_DEF_STMT (name))); @@ -892,7 +904,7 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb) if (gimple_get_lhs (s) == name) fold_range (r, s, get_global_range_query ()); else - r = gimple_range_global (name); + gimple_range_global (r, name); } } @@ -900,12 +912,12 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb) // lookups. void -ranger_cache::entry_range (irange &r, tree name, basic_block bb, +ranger_cache::entry_range (vrange &r, tree name, basic_block bb, enum rfd_mode mode) { if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) { - r = gimple_range_global (name); + gimple_range_global (r, name); return; } @@ -920,12 +932,12 @@ ranger_cache::entry_range (irange &r, tree name, basic_block bb, // lookups. void -ranger_cache::exit_range (irange &r, tree name, basic_block bb, +ranger_cache::exit_range (vrange &r, tree name, basic_block bb, enum rfd_mode mode) { if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) { - r = gimple_range_global (name); + gimple_range_global (r, name); return; } @@ -941,7 +953,7 @@ ranger_cache::exit_range (irange &r, tree name, basic_block bb, // Always returns a range and true. bool -ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode) +ranger_cache::edge_range (vrange &r, edge e, tree name, enum rfd_mode mode) { exit_range (r, name, e->src, mode); // If this is not an abnormal edge, check for inferred ranges on exit. @@ -958,7 +970,7 @@ ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode) // Implement range_of_expr. bool -ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt) +ranger_cache::range_of_expr (vrange &r, tree name, gimple *stmt) { if (!gimple_range_ssa_p (name)) { @@ -982,7 +994,7 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt) // the current cache values. bool -ranger_cache::range_on_edge (irange &r, edge e, tree expr) +ranger_cache::range_on_edge (vrange &r, edge e, tree expr) { if (gimple_range_ssa_p (expr)) return edge_range (r, e, expr, RFD_NONE); @@ -994,7 +1006,7 @@ ranger_cache::range_on_edge (irange &r, edge e, tree expr) // def block for NAME. Otherwise, return false if the cache is empty. bool -ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc) +ranger_cache::block_range (vrange &r, basic_block bb, tree name, bool calc) { gcc_checking_assert (gimple_range_ssa_p (name)); @@ -1038,9 +1050,10 @@ ranger_cache::propagate_cache (tree name) basic_block bb; edge_iterator ei; edge e; - int_range_max new_range; - int_range_max current_range; - int_range_max e_range; + tree type = TREE_TYPE (name); + Value_Range new_range (type); + Value_Range current_range (type); + Value_Range e_range (type); // Process each block by seeing if its calculated range on entry is // the same as its cached value. If there is a difference, update @@ -1175,8 +1188,8 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) { edge_iterator ei; edge e; - int_range_max block_result; - int_range_max undefined; + Value_Range block_result (TREE_TYPE (name)); + Value_Range undefined (TREE_TYPE (name)); // At this point we shouldn't be looking at the def, entry or exit block. gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) && @@ -1229,7 +1242,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) FOR_EACH_EDGE (e, ei, node->preds) { basic_block pred = e->src; - int_range_max r; + Value_Range r (TREE_TYPE (name)); if (DEBUG_RANGE_CACHE) fprintf (dump_file, " %d->%d ",e->src->index, e->dest->index); @@ -1303,7 +1316,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) // dominator tree based on MODE. bool -ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, +ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb, enum rfd_mode mode) { if (mode == RFD_NONE || !dom_info_available_p (CDI_DOMINATORS)) @@ -1359,7 +1372,7 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb, // each incoming edge now and accumulate the results. r.set_undefined (); edge_iterator ei; - int_range_max er; + Value_Range er (TREE_TYPE (name)); FOR_EACH_EDGE (e, ei, prev_bb->preds) { edge_range (er, e, name, RFD_READ_ONLY); diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index d56e56c..1e4b5b3 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -34,8 +34,8 @@ public: block_range_cache (); ~block_range_cache (); - bool set_bb_range (tree name, const_basic_block bb, const irange &r); - bool get_bb_range (irange &r, tree name, const_basic_block bb); + bool set_bb_range (tree name, const_basic_block bb, const vrange &v); + bool get_bb_range (vrange &v, tree name, const_basic_block bb); bool bb_range_p (tree name, const_basic_block bb); void dump (FILE *f); @@ -44,7 +44,7 @@ private: vec<class ssa_block_ranges *> m_ssa_ranges; ssa_block_ranges &get_block_ranges (tree name); ssa_block_ranges *query_block_ranges (tree name); - irange_allocator *m_irange_allocator; + vrange_allocator *m_range_allocator; bitmap_obstack m_bitmaps; }; @@ -57,14 +57,14 @@ class ssa_global_cache public: ssa_global_cache (); ~ssa_global_cache (); - bool get_global_range (irange &r, tree name) const; - bool set_global_range (tree name, const irange &r); + bool get_global_range (vrange &r, tree name) const; + bool set_global_range (tree name, const vrange &r); void clear_global_range (tree name); void clear (); void dump (FILE *f = stderr); private: - vec<irange *> m_tab; - class irange_allocator *m_irange_allocator; + vec<vrange *> m_tab; + vrange_allocator *m_range_allocator; }; // This class provides all the caches a global ranger may need, and makes @@ -77,13 +77,13 @@ public: ranger_cache (int not_executable_flag, bool use_imm_uses); ~ranger_cache (); - virtual bool range_of_expr (irange &r, tree name, gimple *stmt); - virtual bool range_on_edge (irange &r, edge e, tree expr); - bool block_range (irange &r, basic_block bb, tree name, bool calc = true); + virtual bool range_of_expr (vrange &r, tree name, gimple *stmt); + virtual bool range_on_edge (vrange &r, edge e, tree expr); + bool block_range (vrange &r, basic_block bb, tree name, bool calc = true); - bool get_global_range (irange &r, tree name) const; - bool get_global_range (irange &r, tree name, bool ¤t_p); - void set_global_range (tree name, const irange &r); + bool get_global_range (vrange &r, tree name) const; + bool get_global_range (vrange &r, tree name, bool ¤t_p); + void set_global_range (tree name, const vrange &r); void propagate_updated_value (tree name, basic_block bb); @@ -106,11 +106,11 @@ private: RFD_READ_ONLY, // Scan DOM tree, do not write to cache. RFD_FILL // Scan DOM tree, updating important nodes. }; - bool range_from_dom (irange &r, tree name, basic_block bb, enum rfd_mode); - void range_of_def (irange &r, tree name, basic_block bb = NULL); - void entry_range (irange &r, tree expr, basic_block bb, enum rfd_mode); - void exit_range (irange &r, tree expr, basic_block bb, enum rfd_mode); - bool edge_range (irange &r, edge e, tree name, enum rfd_mode); + bool range_from_dom (vrange &r, tree name, basic_block bb, enum rfd_mode); + void range_of_def (vrange &r, tree name, basic_block bb = NULL); + void entry_range (vrange &r, tree expr, basic_block bb, enum rfd_mode); + void exit_range (vrange &r, tree expr, basic_block bb, enum rfd_mode); + bool edge_range (vrange &r, edge e, tree name, enum rfd_mode); vec<basic_block> m_workback; class update_list *m_update; diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc index 0bee38b..03a804a 100644 --- a/gcc/gimple-range-edge.cc +++ b/gcc/gimple-range-edge.cc @@ -42,10 +42,9 @@ gimple_outgoing_range_stmt_p (basic_block bb) if (!gsi_end_p (gsi)) { gimple *s = gsi_stmt (gsi); - if (is_a<gcond *> (s) && gimple_range_handler (s)) + if (is_a<gcond *> (s) && range_op_handler (s)) return gsi_stmt (gsi); - gswitch *sw = dyn_cast<gswitch *> (s); - if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw)))) + if (is_a <gswitch *> (s)) return gsi_stmt (gsi); } return NULL; @@ -83,11 +82,8 @@ gimple_outgoing_range::~gimple_outgoing_range () // Use a cached value if it exists, or calculate it if not. bool -gimple_outgoing_range::get_edge_range (irange &r, gimple *s, edge e) +gimple_outgoing_range::switch_edge_range (irange &r, gswitch *sw, edge e) { - gcc_checking_assert (is_a<gswitch *> (s)); - gswitch *sw = as_a<gswitch *> (s); - // ADA currently has cases where the index is 64 bits and the case // arguments are 32 bit, causing a trap when we create a case_range. // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798) @@ -166,13 +162,13 @@ gimple_outgoing_range::calc_switch_ranges (gswitch *sw) // If there was an existing range and it doesn't fit, we lose the memory. // It'll get reclaimed when the obstack is freed. This seems less // intrusive than allocating max ranges for each case. - slot = m_range_allocator.allocate (case_range); + slot = m_range_allocator.clone <irange> (case_range); } irange *&slot = m_edge_table->get_or_insert (default_edge, &existed); // This should be the first call into this switch. gcc_checking_assert (!existed); - irange *dr = m_range_allocator.allocate (default_range); + irange *dr = m_range_allocator.clone <irange> (default_range); slot = dr; } @@ -204,12 +200,9 @@ gimple_outgoing_range::edge_range_p (irange &r, edge e) gcc_checking_assert (is_a<gswitch *> (s)); gswitch *sw = as_a<gswitch *> (s); - tree type = TREE_TYPE (gimple_switch_index (sw)); - - if (!irange::supports_type_p (type)) - return NULL; - if (get_edge_range (r, sw, e)) + // Switches can only be integers. + if (switch_edge_range (as_a <irange> (r), sw, e)) return s; return NULL; diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h index c131b33..a9c4af8 100644 --- a/gcc/gimple-range-edge.h +++ b/gcc/gimple-range-edge.h @@ -43,11 +43,11 @@ public: gimple *edge_range_p (irange &r, edge e); private: void calc_switch_ranges (gswitch *sw); - bool get_edge_range (irange &r, gimple *s, edge e); + bool switch_edge_range (irange &r, gswitch *sw, edge e); int m_max_edges; hash_map<edge, irange *> *m_edge_table; - irange_allocator m_range_allocator; + vrange_allocator m_range_allocator; }; // If there is a range control statement at the end of block BB, return it. diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 0a947c1..2a8c66e 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -60,7 +60,7 @@ fur_source::fur_source (range_query *q) // Invoke range_of_expr on EXPR. bool -fur_source::get_operand (irange &r, tree expr) +fur_source::get_operand (vrange &r, tree expr) { return m_query->range_of_expr (r, expr); } @@ -69,7 +69,7 @@ fur_source::get_operand (irange &r, tree expr) // range_query to get the range on the edge. bool -fur_source::get_phi_operand (irange &r, tree expr, edge e) +fur_source::get_phi_operand (vrange &r, tree expr, edge e) { return m_query->range_on_edge (r, e, expr); } @@ -109,8 +109,8 @@ class fur_edge : public fur_source { public: fur_edge (edge e, range_query *q = NULL); - virtual bool get_operand (irange &r, tree expr) override; - virtual bool get_phi_operand (irange &r, tree expr, edge e) override; + virtual bool get_operand (vrange &r, tree expr) override; + virtual bool get_phi_operand (vrange &r, tree expr, edge e) override; private: edge m_edge; }; @@ -126,7 +126,7 @@ fur_edge::fur_edge (edge e, range_query *q) : fur_source (q) // Get the value of EXPR on edge m_edge. bool -fur_edge::get_operand (irange &r, tree expr) +fur_edge::get_operand (vrange &r, tree expr) { return m_query->range_on_edge (r, m_edge, expr); } @@ -135,7 +135,7 @@ fur_edge::get_operand (irange &r, tree expr) // range_query to get the range on the edge. bool -fur_edge::get_phi_operand (irange &r, tree expr, edge e) +fur_edge::get_phi_operand (vrange &r, tree expr, edge e) { // Edge to edge recalculations not supoprted yet, until we sort it out. gcc_checking_assert (e == m_edge); @@ -152,7 +152,7 @@ fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q) // Retreive range of EXPR as it occurs as a use on stmt M_STMT. bool -fur_stmt::get_operand (irange &r, tree expr) +fur_stmt::get_operand (vrange &r, tree expr) { return m_query->range_of_expr (r, expr, m_stmt); } @@ -161,7 +161,7 @@ fur_stmt::get_operand (irange &r, tree expr) // range_query to get the range on the edge. bool -fur_stmt::get_phi_operand (irange &r, tree expr, edge e) +fur_stmt::get_phi_operand (vrange &r, tree expr, edge e) { // Pick up the range of expr from edge E. fur_edge e_src (e, m_query); @@ -214,42 +214,42 @@ fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2) class fur_list : public fur_source { public: - fur_list (irange &r1); - fur_list (irange &r1, irange &r2); - fur_list (unsigned num, irange *list); - virtual bool get_operand (irange &r, tree expr) override; - virtual bool get_phi_operand (irange &r, tree expr, edge e) override; + fur_list (vrange &r1); + fur_list (vrange &r1, vrange &r2); + fur_list (unsigned num, vrange **list); + virtual bool get_operand (vrange &r, tree expr) override; + virtual bool get_phi_operand (vrange &r, tree expr, edge e) override; private: - int_range_max m_local[2]; - irange *m_list; + vrange *m_local[2]; + vrange **m_list; unsigned m_index; unsigned m_limit; }; // One range supplied for unary operations. -fur_list::fur_list (irange &r1) : fur_source (NULL) +fur_list::fur_list (vrange &r1) : fur_source (NULL) { m_list = m_local; m_index = 0; m_limit = 1; - m_local[0] = r1; + m_local[0] = &r1; } // Two ranges supplied for binary operations. -fur_list::fur_list (irange &r1, irange &r2) : fur_source (NULL) +fur_list::fur_list (vrange &r1, vrange &r2) : fur_source (NULL) { m_list = m_local; m_index = 0; m_limit = 2; - m_local[0] = r1; - m_local[1] = r2; + m_local[0] = &r1; + m_local[1] = &r2; } // Arbitrary number of ranges in a vector. -fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL) +fur_list::fur_list (unsigned num, vrange **list) : fur_source (NULL) { m_list = list; m_index = 0; @@ -259,18 +259,18 @@ fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL) // Get the next operand from the vector, ensure types are compatible. bool -fur_list::get_operand (irange &r, tree expr) +fur_list::get_operand (vrange &r, tree expr) { if (m_index >= m_limit) return m_query->range_of_expr (r, expr); - r = m_list[m_index++]; + r = *m_list[m_index++]; gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ())); return true; } // This will simply pick the next operand from the vector. bool -fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED) +fur_list::get_phi_operand (vrange &r, tree expr, edge e ATTRIBUTE_UNUSED) { return get_operand (r, expr); } @@ -278,7 +278,7 @@ fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED) // Fold stmt S into range R using R1 as the first operand. bool -fold_range (irange &r, gimple *s, irange &r1) +fold_range (vrange &r, gimple *s, vrange &r1) { fold_using_range f; fur_list src (r1); @@ -288,7 +288,7 @@ fold_range (irange &r, gimple *s, irange &r1) // Fold stmt S into range R using R1 and R2 as the first two operands. bool -fold_range (irange &r, gimple *s, irange &r1, irange &r2) +fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2) { fold_using_range f; fur_list src (r1, r2); @@ -299,7 +299,7 @@ fold_range (irange &r, gimple *s, irange &r1, irange &r2) // operands encountered. bool -fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector) +fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector) { fold_using_range f; fur_list src (num_elements, vector); @@ -309,7 +309,7 @@ fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector) // Fold stmt S into range R using range query Q. bool -fold_range (irange &r, gimple *s, range_query *q) +fold_range (vrange &r, gimple *s, range_query *q) { fold_using_range f; fur_stmt src (s, q); @@ -319,7 +319,7 @@ fold_range (irange &r, gimple *s, range_query *q) // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE. bool -fold_range (irange &r, gimple *s, edge on_edge, range_query *q) +fold_range (vrange &r, gimple *s, edge on_edge, range_query *q) { fold_using_range f; fur_edge src (on_edge, q); @@ -370,7 +370,7 @@ adjust_pointer_diff_expr (irange &res, const gimple *diff_stmt) // Adjust the range for an IMAGPART_EXPR. static void -adjust_imagpart_expr (irange &res, const gimple *stmt) +adjust_imagpart_expr (vrange &res, const gimple *stmt) { tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); @@ -413,7 +413,7 @@ adjust_imagpart_expr (irange &res, const gimple *stmt) // Adjust the range for a REALPART_EXPR. static void -adjust_realpart_expr (irange &res, const gimple *stmt) +adjust_realpart_expr (vrange &res, const gimple *stmt) { tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); @@ -442,12 +442,12 @@ adjust_realpart_expr (irange &res, const gimple *stmt) // this statement. static void -gimple_range_adjustment (irange &res, const gimple *stmt) +gimple_range_adjustment (vrange &res, const gimple *stmt) { switch (gimple_expr_code (stmt)) { case POINTER_DIFF_EXPR: - adjust_pointer_diff_expr (res, stmt); + adjust_pointer_diff_expr (as_a <irange> (res), stmt); return; case IMAGPART_EXPR: @@ -482,7 +482,7 @@ gimple_range_base_of_assignment (const gimple *stmt) tree gimple_range_operand1 (const gimple *stmt) { - gcc_checking_assert (gimple_range_handler (stmt)); + gcc_checking_assert (range_op_handler (stmt)); switch (gimple_code (stmt)) { @@ -515,7 +515,7 @@ gimple_range_operand1 (const gimple *stmt) tree gimple_range_operand2 (const gimple *stmt) { - gcc_checking_assert (gimple_range_handler (stmt)); + gcc_checking_assert (range_op_handler (stmt)); switch (gimple_code (stmt)) { @@ -536,7 +536,7 @@ gimple_range_operand2 (const gimple *stmt) // be calculated, return false. bool -fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name) +fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name) { bool res = false; // If name and S are specified, make sure it is an LHS of S. @@ -549,9 +549,9 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name) // Process addresses. if (gimple_code (s) == GIMPLE_ASSIGN && gimple_assign_rhs_code (s) == ADDR_EXPR) - return range_of_address (r, s, src); + return range_of_address (as_a <irange> (r), s, src); - if (gimple_range_handler (s)) + if (range_op_handler (s)) res = range_of_range_op (r, s, src); else if (is_a<gphi *>(s)) res = range_of_phi (r, as_a<gphi *> (s), src); @@ -566,7 +566,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name) if (!name || !gimple_range_ssa_p (name)) return false; // We don't understand the stmt, so return the global range. - r = gimple_range_global (name); + gimple_range_global (r, name); return true; } @@ -587,32 +587,34 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name) // If a range cannot be calculated, return false. bool -fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src) +fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src) { - int_range_max range1, range2; tree type = gimple_range_type (s); if (!type) return false; - range_operator *handler = gimple_range_handler (s); + range_op_handler handler (s); gcc_checking_assert (handler); tree lhs = gimple_get_lhs (s); tree op1 = gimple_range_operand1 (s); tree op2 = gimple_range_operand2 (s); + Value_Range range1 (TREE_TYPE (op1)); + Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1)); if (src.get_operand (range1, op1)) { if (!op2) { // Fold range, and register any dependency if available. - int_range<2> r2 (type); - handler->fold_range (r, type, range1, r2); + Value_Range r2 (type); + r2.set_varying (type); + handler.fold_range (r, type, range1, r2); if (lhs && gimple_range_ssa_p (op1)) { if (src.gori ()) src.gori ()->register_dependency (lhs, op1); relation_kind rel; - rel = handler->lhs_op1_relation (r, range1, range1); + rel = handler.lhs_op1_relation (r, range1, range1); if (rel != VREL_VARYING) src.register_relation (s, rel, lhs, op1); } @@ -629,8 +631,9 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src) fputc ('\n', dump_file); } // Fold range, and register any dependency if available. - handler->fold_range (r, type, range1, range2, rel); - relation_fold_and_or (r, s, src); + handler.fold_range (r, type, range1, range2, rel); + if (irange::supports_p (type)) + relation_fold_and_or (as_a <irange> (r), s, src); if (lhs) { if (src.gori ()) @@ -640,13 +643,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src) } if (gimple_range_ssa_p (op1)) { - rel = handler->lhs_op1_relation (r, range1, range2, rel); + rel = handler.lhs_op1_relation (r, range1, range2, rel); if (rel != VREL_VARYING) src.register_relation (s, rel, lhs, op1); } if (gimple_range_ssa_p (op2)) { - rel= handler->lhs_op2_relation (r, range1, range2, rel); + rel= handler.lhs_op2_relation (r, range1, range2, rel); if (rel != VREL_VARYING) src.register_relation (s, rel, lhs, op2); } @@ -663,7 +666,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src) e0 = NULL; if (!single_pred_p (e1->dest)) e1 = NULL; - src.register_outgoing_edges (as_a<gcond *> (s), r, e0, e1); + src.register_outgoing_edges (as_a<gcond *> (s), + as_a <irange> (r), e0, e1); } } else @@ -705,7 +709,6 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) tree lhs = gimple_get_lhs (stmt); if (lhs && gimple_range_ssa_p (ssa) && src.gori ()) src.gori ()->register_dependency (lhs, ssa); - gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa))); src.get_operand (r, ssa); range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt))); @@ -729,12 +732,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) { /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't allow going from non-NULL pointer to NULL. */ - if (!range_includes_zero_p (&r)) + if (r.undefined_p () || !r.contains_p (build_zero_cst (r.type ()))) { /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT using POINTER_PLUS_EXPR if off_cst and just fall back to this. */ - r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); + r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } } @@ -746,22 +749,22 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) && known_ne (off, 0) && (flag_delete_null_pointer_checks || known_gt (off, 0))) { - r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); + r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } - r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); + r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } // Handle "= &a". if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p)) { - r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); + r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } // Otherwise return varying. - r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt))); + r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt))); return true; } @@ -769,12 +772,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src) // If a range cannot be calculated, return false. bool -fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src) +fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src) { tree phi_def = gimple_phi_result (phi); tree type = gimple_range_type (phi); - int_range_max arg_range; - int_range_max equiv_range; + Value_Range arg_range (type); + Value_Range equiv_range (type); unsigned x; if (!type) @@ -881,7 +884,7 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src) // If a range cannot be calculated, return false. bool -fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src) +fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src) { tree type = gimple_range_type (call); if (!type) @@ -893,18 +896,18 @@ fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src) if (range_of_builtin_call (r, call, src)) ; else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p)) - r.set (build_int_cst (type, 0), TYPE_MAX_VALUE (type)); + r.set_nonnegative (type); else if (gimple_call_nonnull_result_p (call) || gimple_call_nonnull_arg (call)) - r = range_nonzero (type); + r.set_nonzero (type); else r.set_varying (type); // If there is an LHS, intersect that with what is known. if (lhs) { - value_range def; - def = gimple_range_global (lhs); + Value_Range def (TREE_TYPE (lhs)); + gimple_range_global (def, lhs); r.intersect (def); } return true; @@ -921,7 +924,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call, gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR || code == MULT_EXPR); tree type = gimple_range_type (call); - range_operator *op = range_op_handler (code, type); + range_op_handler op (code, type); gcc_checking_assert (op); int_range_max ir0, ir1; tree arg0 = gimple_call_arg (call, 0); @@ -935,7 +938,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call, // Pretend the arithmetic is wrapping. If there is any overflow, // we'll complain, but will actually do wrapping operation. flag_wrapv = 1; - op->fold_range (r, type, ir0, ir1, relation); + op.fold_range (r, type, ir0, ir1, relation); flag_wrapv = saved_flag_wrapv; // If for both arguments vrp_valueize returned non-NULL, this should @@ -971,7 +974,7 @@ get_letter_range (tree type, irange &lowers, irange &uppers) // TRUE. Otherwise return FALSE. bool -fold_using_range::range_of_builtin_call (irange &r, gcall *call, +fold_using_range::range_of_builtin_call (vrange &r, gcall *call, fur_source &src) { combined_fn func = gimple_call_combined_fn (call); @@ -979,6 +982,23 @@ fold_using_range::range_of_builtin_call (irange &r, gcall *call, return false; tree type = gimple_range_type (call); + gcc_checking_assert (type); + + if (irange::supports_p (type)) + return range_of_builtin_int_call (as_a <irange> (r), call, src); + + return false; +} + +bool +fold_using_range::range_of_builtin_int_call (irange &r, gcall *call, + fur_source &src) +{ + combined_fn func = gimple_call_combined_fn (call); + if (func == CFN_LAST) + return false; + + tree type = gimple_range_type (call); tree arg; int mini, maxi, zerov = 0, prec; scalar_int_mode mode; @@ -1256,9 +1276,8 @@ fold_using_range::range_of_builtin_call (irange &r, gcall *call, // If a range cannot be calculated, return false. bool -fold_using_range::range_of_cond_expr (irange &r, gassign *s, fur_source &src) +fold_using_range::range_of_cond_expr (vrange &r, gassign *s, fur_source &src) { - int_range_max cond_range, range1, range2; tree cond = gimple_assign_rhs1 (s); tree op1 = gimple_assign_rhs2 (s); tree op2 = gimple_assign_rhs3 (s); @@ -1267,6 +1286,9 @@ fold_using_range::range_of_cond_expr (irange &r, gassign *s, fur_source &src) if (!type) return false; + Value_Range range1 (TREE_TYPE (op1)); + Value_Range range2 (TREE_TYPE (op2)); + Value_Range cond_range (TREE_TYPE (cond)); gcc_checking_assert (gimple_assign_rhs_code (s) == COND_EXPR); gcc_checking_assert (range_compatible_p (TREE_TYPE (op1), TREE_TYPE (op2))); src.get_operand (cond_range, cond); @@ -1391,8 +1413,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1) return; - range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1)); - range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2)); + range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1)); + range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2)); // If either handler is not present, no relation is found. if (!handler1 || !handler2) @@ -1400,8 +1422,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, int_range<2> bool_one (boolean_true_node, boolean_true_node); - relation_kind relation1 = handler1->op1_op2_relation (bool_one); - relation_kind relation2 = handler2->op1_op2_relation (bool_one); + relation_kind relation1 = handler1.op1_op2_relation (bool_one); + relation_kind relation2 = handler2.op1_op2_relation (bool_one); if (relation1 == VREL_VARYING || relation2 == VREL_VARYING) return; @@ -1438,10 +1460,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, void 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; tree name; - range_operator *handler; basic_block bb = gimple_bb (s); if (e0) @@ -1472,17 +1492,17 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s)); if (ssa1 && ssa2) { - handler = gimple_range_handler (s); + range_op_handler handler (s); gcc_checking_assert (handler); if (e0) { - relation_kind relation = handler->op1_op2_relation (e0_range); + relation_kind relation = handler.op1_op2_relation (e0_range); if (relation != VREL_VARYING) register_relation (e0, relation, ssa1, ssa2); } if (e1) { - relation_kind relation = handler->op1_op2_relation (e1_range); + relation_kind relation = handler.op1_op2_relation (e1_range); if (relation != VREL_VARYING) register_relation (e1, relation, ssa1, ssa2); } @@ -1501,24 +1521,25 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE) continue; gimple *stmt = SSA_NAME_DEF_STMT (name); - handler = gimple_range_handler (stmt); + range_op_handler handler (stmt); if (!handler) continue; tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); + Value_Range r (TREE_TYPE (name)); if (ssa1 && ssa2) { if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query) && r.singleton_p ()) { - relation_kind relation = handler->op1_op2_relation (r); + relation_kind relation = handler.op1_op2_relation (r); if (relation != VREL_VARYING) register_relation (e0, relation, ssa1, ssa2); } if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query) && r.singleton_p ()) { - relation_kind relation = handler->op1_op2_relation (r); + relation_kind relation = handler.op1_op2_relation (r); if (relation != VREL_VARYING) register_relation (e1, relation, ssa1, ssa2); } diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index 53a5bf8..fbf6627 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see #define GCC_GIMPLE_RANGE_FOLD_H // This file is the main include point for gimple range folding. -// These routines will fold stmt S into the result irange R. +// These routines will fold stmt S into the result range R. // Any ssa_names on the stmt will be calculated using the range_query // parameter via a call to range_of_expr. // If no range_query is provided, current global range info will be used. @@ -31,30 +31,15 @@ along with GCC; see the file COPYING3. If not see // it appeared on that edge. // Fold stmt S into range R using range query Q. -bool fold_range (irange &r, gimple *s, range_query *q = NULL); +bool fold_range (vrange &r, gimple *s, range_query *q = NULL); // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE. -bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL); +bool fold_range (vrange &v, gimple *s, edge on_edge, range_query *q = NULL); // These routines the operands to be specified when manually folding. // Any excess queries will be drawn from the current range_query. -bool fold_range (irange &r, gimple *s, irange &r1); -bool fold_range (irange &r, gimple *s, irange &r1, irange &r2); -bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector); - -// Return the range_operator pointer for this statement. This routine -// can also be used to gate whether a routine is range-ops enabled. - -static inline range_operator * -gimple_range_handler (const gimple *s) -{ - if (const gassign *ass = dyn_cast<const gassign *> (s)) - return range_op_handler (gimple_assign_rhs_code (ass), - TREE_TYPE (gimple_assign_lhs (ass))); - if (const gcond *cond = dyn_cast<const gcond *> (s)) - return range_op_handler (gimple_cond_code (cond), - TREE_TYPE (gimple_cond_lhs (cond))); - return NULL; -} +bool fold_range (vrange &r, gimple *s, vrange &r1); +bool fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2); +bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector); // Return the type of range which statement S calculates. If the type is // unsupported or no type can be determined, return NULL_TREE. @@ -81,7 +66,7 @@ gimple_range_type (const gimple *s) type = TREE_TYPE (type); } } - if (irange::supports_type_p (type)) + if (type && Value_Range::supports_type_p (type)) return type; return NULL_TREE; } @@ -94,7 +79,7 @@ gimple_range_ssa_p (tree exp) if (exp && TREE_CODE (exp) == SSA_NAME && !SSA_NAME_IS_VIRTUAL_OPERAND (exp) && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) && - irange::supports_type_p (TREE_TYPE (exp))) + Value_Range::supports_type_p (TREE_TYPE (exp))) return exp; return NULL_TREE; } @@ -123,8 +108,8 @@ public: fur_source (range_query *q = NULL); inline range_query *query () { return m_query; } inline class gori_compute *gori () { return m_gori; }; - virtual bool get_operand (irange &r, tree expr); - virtual bool get_phi_operand (irange &r, tree expr, edge e); + virtual bool get_operand (vrange &r, tree expr); + virtual bool get_phi_operand (vrange &r, tree expr, edge e); virtual relation_kind query_relation (tree op1, tree op2); virtual void register_relation (gimple *stmt, relation_kind k, tree op1, tree op2); @@ -143,8 +128,8 @@ class fur_stmt : public fur_source { public: fur_stmt (gimple *s, range_query *q = NULL); - virtual bool get_operand (irange &r, tree expr) override; - virtual bool get_phi_operand (irange &r, tree expr, edge e) override; + virtual bool get_operand (vrange &r, tree expr) override; + virtual bool get_phi_operand (vrange &r, tree expr, edge e) override; virtual relation_kind query_relation (tree op1, tree op2) override; private: gimple *m_stmt; @@ -176,17 +161,18 @@ extern tree gimple_range_operand2 (const gimple *s); class fold_using_range { public: - bool fold_stmt (irange &r, gimple *s, class fur_source &src, + bool fold_stmt (vrange &r, gimple *s, class fur_source &src, tree name = NULL_TREE); protected: - bool range_of_range_op (irange &r, gimple *s, fur_source &src); - bool range_of_call (irange &r, gcall *call, fur_source &src); - bool range_of_cond_expr (irange &r, gassign* cond, fur_source &src); + bool range_of_range_op (vrange &r, gimple *s, fur_source &src); + bool range_of_call (vrange &r, gcall *call, fur_source &src); + bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src); bool range_of_address (irange &r, gimple *s, fur_source &src); - bool range_of_builtin_call (irange &r, gcall *call, fur_source &src); + bool range_of_builtin_call (vrange &r, gcall *call, fur_source &src); + bool range_of_builtin_int_call (irange &r, gcall *call, fur_source &src); void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code, fur_source &src); - bool range_of_phi (irange &r, gphi *phi, fur_source &src); + bool range_of_phi (vrange &r, gphi *phi, fur_source &src); 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); diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index 3e15eb5..0a3e54e 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see // LHS_RANGE. Return false if nothing can be determined. bool -gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range) +gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range) { gcc_checking_assert (gimple_num_ops (stmt) < 3); // Give up on empty ranges. @@ -44,9 +44,9 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range) // Unary operations require the type of the first operand in the // second range position. tree type = TREE_TYPE (gimple_range_operand1 (stmt)); - int_range<2> type_range (type); - return gimple_range_handler (stmt)->op1_range (r, type, lhs_range, - type_range); + Value_Range type_range (type); + type_range.set_varying (type); + return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range); } // Calculate what we can determine of the range of this statement's @@ -55,8 +55,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range) // nothing can be determined. bool -gimple_range_calc_op1 (irange &r, const gimple *stmt, - const irange &lhs_range, const irange &op2_range) +gimple_range_calc_op1 (vrange &r, const gimple *stmt, + const vrange &lhs_range, const vrange &op2_range) { // Give up on empty ranges. if (lhs_range.undefined_p ()) @@ -72,12 +72,12 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, // This is sometimes invoked on single operand stmts. if (gimple_num_ops (stmt) < 3) return false; - int_range<2> trange (TREE_TYPE (gimple_range_operand2 (stmt))); - return gimple_range_handler (stmt)->op1_range (r, type, lhs_range, - trange); + tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt)); + Value_Range trange (op2_type); + trange.set_varying (op2_type); + return range_op_handler (stmt).op1_range (r, type, lhs_range, trange); } - return gimple_range_handler (stmt)->op1_range (r, type, lhs_range, - op2_range); + return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range); } // Calculate what we can determine of the range of this statement's @@ -86,8 +86,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, // nothing can be determined. bool -gimple_range_calc_op2 (irange &r, const gimple *stmt, - const irange &lhs_range, const irange &op1_range) +gimple_range_calc_op2 (vrange &r, const gimple *stmt, + const vrange &lhs_range, const vrange &op1_range) { // Give up on empty ranges. if (lhs_range.undefined_p ()) @@ -97,12 +97,13 @@ gimple_range_calc_op2 (irange &r, const gimple *stmt, // If op1 is undefined, solve as if it is varying. if (op1_range.undefined_p ()) { - int_range<2> trange (TREE_TYPE (gimple_range_operand1 (stmt))); - return gimple_range_handler (stmt)->op2_range (r, type, lhs_range, - trange); + tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt)); + Value_Range trange (op1_type); + trange.set_varying (op1_type); + return range_op_handler (stmt).op2_range (r, type, lhs_range, trange); } - return gimple_range_handler (stmt)->op2_range (r, type, lhs_range, - op1_range); + return range_op_handler (stmt).op2_range (r, type, lhs_range, + op1_range); } // Return TRUE if GS is a logical && or || expression. @@ -346,7 +347,7 @@ range_def_chain::get_def_chain (tree name) } gimple *stmt = SSA_NAME_DEF_STMT (name); - if (gimple_range_handler (stmt)) + if (range_op_handler (stmt)) { ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); @@ -662,8 +663,8 @@ gori_compute::gori_compute (int not_executable_flag) // was not resolvable. bool -gori_compute::compute_operand_range_switch (irange &r, gswitch *s, - const irange &lhs, +gori_compute::compute_operand_range_switch (vrange &r, gswitch *s, + const vrange &lhs, tree name, fur_source &src) { tree op1 = gimple_switch_index (s); @@ -690,8 +691,8 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s, // store the evaluation in R, otherwise return FALSE. bool -gori_compute::compute_operand_range (irange &r, gimple *stmt, - const irange &lhs, tree name, +gori_compute::compute_operand_range (vrange &r, gimple *stmt, + const vrange &lhs, tree name, fur_source &src) { // If the lhs doesn't tell us anything, neither will unwinding further. @@ -707,7 +708,7 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt, if (is_a<gswitch *> (stmt)) return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name, src); - if (!gimple_range_handler (stmt)) + if (!range_op_handler (stmt)) return false; tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); @@ -742,13 +743,18 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt, print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } - int_range_max op1_trange, op1_frange; - int_range_max op2_trange, op2_frange; - compute_logical_operands (op1_trange, op1_frange, stmt, lhs, + tree type = TREE_TYPE (name); + Value_Range op1_trange (type), op1_frange (type); + Value_Range op2_trange (type), op2_frange (type); + compute_logical_operands (op1_trange, op1_frange, stmt, + as_a <irange> (lhs), name, src, op1, op1_in_chain); - compute_logical_operands (op2_trange, op2_frange, stmt, lhs, + compute_logical_operands (op2_trange, op2_frange, stmt, + as_a <irange> (lhs), name, src, op2, op2_in_chain); - res = logical_combine (r, gimple_expr_code (stmt), lhs, + res = logical_combine (r, + gimple_expr_code (stmt), + as_a <irange> (lhs), op1_trange, op1_frange, op2_trange, op2_frange); if (idx) tracer.trailer (idx, "compute_operand", res, name, r); @@ -788,10 +794,10 @@ range_is_either_true_or_false (const irange &r) // the LHS. bool -gori_compute::logical_combine (irange &r, enum tree_code code, +gori_compute::logical_combine (vrange &r, enum tree_code code, const irange &lhs, - const irange &op1_true, const irange &op1_false, - const irange &op2_true, const irange &op2_false) + const vrange &op1_true, const vrange &op1_false, + const vrange &op2_true, const vrange &op2_false) { if (op1_true.varying_p () && op1_false.varying_p () && op2_true.varying_p () && op2_false.varying_p ()) @@ -867,7 +873,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code, if (!range_is_either_true_or_false (lhs)) { bool res; - int_range_max r1; + Value_Range r1 (r); if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false, op2_true, op2_false) && logical_combine (r, code, m_bool_one, op1_true, op1_false, @@ -897,11 +903,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code, else { // The FALSE side is the union of the other 3 cases. - int_range_max ff (op1_false); + Value_Range ff (op1_false); ff.intersect (op2_false); - int_range_max tf (op1_true); + Value_Range tf (op1_true); tf.intersect (op2_false); - int_range_max ft (op1_false); + Value_Range ft (op1_false); ft.intersect (op2_true); r = ff; r.union_ (tf); @@ -924,11 +930,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code, { // The TRUE side of an OR operation will be the union of // the other three combinations. - int_range_max tt (op1_true); + Value_Range tt (op1_true); tt.intersect (op2_true); - int_range_max tf (op1_true); + Value_Range tf (op1_true); tf.intersect (op2_false); - int_range_max ft (op1_false); + Value_Range ft (op1_false); ft.intersect (op2_true); r = tt; r.union_ (tf); @@ -950,7 +956,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code, // OP_IN_CHAIN is true. void -gori_compute::compute_logical_operands (irange &true_range, irange &false_range, +gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range, gimple *stmt, const irange &lhs, tree name, fur_source &src, @@ -1006,13 +1012,15 @@ gori_compute::compute_logical_operands (irange &true_range, irange &false_range, // R, or false if no range could be calculated. bool -gori_compute::compute_operand1_range (irange &r, gimple *stmt, - const irange &lhs, tree name, +gori_compute::compute_operand1_range (vrange &r, gimple *stmt, + const vrange &lhs, tree name, fur_source &src) { - int_range_max op1_range, op2_range; tree op1 = gimple_range_operand1 (stmt); tree op2 = gimple_range_operand2 (stmt); + Value_Range op1_range (TREE_TYPE (op1)); + Value_Range tmp (TREE_TYPE (op1)); + Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1)); // Fetch the known range for op1 in this block. src.get_operand (op1_range, op1); @@ -1021,7 +1029,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, if (op2) { src.get_operand (op2_range, op2); - if (!gimple_range_calc_op1 (r, stmt, lhs, op2_range)) + if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range)) return false; } else @@ -1029,7 +1037,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, // We pass op1_range to the unary operation. Nomally it's a // hidden range_for_type parameter, but sometimes having the // actual range can result in better information. - if (!gimple_range_calc_op1 (r, stmt, lhs, op1_range)) + if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range)) return false; } @@ -1052,7 +1060,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, tracer.print (idx, "Computes "); print_generic_expr (dump_file, op1, TDF_SLIM); fprintf (dump_file, " = "); - r.dump (dump_file); + tmp.dump (dump_file); fprintf (dump_file, " intersect Known range : "); op1_range.dump (dump_file); fputc ('\n', dump_file); @@ -1060,13 +1068,14 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, // Intersect the calculated result with the known result and return if done. if (op1 == name) { - r.intersect (op1_range); + tmp.intersect (op1_range); + r = tmp; if (idx) tracer.trailer (idx, "produces ", true, name, r); return true; } // If the calculation continues, we're using op1_range as the new LHS. - op1_range.intersect (r); + op1_range.intersect (tmp); if (idx) tracer.trailer (idx, "produces ", true, op1, op1_range); @@ -1083,19 +1092,21 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, // R, or false if no range could be calculated. bool -gori_compute::compute_operand2_range (irange &r, gimple *stmt, - const irange &lhs, tree name, +gori_compute::compute_operand2_range (vrange &r, gimple *stmt, + const vrange &lhs, tree name, fur_source &src) { - int_range_max op1_range, op2_range; tree op1 = gimple_range_operand1 (stmt); tree op2 = gimple_range_operand2 (stmt); + Value_Range op1_range (TREE_TYPE (op1)); + Value_Range op2_range (TREE_TYPE (op2)); + Value_Range tmp (TREE_TYPE (op2)); src.get_operand (op1_range, op1); src.get_operand (op2_range, op2); // Intersect with range for op2 based on lhs and op1. - if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range)) + if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range)) return false; unsigned idx; @@ -1117,7 +1128,7 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt, tracer.print (idx, "Computes "); print_generic_expr (dump_file, op2, TDF_SLIM); fprintf (dump_file, " = "); - r.dump (dump_file); + tmp.dump (dump_file); fprintf (dump_file, " intersect Known range : "); op2_range.dump (dump_file); fputc ('\n', dump_file); @@ -1125,13 +1136,14 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt, // Intersect the calculated result with the known result and return if done. if (op2 == name) { - r.intersect (op2_range); + tmp.intersect (op2_range); + r = tmp; if (idx) tracer.trailer (idx, " produces ", true, NULL_TREE, r); return true; } // If the calculation continues, we're using op2_range as the new LHS. - op2_range.intersect (r); + op2_range.intersect (tmp); if (idx) tracer.trailer (idx, " produces ", true, op2, op2_range); @@ -1148,13 +1160,13 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt, // R, or false if no range could be calculated. bool -gori_compute::compute_operand1_and_operand2_range (irange &r, +gori_compute::compute_operand1_and_operand2_range (vrange &r, gimple *stmt, - const irange &lhs, + const vrange &lhs, tree name, fur_source &src) { - int_range_max op_range; + Value_Range op_range (TREE_TYPE (name)); // Calculate a good a range for op2. Since op1 == op2, this will // have already included whatever the actual range of name is. @@ -1235,10 +1247,9 @@ gori_compute::has_edge_range_p (tree name, edge e) // control edge or NAME is not defined by this edge. bool -gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, +gori_compute::outgoing_edge_range_p (vrange &r, edge e, tree name, range_query &q) { - int_range_max lhs; unsigned idx; if ((e->flags & m_not_executable_flag)) @@ -1251,6 +1262,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, } gcc_checking_assert (gimple_range_ssa_p (name)); + int_range_max lhs; // Determine if there is an outgoing edge. gimple *stmt = outgoing.edge_range_p (lhs, e); if (!stmt) @@ -1311,10 +1323,9 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, // edge and OP2 on the false edge. bool -gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond, +gori_compute::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond, tree op1, tree op2, fur_source &src) { - int_range_max tmp, cond_true, cond_false; tree ssa1 = gimple_range_ssa_p (op1); tree ssa2 = gimple_range_ssa_p (op2); if (!ssa1 && !ssa2) @@ -1328,7 +1339,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond, tree type = TREE_TYPE (gimple_assign_rhs1 (cond_def)); if (!range_compatible_p (type, TREE_TYPE (gimple_assign_rhs2 (cond_def)))) return false; - range_operator *hand = range_op_handler (gimple_assign_rhs_code (cond_def), type); + range_op_handler hand (gimple_assign_rhs_code (cond_def), type); if (!hand) return false; @@ -1340,29 +1351,33 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond, return false; // Pick up the current values of each part of the condition. - int_range_max cl, cr; - src.get_operand (cl, gimple_assign_rhs1 (cond_def)); - src.get_operand (cr, gimple_assign_rhs2 (cond_def)); + tree rhs1 = gimple_assign_rhs1 (cond_def); + tree rhs2 = gimple_assign_rhs2 (cond_def); + Value_Range cl (TREE_TYPE (rhs1)); + Value_Range cr (TREE_TYPE (rhs2)); + src.get_operand (cl, rhs1); + src.get_operand (cr, rhs2); tree cond_name = c1 ? c1 : c2; gimple *def_stmt = SSA_NAME_DEF_STMT (cond_name); // Evaluate the value of COND_NAME on the true and false edges, using either // the op1 or op2 routines based on its location. + Value_Range cond_true (type), cond_false (type); if (c1) { - if (!hand->op1_range (cond_false, type, m_bool_zero, cr)) + if (!hand.op1_range (cond_false, type, m_bool_zero, cr)) return false; - if (!hand->op1_range (cond_true, type, m_bool_one, cr)) + if (!hand.op1_range (cond_true, type, m_bool_one, cr)) return false; cond_false.intersect (cl); cond_true.intersect (cl); } else { - if (!hand->op2_range (cond_false, type, m_bool_zero, cl)) + if (!hand.op2_range (cond_false, type, m_bool_zero, cl)) return false; - if (!hand->op2_range (cond_true, type, m_bool_one, cl)) + if (!hand.op2_range (cond_true, type, m_bool_one, cl)) return false; cond_false.intersect (cr); cond_true.intersect (cr); @@ -1379,6 +1394,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond, } // Now solve for SSA1 or SSA2 if they are in the dependency chain. + Value_Range tmp (type); if (ssa1 && in_chain_p (ssa1, cond_name)) { if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src)) diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index 605884e..f5f691f 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -121,7 +121,7 @@ private: // on *ANY* edge that has been seen. FALSE indicates that the global value // is applicable everywhere that has been processed. // -// outgoing_edge_range_p (irange &range, edge e, tree name) +// outgoing_edge_range_p (vrange &range, edge e, tree name) // Actually does the calculation of RANGE for name on E // This represents application of whatever static range effect edge E // may have on NAME, not any cumulative effect. @@ -157,8 +157,8 @@ class gori_compute : public gori_map { public: gori_compute (int not_executable_flag = 0); - bool outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q); - bool condexpr_adjust (irange &r1, irange &r2, gimple *s, tree cond, tree op1, + bool outgoing_edge_range_p (vrange &r, edge e, tree name, range_query &q); + bool condexpr_adjust (vrange &r1, vrange &r2, gimple *s, tree cond, tree op1, tree op2, fur_source &src); bool has_edge_range_p (tree name, basic_block bb = NULL); bool has_edge_range_p (tree name, edge e); @@ -166,24 +166,24 @@ public: private: bool may_recompute_p (tree name, edge e); bool may_recompute_p (tree name, basic_block bb = NULL); - bool compute_operand_range (irange &r, gimple *stmt, const irange &lhs, + bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs, tree name, class fur_source &src); - bool compute_operand_range_switch (irange &r, gswitch *s, const irange &lhs, + bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs, tree name, fur_source &src); - bool compute_operand1_range (irange &r, gimple *stmt, const irange &lhs, + bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs, tree name, fur_source &src); - bool compute_operand2_range (irange &r, gimple *stmt, const irange &lhs, + bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs, tree name, fur_source &src); - bool compute_operand1_and_operand2_range (irange &r, gimple *stmt, - const irange &lhs, tree name, + bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt, + const vrange &lhs, tree name, fur_source &src); - void compute_logical_operands (irange &true_range, irange &false_range, + void compute_logical_operands (vrange &true_range, vrange &false_range, gimple *stmt, const irange &lhs, tree name, fur_source &src, tree op, bool op_in_chain); - bool logical_combine (irange &r, enum tree_code code, const irange &lhs, - const irange &op1_true, const irange &op1_false, - const irange &op2_true, const irange &op2_false); + bool logical_combine (vrange &r, enum tree_code code, const irange &lhs, + const vrange &op1_true, const vrange &op1_false, + const vrange &op2_true, const vrange &op2_false); int_range<2> m_bool_zero; // Boolean false cached. int_range<2> m_bool_one; // Boolean true cached. @@ -193,14 +193,14 @@ private: }; // These routines provide a GIMPLE interface to the range-ops code. -extern bool gimple_range_calc_op1 (irange &r, const gimple *s, - const irange &lhs_range); -extern bool gimple_range_calc_op1 (irange &r, const gimple *s, - const irange &lhs_range, - const irange &op2_range); -extern bool gimple_range_calc_op2 (irange &r, const gimple *s, - const irange &lhs_range, - const irange &op1_range); +extern bool gimple_range_calc_op1 (vrange &r, const gimple *s, + const vrange &lhs_range); +extern bool gimple_range_calc_op1 (vrange &r, const gimple *s, + const vrange &lhs_range, + const vrange &op2_range); +extern bool gimple_range_calc_op2 (vrange &r, const gimple *s, + const vrange &lhs_range, + const vrange &op1_range); // For each name that is an import into BB's exports.. #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name) \ diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc index 545d4f2..eee1491 100644 --- a/gcc/gimple-range-infer.cc +++ b/gcc/gimple-range-infer.cc @@ -58,7 +58,7 @@ non_null_loadstore (gimple *, tree op, tree, void *data) // Add NAME and RANGE to the the range inference summary. void -gimple_infer_range::add_range (tree name, irange &range) +gimple_infer_range::add_range (tree name, vrange &range) { m_names[num_args] = name; m_ranges[num_args] = range; @@ -126,7 +126,7 @@ class exit_range { public: tree name; - irange *range; + vrange *range; exit_range *next; }; @@ -181,7 +181,7 @@ infer_range_manager::~infer_range_manager () // Return a non-zero range value of the appropriate type for NAME from // the cache, creating it if necessary. -const irange& +const vrange& infer_range_manager::get_nonzero (tree name) { unsigned v = SSA_NAME_VERSION (name); @@ -189,7 +189,7 @@ infer_range_manager::get_nonzero (tree name) m_nonzero.safe_grow_cleared (num_ssa_names + 20); if (!m_nonzero[v]) { - m_nonzero[v] = m_range_allocator.allocate (2); + m_nonzero[v] = m_range_allocator.alloc_vrange (TREE_TYPE (name)); m_nonzero[v]->set_nonzero (TREE_TYPE (name)); } return *(m_nonzero[v]); @@ -217,7 +217,7 @@ infer_range_manager::has_range_p (tree name, basic_block bb) // to include it. bool -infer_range_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) +infer_range_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb) { if (!has_range_p (name, bb)) return false; @@ -230,7 +230,7 @@ infer_range_manager::maybe_adjust_range (irange &r, tree name, basic_block bb) // Add range R as an inferred range for NAME in block BB. void -infer_range_manager::add_range (tree name, basic_block bb, const irange &r) +infer_range_manager::add_range (tree name, basic_block bb, const vrange &r) { if (bb->index >= (int)m_on_exit.length ()) m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1); @@ -252,21 +252,24 @@ infer_range_manager::add_range (tree name, basic_block bb, const irange &r) exit_range *ptr = m_on_exit[bb->index].find_ptr (name); if (ptr) { - int_range_max cur = r; + Value_Range cur (r); // If no new info is added, just return. if (!cur.intersect (*(ptr->range))) return; if (ptr->range->fits_p (cur)) *(ptr->range) = cur; else - ptr->range = m_range_allocator.allocate (cur); + { + vrange &v = cur; + ptr->range = m_range_allocator.clone (v); + } return; } // Otherwise create a record. bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name)); ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range)); - ptr->range = m_range_allocator.allocate (r); + ptr->range = m_range_allocator.clone (r); ptr->name = name; ptr->next = m_on_exit[bb->index].head; m_on_exit[bb->index].head = ptr; diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h index 412958f..aafa8bb 100644 --- a/gcc/gimple-range-infer.h +++ b/gcc/gimple-range-infer.h @@ -35,15 +35,15 @@ public: inline unsigned num () const { return num_args; } inline tree name (unsigned index) const { gcc_checking_assert (index < num_args); return m_names[index]; } - inline const irange& range (unsigned index) const + inline const vrange& range (unsigned index) const { gcc_checking_assert (index < num_args); return m_ranges[index]; } - void add_range (tree name, irange &range); + void add_range (tree name, vrange &range); void add_nonzero (tree name); private: unsigned num_args; static const int size_limit = 10; tree m_names[size_limit]; - int_range<3> m_ranges[size_limit]; + Value_Range m_ranges[size_limit]; inline void bump_index () { if (num_args < size_limit - 1) num_args++; } }; @@ -58,10 +58,10 @@ class infer_range_manager public: infer_range_manager (bool do_search); ~infer_range_manager (); - void add_range (tree name, basic_block bb, const irange &r); + void add_range (tree name, basic_block bb, const vrange &r); void add_nonzero (tree name, basic_block bb); bool has_range_p (tree name, basic_block bb); - bool maybe_adjust_range (irange &r, tree name, basic_block bb); + bool maybe_adjust_range (vrange &r, tree name, basic_block bb); private: class exit_range_head { @@ -73,12 +73,12 @@ private: }; void register_all_uses (tree name); vec <exit_range_head> m_on_exit; - const irange &get_nonzero (tree name); - vec <irange *> m_nonzero; + const vrange &get_nonzero (tree name); + vec <vrange *> m_nonzero; bitmap m_seen; bitmap_obstack m_bitmaps; struct obstack m_list_obstack; - irange_allocator m_range_allocator; + vrange_allocator m_range_allocator; }; #endif // GCC_GIMPLE_RANGE_SIDE_H diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index 459d379..e1b9683 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -83,7 +83,7 @@ path_range_query::clear_cache (tree name) // If NAME has a cache entry, return it in R, and return TRUE. inline bool -path_range_query::get_cache (irange &r, tree name) +path_range_query::get_cache (vrange &r, tree name) { if (!gimple_range_ssa_p (name)) return get_global_range_query ()->range_of_expr (r, name); @@ -98,7 +98,7 @@ path_range_query::get_cache (irange &r, tree name) // Set the cache entry for NAME to R. void -path_range_query::set_cache (const irange &r, tree name) +path_range_query::set_cache (const vrange &r, tree name) { unsigned v = SSA_NAME_VERSION (name); bitmap_set_bit (m_has_cache_entry, v); @@ -149,7 +149,7 @@ path_range_query::defined_outside_path (tree name) // Return the range of NAME on entry to the path. void -path_range_query::range_on_path_entry (irange &r, tree name) +path_range_query::range_on_path_entry (vrange &r, tree name) { gcc_checking_assert (defined_outside_path (name)); basic_block entry = entry_bb (); @@ -168,7 +168,7 @@ path_range_query::range_on_path_entry (irange &r, tree name) // block. This can happen when we're querying a block with only an // outgoing edge (no statement but the fall through edge), but for // which we can determine a range on entry to the block. - int_range_max tmp; + Value_Range tmp (TREE_TYPE (name)); bool changed = false; r.set_undefined (); for (unsigned i = 0; i < EDGE_COUNT (entry->preds); ++i) @@ -190,9 +190,9 @@ path_range_query::range_on_path_entry (irange &r, tree name) // Return the range of NAME at the end of the path being analyzed. bool -path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt) +path_range_query::internal_range_of_expr (vrange &r, tree name, gimple *stmt) { - if (!irange::supports_type_p (TREE_TYPE (name))) + if (!r.supports_type_p (TREE_TYPE (name))) return false; if (get_cache (r, name)) @@ -209,18 +209,22 @@ path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt) && range_defined_in_block (r, name, gimple_bb (stmt))) { if (TREE_CODE (name) == SSA_NAME) - r.intersect (gimple_range_global (name)); + { + Value_Range glob (TREE_TYPE (name)); + gimple_range_global (glob, name); + r.intersect (glob); + } set_cache (r, name); return true; } - r = gimple_range_global (name); + gimple_range_global (r, name); return true; } bool -path_range_query::range_of_expr (irange &r, tree name, gimple *stmt) +path_range_query::range_of_expr (vrange &r, tree name, gimple *stmt) { if (internal_range_of_expr (r, name, stmt)) { @@ -269,7 +273,7 @@ path_range_query::ssa_defined_in_bb (tree name, basic_block bb) // calculating the PHI's range must not trigger additional lookups. void -path_range_query::ssa_range_in_phi (irange &r, gphi *phi) +path_range_query::ssa_range_in_phi (vrange &r, gphi *phi) { tree name = gimple_phi_result (phi); basic_block bb = gimple_bb (phi); @@ -283,7 +287,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi) // Try to fold the phi exclusively with global or cached values. // This will get things like PHI <5(99), 6(88)>. We do this by // calling range_of_expr with no context. - int_range_max arg_range; + Value_Range arg_range (TREE_TYPE (name)); r.set_undefined (); for (size_t i = 0; i < nargs; ++i) { @@ -312,7 +316,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi) { if (m_resolve) { - int_range_max tmp; + Value_Range tmp (TREE_TYPE (name)); // Using both the range on entry to the path, and the // range on this edge yields significantly better // results. @@ -335,7 +339,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi) // TRUE. Otherwise, return FALSE. bool -path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb) +path_range_query::range_defined_in_block (vrange &r, tree name, basic_block bb) { gimple *def_stmt = SSA_NAME_DEF_STMT (name); basic_block def_bb = gimple_bb (def_stmt); @@ -377,7 +381,6 @@ path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb) void path_range_query::compute_ranges_in_phis (basic_block bb) { - int_range_max r; auto_bitmap phi_set; // PHIs must be resolved simultaneously on entry to the block @@ -390,7 +393,11 @@ path_range_query::compute_ranges_in_phis (basic_block bb) gphi *phi = iter.phi (); tree name = gimple_phi_result (phi); - if (import_p (name) && range_defined_in_block (r, name, bb)) + if (!import_p (name)) + continue; + + Value_Range r (TREE_TYPE (name)); + if (range_defined_in_block (r, name, bb)) { unsigned v = SSA_NAME_VERSION (name); set_cache (r, name); @@ -423,7 +430,6 @@ void path_range_query::compute_ranges_in_block (basic_block bb) { bitmap_iterator bi; - int_range_max r, cached_range; unsigned i; if (m_resolve && !at_entry ()) @@ -444,6 +450,7 @@ path_range_query::compute_ranges_in_block (basic_block bb) EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi) { tree name = ssa_name (i); + Value_Range r (TREE_TYPE (name)); if (gimple_code (SSA_NAME_DEF_STMT (name)) != GIMPLE_PHI && range_defined_in_block (r, name, bb)) @@ -480,8 +487,10 @@ path_range_query::compute_ranges_in_block (basic_block bb) if (bitmap_bit_p (exports, i)) { + Value_Range r (TREE_TYPE (name)); if (g.outgoing_edge_range_p (r, e, name, *this)) { + Value_Range cached_range (TREE_TYPE (name)); if (get_cache (cached_range, name)) r.intersect (cached_range); @@ -539,7 +548,7 @@ bool path_range_query::add_to_imports (tree name, bitmap imports) { if (TREE_CODE (name) == SSA_NAME - && irange::supports_type_p (TREE_TYPE (name))) + && Value_Range::supports_type_p (TREE_TYPE (name))) return bitmap_set_bit (imports, SSA_NAME_VERSION (name)); return false; } @@ -751,11 +760,11 @@ jt_fur_source::query_relation (tree op1, tree 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) +path_range_query::range_of_stmt (vrange &r, gimple *stmt, tree) { tree type = gimple_range_type (stmt); - if (!irange::supports_type_p (type)) + if (!type || !r.supports_type_p (type)) return false; // If resolving unknowns, fold the statement making use of any diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h index 914983b..2c4624e 100644 --- a/gcc/gimple-range-path.h +++ b/gcc/gimple-range-path.h @@ -38,29 +38,29 @@ public: const bitmap_head *imports = NULL); void compute_ranges (edge e); void compute_imports (bitmap imports, basic_block exit); - bool range_of_expr (irange &r, tree name, gimple * = NULL) override; - bool range_of_stmt (irange &r, gimple *, tree name = NULL) override; + bool range_of_expr (vrange &r, tree name, gimple * = NULL) override; + bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override; bool unreachable_path_p (); void dump (FILE *) override; void debug (); private: - bool internal_range_of_expr (irange &r, tree name, gimple *); + bool internal_range_of_expr (vrange &r, tree name, gimple *); bool defined_outside_path (tree name); - void range_on_path_entry (irange &r, tree name); + void range_on_path_entry (vrange &r, tree name); path_oracle *get_path_oracle () { return (path_oracle *)m_oracle; } // Cache manipulation. - void set_cache (const irange &r, tree name); - bool get_cache (irange &r, tree name); + void set_cache (const vrange &r, tree name); + bool get_cache (vrange &r, tree name); void clear_cache (tree name); // Methods to compute ranges for the given path. - bool range_defined_in_block (irange &, tree name, basic_block bb); + bool range_defined_in_block (vrange &, tree name, basic_block bb); void compute_ranges_in_block (basic_block bb); void compute_ranges_in_phis (basic_block bb); void adjust_for_non_null_uses (basic_block bb); - void ssa_range_in_phi (irange &r, gphi *phi); + void ssa_range_in_phi (vrange &r, gphi *phi); void compute_outgoing_relations (basic_block bb, basic_block next); void compute_phi_relations (basic_block bb, basic_block prev); void maybe_register_phi_relation (gphi *, edge e); diff --git a/gcc/gimple-range-tests.cc b/gcc/gimple-range-tests.cc index 572acd3..84ecc48 100644 --- a/gcc/gimple-range-tests.cc +++ b/gcc/gimple-range-tests.cc @@ -42,8 +42,9 @@ public: ASSERT_TRUE (r == expect); } - virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) override + virtual bool range_of_expr (vrange &v, tree expr, gimple * = NULL) override { + irange &r = as_a <irange> (v); if (expr == op0) { r.set (build_int_cst (type, 5), build_int_cst (type, 10)); diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc index 3997109..46827f9 100644 --- a/gcc/gimple-range-trace.cc +++ b/gcc/gimple-range-trace.cc @@ -102,7 +102,7 @@ range_tracer::print (unsigned counter, const char *str) void range_tracer::trailer (unsigned counter, const char *caller, bool result, - tree name, const irange &r) + tree name, const vrange &r) { gcc_checking_assert (tracing && counter != 0); @@ -141,7 +141,6 @@ debug_seed_ranger (gimple_ranger &ranger) } basic_block bb; - int_range_max r; gimple_stmt_iterator gsi; FOR_EACH_BB_FN (bb, cfun) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) @@ -151,7 +150,11 @@ debug_seed_ranger (gimple_ranger &ranger) if (is_gimple_debug (stmt)) continue; - ranger.range_of_stmt (r, stmt); + if (tree type = gimple_range_type (stmt)) + { + Value_Range r (type); + ranger.range_of_stmt (r, stmt); + } } } diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h index 302afda..3f92e51 100644 --- a/gcc/gimple-range-trace.h +++ b/gcc/gimple-range-trace.h @@ -32,7 +32,7 @@ public: range_tracer (const char *name = ""); unsigned header (const char *str); void trailer (unsigned counter, const char *caller, bool result, tree name, - const irange &r); + const vrange &r); void print (unsigned counter, const char *str); inline void enable_trace () { tracing = true; } inline void disable_trace () { tracing = false; } diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index 53f4865..f3a4655 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -71,7 +71,7 @@ gimple_ranger::~gimple_ranger () } bool -gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) +gimple_ranger::range_of_expr (vrange &r, tree expr, gimple *stmt) { unsigned idx; if (!gimple_range_ssa_p (expr)) @@ -93,7 +93,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) // If there is no statement, just get the global value. if (!stmt) { - int_range_max tmp; + Value_Range tmp (TREE_TYPE (expr)); m_cache.get_global_range (r, expr); // Pick up implied context information from the on-entry cache // if current_bb is set. Do not attempt any new calculations. @@ -137,9 +137,9 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) // Return the range of NAME on entry to block BB in R. void -gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) +gimple_ranger::range_on_entry (vrange &r, basic_block bb, tree name) { - int_range_max entry_range; + Value_Range entry_range (TREE_TYPE (name)); gcc_checking_assert (gimple_range_ssa_p (name)); unsigned idx; @@ -164,7 +164,7 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) // Return false if no range can be calculated. void -gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) +gimple_ranger::range_on_exit (vrange &r, basic_block bb, tree name) { // on-exit from the exit block? gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)); @@ -198,10 +198,10 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) // Calculate a range for NAME on edge E and return it in R. bool -gimple_ranger::range_on_edge (irange &r, edge e, tree name) +gimple_ranger::range_on_edge (vrange &r, edge e, tree name) { - int_range_max edge_range; - gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name))); + Value_Range edge_range (TREE_TYPE (name)); + gcc_checking_assert (r.supports_type_p (TREE_TYPE (name))); // Do not process values along abnormal edges. if (e->flags & EDGE_ABNORMAL) @@ -249,7 +249,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) // fold_range wrapper for range_of_stmt to use as an internal client. bool -gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name) +gimple_ranger::fold_range_internal (vrange &r, gimple *s, tree name) { fold_using_range f; fur_depend src (s, &(gori ()), this); @@ -263,7 +263,7 @@ gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name) // avoided. If a range cannot be calculated, return false and UNDEFINED. bool -gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) +gimple_ranger::range_of_stmt (vrange &r, gimple *s, tree name) { bool res; r.set_undefined (); @@ -313,7 +313,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) prefill_stmt_dependencies (name); // Calculate a new value. - int_range_max tmp; + Value_Range tmp (TREE_TYPE (name)); fold_range_internal (tmp, s, name); // Combine the new value with the old value. This is required because @@ -334,12 +334,12 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) // stack if so. R is a scratch range. inline void -gimple_ranger::prefill_name (irange &r, tree name) +gimple_ranger::prefill_name (vrange &r, tree name) { if (!gimple_range_ssa_p (name)) return; gimple *stmt = SSA_NAME_DEF_STMT (name); - if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt)) + if (!range_op_handler (stmt) && !is_a<gphi *> (stmt)) return; bool current; @@ -357,13 +357,12 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) if (SSA_NAME_IS_DEFAULT_DEF (ssa)) return; - int_range_max r; unsigned idx; gimple *stmt = SSA_NAME_DEF_STMT (ssa); gcc_checking_assert (stmt && gimple_bb (stmt)); // Only pre-process range-ops and phis. - if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt)) + if (!range_op_handler (stmt) && !is_a<gphi *> (stmt)) return; // Mark where on the stack we are starting. @@ -388,9 +387,10 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) { // Fold and save the value for NAME. stmt = SSA_NAME_DEF_STMT (name); + Value_Range r (TREE_TYPE (name)); fold_range_internal (r, stmt, name); // Make sure we don't lose any current global info. - int_range_max tmp; + Value_Range tmp (TREE_TYPE (name)); m_cache.get_global_range (tmp, name); r.intersect (tmp); m_cache.set_global_range (name, r); @@ -414,13 +414,15 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) gphi *phi = dyn_cast <gphi *> (stmt); if (phi) { + Value_Range r (TREE_TYPE (gimple_phi_result (phi))); for (unsigned x = 0; x < gimple_phi_num_args (phi); x++) prefill_name (r, gimple_phi_arg_def (phi, x)); } else { - gcc_checking_assert (gimple_range_handler (stmt)); + gcc_checking_assert (range_op_handler (stmt)); tree op = gimple_range_operand2 (stmt); + Value_Range r (TREE_TYPE (name)); if (op) prefill_name (r, op); op = gimple_range_operand1 (stmt); @@ -429,7 +431,10 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) } } if (idx) - tracer.trailer (idx, "ROS ", false, ssa, r); + { + unsupported_range r; + tracer.trailer (idx, "ROS ", false, ssa, r); + } } @@ -456,17 +461,20 @@ gimple_ranger::register_inferred_ranges (gimple *s) tree lhs = gimple_get_lhs (s); if (lhs) { - int_range_max tmp; + Value_Range tmp (TREE_TYPE (lhs)); if (range_of_stmt (tmp, s, lhs) && !tmp.varying_p () && update_global_range (tmp, lhs) && dump_file) { - value_range vr = tmp; + // ?? This section should be adjusted when non-iranges can + // be exported. For now, the only way update_global_range + // above can succeed is with an irange so this is safe. + value_range vr = as_a <irange> (tmp); fprintf (dump_file, "Global Exported: "); print_generic_expr (dump_file, lhs, TDF_SLIM); fprintf (dump_file, " = "); vr.dump (dump_file); int_range_max same = vr; - if (same != tmp) + if (same != as_a <irange> (tmp)) { fprintf (dump_file, " ... irange was : "); tmp.dump (dump_file); @@ -487,8 +495,10 @@ gimple_ranger::export_global_ranges () bool print_header = true; for (unsigned x = 1; x < num_ssa_names; x++) { - int_range_max r; tree name = ssa_name (x); + if (!name) + continue; + Value_Range r (TREE_TYPE (name)); if (name && !SSA_NAME_IN_FREE_LIST (name) && gimple_range_ssa_p (name) && m_cache.get_global_range (r, name) @@ -507,13 +517,17 @@ gimple_ranger::export_global_ranges () print_header = false; } - value_range vr = r; + if (!irange::supports_p (TREE_TYPE (name))) + continue; + + vrange &v = r; + value_range vr = as_a <irange> (v); print_generic_expr (dump_file, name , TDF_SLIM); fprintf (dump_file, " : "); vr.dump (dump_file); fprintf (dump_file, "\n"); int_range_max same = vr; - if (same != r) + if (same != as_a <irange> (v)) { fprintf (dump_file, " irange : "); r.dump (dump_file); @@ -531,7 +545,6 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) unsigned x; edge_iterator ei; edge e; - int_range_max range, tmp_range; fprintf (f, "\n=========== BB %d ============\n", bb->index); m_cache.dump_bb (f, bb); @@ -541,9 +554,11 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) for (x = 1; x < num_ssa_names; x++) { tree name = ssa_name (x); - if (gimple_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) && - gimple_bb (SSA_NAME_DEF_STMT (name)) == bb && - m_cache.get_global_range (range, name)) + if (!gimple_range_ssa_p (name) || !SSA_NAME_DEF_STMT (name)) + continue; + Value_Range range (TREE_TYPE (name)); + if (gimple_bb (SSA_NAME_DEF_STMT (name)) == bb + && m_cache.get_global_range (range, name)) { if (!range.varying_p ()) { @@ -562,10 +577,14 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) for (x = 1; x < num_ssa_names; x++) { tree name = gimple_range_ssa_p (ssa_name (x)); - if (name && gori ().has_edge_range_p (name, e) - && m_cache.range_on_edge (range, e, name)) + if (!name || !gori ().has_edge_range_p (name, e)) + continue; + + Value_Range range (TREE_TYPE (name)); + if (m_cache.range_on_edge (range, e, name)) { gimple *s = SSA_NAME_DEF_STMT (name); + Value_Range tmp_range (TREE_TYPE (name)); // Only print the range if this is the def block, or // the on entry cache for either end of the edge is // set. diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index c67280d..34f6102 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -48,11 +48,11 @@ class gimple_ranger : public range_query public: gimple_ranger (bool use_imm_uses = true); ~gimple_ranger (); - virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) override; - virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) override; - virtual bool range_on_edge (irange &r, edge e, tree name) override; - void range_on_entry (irange &r, basic_block bb, tree name); - void range_on_exit (irange &r, basic_block bb, tree name); + virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override; + virtual bool range_of_expr (vrange &r, tree name, gimple * = NULL) override; + virtual bool range_on_edge (vrange &r, edge e, tree name) override; + void range_on_entry (vrange &r, basic_block bb, tree name); + void range_on_exit (vrange &r, basic_block bb, tree name); void export_global_ranges (); inline gori_compute &gori () { return m_cache.m_gori; } virtual void dump (FILE *f) override; @@ -62,8 +62,8 @@ public: bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree)); void register_inferred_ranges (gimple *s); protected: - bool fold_range_internal (irange &r, gimple *s, tree name); - void prefill_name (irange &r, tree name); + bool fold_range_internal (vrange &r, gimple *s, tree name); + void prefill_name (vrange &r, tree name); void prefill_stmt_dependencies (tree ssa); ranger_cache m_cache; range_tracer tracer; diff --git a/gcc/gimple-ssa-evrp-analyze.cc b/gcc/gimple-ssa-evrp-analyze.cc index 16e5a75..82142db 100644 --- a/gcc/gimple-ssa-evrp-analyze.cc +++ b/gcc/gimple-ssa-evrp-analyze.cc @@ -255,7 +255,7 @@ evrp_range_analyzer::record_ranges_from_phis (basic_block bb) /* Skips floats and other things we can't represent in a range. */ - if (!value_range::supports_type_p (TREE_TYPE (lhs))) + if (!value_range_equiv::supports_p (TREE_TYPE (lhs))) continue; value_range_equiv vr_result; diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 9357a4e..00f6585 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -328,11 +328,11 @@ check_nul_terminated_array (GimpleOrTree expr, tree src, tree bound) wide_int bndrng[2]; if (bound) { - value_range r; + Value_Range r (TREE_TYPE (bound)); get_global_range_query ()->range_of_expr (r, bound); - if (r.kind () != VR_RANGE) + if (r.undefined_p () || r.varying_p ()) return true; bndrng[0] = r.lower_bound (); @@ -2790,9 +2790,8 @@ memmodel_to_uhwi (tree ord, gimple *stmt, unsigned HOST_WIDE_INT *cstval) { /* Use the range query to determine constant values in the absence of constant propagation (such as at -O0). */ - value_range rng; + Value_Range rng (TREE_TYPE (ord)); if (!get_range_query (cfun)->range_of_expr (rng, ord, stmt) - || !rng.constant_p () || !rng.singleton_p (&ord)) return false; diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index f50a60b7..5fdf423 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,12 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * go-lang.cc (go_get_sarif_source_language): New. + (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (go.tags): Look at *.cc. + 2022-02-13 Ian Lance Taylor <iant@golang.org> * gospec.cc: Revert 2022-02-09 change: diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index 31c6773..0e81268 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -133,7 +133,7 @@ go.srcinfo: doc/gccgo.info go.srcextra: go.tags: force cd $(srcdir)/go; \ - $(ETAGS) -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \ + $(ETAGS) -o TAGS.sub *.cc *.h gofrontend/*.h gofrontend/*.cc; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub go.man: doc/gccgo.1 go.srcman: doc/gccgo.1 diff --git a/gcc/go/go-lang.cc b/gcc/go/go-lang.cc index c8365d2..84cd623 100644 --- a/gcc/go/go-lang.cc +++ b/gcc/go/go-lang.cc @@ -545,6 +545,15 @@ go_langhook_eh_personality (void) return personality_decl; } +/* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property, + based on the list in SARIF v2.1.0 Appendix J. */ + +static const char * +go_get_sarif_source_language (const char *) +{ + return "go"; +} + /* Functions called directly by the generic backend. */ tree @@ -615,6 +624,7 @@ go_localize_identifier (const char *ident) #undef LANG_HOOKS_GETDECLS #undef LANG_HOOKS_GIMPLIFY_EXPR #undef LANG_HOOKS_EH_PERSONALITY +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE #define LANG_HOOKS_NAME "GNU Go" #define LANG_HOOKS_INIT go_langhook_init @@ -631,6 +641,7 @@ go_localize_identifier (const char *ident) #define LANG_HOOKS_GETDECLS go_langhook_getdecls #define LANG_HOOKS_GIMPLIFY_EXPR go_langhook_gimplify_expr #define LANG_HOOKS_EH_PERSONALITY go_langhook_eh_personality +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE go_get_sarif_source_language struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/json.cc b/gcc/json.cc index 3bf9b61..974f8c3 100644 --- a/gcc/json.cc +++ b/gcc/json.cc @@ -207,7 +207,7 @@ string::print (pretty_printer *pp) const pp_string (pp, "\\\""); break; case '\\': - pp_string (pp, "\\n"); + pp_string (pp, "\\\\"); break; case '\b': pp_string (pp, "\\b"); diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 95d8dec..4e17915 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -98,6 +98,7 @@ extern const char *lhd_get_substring_location (const substring_loc &, extern int lhd_decl_dwarf_attribute (const_tree, int); extern int lhd_type_dwarf_attribute (const_tree, int); extern void lhd_finalize_early_debug (void); +extern const char *lhd_get_sarif_source_language (const char *); #define LANG_HOOKS_NAME "GNU unknown" #define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct lang_identifier) @@ -150,6 +151,7 @@ extern void lhd_finalize_early_debug (void); #define LANG_HOOKS_RUN_LANG_SELFTESTS lhd_do_nothing #define LANG_HOOKS_GET_SUBSTRING_LOCATION lhd_get_substring_location #define LANG_HOOKS_FINALIZE_EARLY_DEBUG lhd_finalize_early_debug +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE lhd_get_sarif_source_language /* Attribute hooks. */ #define LANG_HOOKS_ATTRIBUTE_TABLE NULL @@ -394,7 +396,8 @@ extern void lhd_end_section (void); LANG_HOOKS_EMITS_BEGIN_STMT, \ LANG_HOOKS_RUN_LANG_SELFTESTS, \ LANG_HOOKS_GET_SUBSTRING_LOCATION, \ - LANG_HOOKS_FINALIZE_EARLY_DEBUG \ + LANG_HOOKS_FINALIZE_EARLY_DEBUG, \ + LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE \ } #endif /* GCC_LANG_HOOKS_DEF_H */ diff --git a/gcc/langhooks.cc b/gcc/langhooks.cc index 97e5139..a933407 100644 --- a/gcc/langhooks.cc +++ b/gcc/langhooks.cc @@ -925,6 +925,14 @@ lhd_finalize_early_debug (void) (*debug_hooks->early_global_decl) (cnode->decl); } +/* Default implementation of LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE. */ + +const char * +lhd_get_sarif_source_language (const char *) +{ + return NULL; +} + /* Returns true if the current lang_hooks represents the GNU C frontend. */ bool diff --git a/gcc/langhooks.h b/gcc/langhooks.h index 7502555..97aa9e0 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -640,6 +640,12 @@ struct lang_hooks /* Invoked before the early_finish debug hook is invoked. */ void (*finalize_early_debug) (void); + /* Get a value for the SARIF v2.1.0 "artifact.sourceLanguage" property + for FILENAME, or return NULL. + See SARIF v2.1.0 Appendix J for suggested values for common programming + languages. */ + const char *(*get_sarif_source_language) (const char *filename); + /* Whenever you add entries here, make sure you adjust langhooks-def.h and langhooks.cc accordingly. */ }; diff --git a/gcc/logical-location.h b/gcc/logical-location.h new file mode 100644 index 0000000..2e7b8e3 --- /dev/null +++ b/gcc/logical-location.h @@ -0,0 +1,72 @@ +/* Logical location support, without knowledge of "tree". + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_LOGICAL_LOCATION_H +#define GCC_LOGICAL_LOCATION_H + +/* An enum for discriminating between different kinds of logical location + for a diagnostic. + + Roughly corresponds to logicalLocation's "kind" property in SARIF v2.1.0 + (section 3.33.7). */ + +enum logical_location_kind +{ + LOGICAL_LOCATION_KIND_UNKNOWN, + + LOGICAL_LOCATION_KIND_FUNCTION, + LOGICAL_LOCATION_KIND_MEMBER, + LOGICAL_LOCATION_KIND_MODULE, + LOGICAL_LOCATION_KIND_NAMESPACE, + LOGICAL_LOCATION_KIND_TYPE, + LOGICAL_LOCATION_KIND_RETURN_TYPE, + LOGICAL_LOCATION_KIND_PARAMETER, + LOGICAL_LOCATION_KIND_VARIABLE +}; + +/* Abstract base class for passing around logical locations in the + diagnostics subsystem, such as: + - "within function 'foo'", or + - "within method 'bar'", + but *without* requiring knowledge of trees + (see tree-logical-location.h for subclasses relating to trees). */ + +class logical_location +{ +public: + virtual ~logical_location () {} + + /* Get a string (or NULL) suitable for use by the SARIF logicalLocation + "name" property (SARIF v2.1.0 section 3.33.4). */ + virtual const char *get_short_name () const = 0; + + /* Get a string (or NULL) suitable for use by the SARIF logicalLocation + "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */ + virtual const char *get_name_with_scope () const = 0; + + /* Get a string (or NULL) suitable for use by the SARIF logicalLocation + "decoratedName" property (SARIF v2.1.0 section 3.33.6). */ + virtual const char *get_internal_name () const = 0; + + /* Get what kind of SARIF logicalLocation this is (if any). */ + virtual enum logical_location_kind get_kind () const = 0; +}; + +#endif /* GCC_LOGICAL_LOCATION_H. */ diff --git a/gcc/loop-iv.cc b/gcc/loop-iv.cc index 0eafe7d..d639336 100644 --- a/gcc/loop-iv.cc +++ b/gcc/loop-iv.cc @@ -1378,49 +1378,6 @@ simple_rhs_p (rtx rhs) } } -/* If REGNO has a single definition, return its known value, otherwise return - null. */ - -static rtx -find_single_def_src (unsigned int regno) -{ - rtx src = NULL_RTX; - - /* Don't look through unbounded number of single definition REG copies, - there might be loops for sources with uninitialized variables. */ - for (int cnt = 0; cnt < 128; cnt++) - { - df_ref adef = DF_REG_DEF_CHAIN (regno); - if (adef == NULL || DF_REF_NEXT_REG (adef) != NULL - || DF_REF_IS_ARTIFICIAL (adef)) - return NULL_RTX; - - rtx set = single_set (DF_REF_INSN (adef)); - if (set == NULL || !REG_P (SET_DEST (set)) - || REGNO (SET_DEST (set)) != regno) - return NULL_RTX; - - rtx note = find_reg_equal_equiv_note (DF_REF_INSN (adef)); - if (note && function_invariant_p (XEXP (note, 0))) - { - src = XEXP (note, 0); - break; - } - src = SET_SRC (set); - - if (REG_P (src)) - { - regno = REGNO (src); - continue; - } - break; - } - if (!function_invariant_p (src)) - return NULL_RTX; - - return src; -} - /* If any registers in *EXPR that have a single definition, try to replace them with the known-equivalent values. */ @@ -1433,7 +1390,7 @@ replace_single_def_regs (rtx *expr) { rtx x = *iter; if (REG_P (x)) - if (rtx new_x = find_single_def_src (REGNO (x))) + if (rtx new_x = df_find_single_def_src (x)) { *expr = simplify_replace_rtx (*expr, x, new_x); goto repeat; diff --git a/gcc/match.pd b/gcc/match.pd index 88c6c41..44a385b 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5969,6 +5969,41 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) && (!TYPE_UNSIGNED (TREE_TYPE (@2)) || TYPE_UNSIGNED (TREE_TYPE (@0)))) (ovf @1 @0)))) +/* Optimize __builtin_mul_overflow_p (x, cst, (utype) 0) if all 3 types + are unsigned to x > (umax / cst). Similarly for signed type, but + in that case it needs to be outside of a range. */ +(simplify + (imagpart (IFN_MUL_OVERFLOW:cs@2 @0 integer_nonzerop@1)) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && TYPE_MAX_VALUE (TREE_TYPE (@0)) + && types_match (TREE_TYPE (@0), TREE_TYPE (TREE_TYPE (@2))) + && int_fits_type_p (@1, TREE_TYPE (@0))) + (if (TYPE_UNSIGNED (TREE_TYPE (@0))) + (convert (gt @0 (trunc_div! { TYPE_MAX_VALUE (TREE_TYPE (@0)); } @1))) + (if (TYPE_MIN_VALUE (TREE_TYPE (@0))) + (if (integer_minus_onep (@1)) + (convert (eq @0 { TYPE_MIN_VALUE (TREE_TYPE (@0)); })) + (with + { + tree lo = int_const_binop (TRUNC_DIV_EXPR, + TYPE_MIN_VALUE (TREE_TYPE (@0)), + fold_convert (TREE_TYPE (@0), @1)); + tree hi = int_const_binop (TRUNC_DIV_EXPR, + TYPE_MAX_VALUE (TREE_TYPE (@0)), + fold_convert (TREE_TYPE (@0), @1)); + tree etype = range_check_type (TREE_TYPE (@0)); + if (etype) + { + if (wi::neg_p (wi::to_wide (@1))) + std::swap (lo, hi); + lo = fold_convert (etype, lo); + hi = fold_convert (etype, hi); + hi = int_const_binop (MINUS_EXPR, hi, lo); + } + } + (if (etype) + (convert (gt (minus (convert:etype @0) { lo; }) { hi; }))))))))) + /* Simplification of math builtins. These rules must all be optimizations as well as IL simplifications. If there is a possibility that the new form could be a pessimization, the rule should go in the canonicalization diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index 007558c..01720f7 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,13 @@ +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * objc-act.h (objc_get_sarif_source_language): New decl. + * objc-lang.cc (LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE): Redefine. + (objc_get_sarif_source_language): New. + +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (objc.tags): Look at *.cc. + 2022-05-25 Jakub Jelinek <jakub@redhat.com> PR c/91134 diff --git a/gcc/objc/Make-lang.in b/gcc/objc/Make-lang.in index 6e4ebf5..b2ebd86 100644 --- a/gcc/objc/Make-lang.in +++ b/gcc/objc/Make-lang.in @@ -102,7 +102,7 @@ objc.srcman: objc.install-plugin: objc.tags: force - cd $(srcdir)/objc; $(ETAGS) -o TAGS.sub *.c *.h; \ + cd $(srcdir)/objc; $(ETAGS) -o TAGS.sub *.cc *.h; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub lang_checks += check-objc diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 7d0c6d5..4f9c3a2 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -27,6 +27,7 @@ bool objc_init (void); const char *objc_printable_name (tree, int); int objc_gimplify_expr (tree *, gimple_seq *, gimple_seq *); void objc_common_init_ts (void); +const char *objc_get_sarif_source_language (const char *); /* NB: The remaining public functions are prototyped in c-common.h, for the benefit of stub-objc.cc and objc-act.cc. */ diff --git a/gcc/objc/objc-lang.cc b/gcc/objc/objc-lang.cc index ef664f5..559de4b 100644 --- a/gcc/objc/objc-lang.cc +++ b/gcc/objc/objc-lang.cc @@ -46,10 +46,18 @@ enum c_language_kind c_language = clk_objc; #define LANG_HOOKS_INIT_TS objc_common_init_ts #undef LANG_HOOKS_TREE_SIZE #define LANG_HOOKS_TREE_SIZE objc_common_tree_size +#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE +#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE objc_get_sarif_source_language /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; +const char * +objc_get_sarif_source_language (const char *) +{ + return "objectivec"; +} + /* Lang hook routines common to C and ObjC appear in c-objc-common.cc; there should be very few (if any) routines below. */ diff --git a/gcc/objcp/ChangeLog b/gcc/objcp/ChangeLog index d50c3d8..c5b292a 100644 --- a/gcc/objcp/ChangeLog +++ b/gcc/objcp/ChangeLog @@ -1,3 +1,7 @@ +2022-05-31 Jason Merrill <jason@redhat.com> + + * Make-lang.in (obj-c++.tags): Look at *.cc. + 2022-05-11 Martin Liska <mliska@suse.cz> PR target/105355 diff --git a/gcc/objcp/Make-lang.in b/gcc/objcp/Make-lang.in index fc8e05b..bd2466c 100644 --- a/gcc/objcp/Make-lang.in +++ b/gcc/objcp/Make-lang.in @@ -136,7 +136,7 @@ obj-c++.man: obj-c++.install-plugin: obj-c++.tags: force - cd $(srcdir)/objcp; $(ETAGS) -o TAGS.sub *.c *.h; \ + cd $(srcdir)/objcp; $(ETAGS) -o TAGS.sub *.cc *.h; \ $(ETAGS) --include TAGS.sub --include ../TAGS.sub lang_checks += check-obj-c++ diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index 16f5965..f976e3a 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -683,6 +683,7 @@ build_outer_var_ref (tree var, omp_context *ctx, else if ((gimple_code (ctx->stmt) == GIMPLE_OMP_FOR && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_SIMD) || ctx->loop_p + || code == OMP_CLAUSE_ALLOCATE || (code == OMP_CLAUSE_PRIVATE && (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR || gimple_code (ctx->stmt) == GIMPLE_OMP_SECTIONS @@ -4849,7 +4850,7 @@ lower_private_allocate (tree var, tree new_var, tree &allocator, allocator = TREE_PURPOSE (allocator); } if (TREE_CODE (allocator) != INTEGER_CST) - allocator = build_outer_var_ref (allocator, ctx); + allocator = build_outer_var_ref (allocator, ctx, OMP_CLAUSE_ALLOCATE); allocator = fold_convert (pointer_sized_int_node, allocator); if (TREE_CODE (allocator) != INTEGER_CST) { diff --git a/gcc/optabs-query.cc b/gcc/optabs-query.cc index 809482b..44ce41e 100644 --- a/gcc/optabs-query.cc +++ b/gcc/optabs-query.cc @@ -426,7 +426,7 @@ can_vec_perm_const_p (machine_mode mode, machine_mode op_mode, return false; /* It's probably cheaper to test for the variable case first. */ - if (allow_variable_p && selector_fits_mode_p (mode, sel)) + if (op_mode == mode && allow_variable_p && selector_fits_mode_p (mode, sel)) { if (direct_optab_handler (vec_perm_optab, mode) != CODE_FOR_nothing) return true; diff --git a/gcc/opts.cc b/gcc/opts.cc index f0c5c4d..bf06a55 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -2800,7 +2800,7 @@ common_handle_option (struct gcc_options *opts, break; case OPT_fdiagnostics_format_: - diagnostic_output_format_init (dc, + diagnostic_output_format_init (dc, opts->x_dump_base_name, (enum diagnostics_output_format)value); break; diff --git a/gcc/plugin.cc b/gcc/plugin.cc index 17b33e4..6c42e05 100644 --- a/gcc/plugin.cc +++ b/gcc/plugin.cc @@ -815,6 +815,44 @@ finalize_plugins (void) plugin_name_args_tab = NULL; } +/* Implementation detail of for_each_plugin. */ + +struct for_each_plugin_closure +{ + void (*cb) (const plugin_name_args *, + void *user_data); + void *user_data; +}; + +/* Implementation detail of for_each_plugin: callback for htab_traverse_noresize + that calls the user-provided callback. */ + +static int +for_each_plugin_cb (void **slot, void *info) +{ + struct plugin_name_args *plugin = (struct plugin_name_args *) *slot; + for_each_plugin_closure *c = (for_each_plugin_closure *)info; + c->cb (plugin, c->user_data); + return 1; +} + +/* Call CB with USER_DATA on each plugin. */ + +void +for_each_plugin (void (*cb) (const plugin_name_args *, + void *user_data), + void *user_data) +{ + if (!plugin_name_args_tab) + return; + + for_each_plugin_closure c; + c.cb = cb; + c.user_data = user_data; + + htab_traverse_noresize (plugin_name_args_tab, for_each_plugin_cb, &c); +} + /* Used to pass options to htab_traverse callbacks. */ struct print_options diff --git a/gcc/plugin.h b/gcc/plugin.h index ff999c4..e7e8b51 100644 --- a/gcc/plugin.h +++ b/gcc/plugin.h @@ -170,6 +170,9 @@ extern void warn_if_plugins (void); extern void print_plugins_versions (FILE *file, const char *indent); extern void print_plugins_help (FILE *file, const char *indent); extern void finalize_plugins (void); +extern void for_each_plugin (void (*cb) (const plugin_name_args *, + void *user_data), + void *user_data); extern bool flag_plugin_added; diff --git a/gcc/range-op.cc b/gcc/range-op.cc index c88da8c..5150c60 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -111,7 +111,7 @@ range_operator::wi_fold (irange &r, tree type, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const { - gcc_checking_assert (irange::supports_type_p (type)); + gcc_checking_assert (r.supports_type_p (type)); r.set_varying (type); } @@ -181,7 +181,7 @@ range_operator::fold_range (irange &r, tree type, const irange &rh, relation_kind rel) const { - gcc_checking_assert (irange::supports_type_p (type)); + gcc_checking_assert (r.supports_type_p (type)); if (empty_range_varying (r, type, lh, rh)) return true; @@ -420,7 +420,7 @@ create_possibly_reversed_range (irange &r, tree type, // return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing. bool_range_state -get_bool_state (irange &r, const irange &lhs, tree val_type) +get_bool_state (vrange &r, const vrange &lhs, tree val_type) { // If there is no result, then this is unexecutable. if (lhs.undefined_p ()) @@ -446,6 +446,9 @@ get_bool_state (irange &r, const irange &lhs, tree val_type) class operator_equal : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -562,6 +565,9 @@ operator_equal::op2_range (irange &r, tree type, class operator_not_equal : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -738,6 +744,9 @@ build_ge (irange &r, tree type, const wide_int &val) class operator_lt : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -846,6 +855,9 @@ operator_lt::op2_range (irange &r, tree type, class operator_le : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -954,6 +966,9 @@ operator_le::op2_range (irange &r, tree type, class operator_gt : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -1061,6 +1076,9 @@ operator_gt::op2_range (irange &r, tree type, class operator_ge : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -1169,6 +1187,10 @@ operator_ge::op2_range (irange &r, tree type, class operator_plus : public range_operator { + using range_operator::op1_range; + using range_operator::op2_range; + using range_operator::lhs_op1_relation; + using range_operator::lhs_op2_relation; public: virtual bool op1_range (irange &r, tree type, const irange &lhs, @@ -1286,7 +1308,7 @@ operator_plus::op1_range (irange &r, tree type, const irange &op2, relation_kind rel ATTRIBUTE_UNUSED) const { - return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2); + return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op2); } bool @@ -1295,12 +1317,15 @@ operator_plus::op2_range (irange &r, tree type, const irange &op1, relation_kind rel ATTRIBUTE_UNUSED) const { - return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1); + return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op1); } class operator_minus : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool op1_range (irange &r, tree type, const irange &lhs, @@ -1445,7 +1470,7 @@ operator_minus::op1_range (irange &r, tree type, const irange &op2, relation_kind rel ATTRIBUTE_UNUSED) const { - return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2); + return range_op_handler (PLUS_EXPR, type).fold_range (r, type, lhs, op2); } bool @@ -1597,6 +1622,8 @@ cross_product_operator::wi_cross_product (irange &r, tree type, class operator_mult : public cross_product_operator { + using range_operator::op1_range; + using range_operator::op2_range; public: virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, @@ -1629,8 +1656,8 @@ operator_mult::op1_range (irange &r, tree type, return false; if (op2.singleton_p (&offset) && !integer_zerop (offset)) - return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type, - lhs, op2); + return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type, + lhs, op2); return false; } @@ -1857,6 +1884,7 @@ operator_div op_ceil_div (CEIL_DIV_EXPR); class operator_exact_divide : public operator_div { + using range_operator::op1_range; public: operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { } virtual bool op1_range (irange &r, tree type, @@ -1881,13 +1909,15 @@ operator_exact_divide::op1_range (irange &r, tree type, // If op2 is a multiple of 2, we would be able to set some non-zero bits. if (op2.singleton_p (&offset) && !integer_zerop (offset)) - return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2); + return range_op_handler (MULT_EXPR, type).fold_range (r, type, lhs, op2); return false; } class operator_lshift : public cross_product_operator { + using range_operator::fold_range; + using range_operator::op1_range; public: virtual bool op1_range (irange &r, tree type, const irange &lhs, @@ -1909,6 +1939,9 @@ public: class operator_rshift : public cross_product_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::lhs_op1_relation; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -2248,6 +2281,8 @@ operator_rshift::wi_fold (irange &r, tree type, class operator_cast: public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -2417,10 +2452,9 @@ operator_cast::op1_range (irange &r, tree type, // Add this to the unsigned LHS range(s). int_range_max lim_range (type, lim, lim); int_range_max lhs_neg; - range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg, - type, - converted_lhs, - lim_range); + range_op_handler (PLUS_EXPR, type).fold_range (lhs_neg, type, + converted_lhs, + lim_range); // lhs_neg now has all the negative versions of the LHS. // Now union in all the values from SIGNED MIN (0x80000) to // lim-1 in order to fill in all the ranges with the upper @@ -2469,6 +2503,9 @@ operator_cast::op1_range (irange &r, tree type, class operator_logical_and : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &lh, @@ -2542,6 +2579,9 @@ operator_logical_and::op2_range (irange &r, tree type, class operator_bitwise_and : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &lh, @@ -2988,6 +3028,9 @@ operator_bitwise_and::op2_range (irange &r, tree type, class operator_logical_or : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool fold_range (irange &r, tree type, const irange &lh, @@ -3051,6 +3094,8 @@ operator_logical_or::op2_range (irange &r, tree type, class operator_bitwise_or : public range_operator { + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool op1_range (irange &r, tree type, const irange &lhs, @@ -3155,6 +3200,8 @@ operator_bitwise_or::op2_range (irange &r, tree type, class operator_bitwise_xor : public range_operator { + using range_operator::op1_range; + using range_operator::op2_range; public: virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, @@ -3296,6 +3343,8 @@ operator_bitwise_xor::op2_range (irange &r, tree type, class operator_trunc_mod : public range_operator { + using range_operator::op1_range; + using range_operator::op2_range; public: virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, @@ -3432,6 +3481,8 @@ operator_trunc_mod::op2_range (irange &r, tree type, class operator_logical_not : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; public: virtual bool fold_range (irange &r, tree type, const irange &lh, @@ -3487,6 +3538,8 @@ operator_logical_not::op1_range (irange &r, class operator_bitwise_not : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; public: virtual bool fold_range (irange &r, tree type, const irange &lh, @@ -3513,8 +3566,7 @@ operator_bitwise_not::fold_range (irange &r, tree type, // ~X is simply -1 - X. int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)), wi::minus_one (TYPE_PRECISION (type))); - return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone, - lh); + return range_op_handler (MINUS_EXPR, type).fold_range (r, type, minusone, lh); } bool @@ -3533,6 +3585,7 @@ operator_bitwise_not::op1_range (irange &r, tree type, class operator_cst : public range_operator { + using range_operator::fold_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -3553,6 +3606,9 @@ operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, class operator_identity : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; + using range_operator::lhs_op1_relation; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -3605,6 +3661,7 @@ operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED, class operator_unknown : public range_operator { + using range_operator::fold_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -3625,6 +3682,7 @@ operator_unknown::fold_range (irange &r, tree type, class operator_abs : public range_operator { + using range_operator::op1_range; public: virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, @@ -3790,6 +3848,8 @@ operator_absu::wi_fold (irange &r, tree type, class operator_negate : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -3810,9 +3870,8 @@ operator_negate::fold_range (irange &r, tree type, if (empty_range_varying (r, type, lh, rh)) return true; // -X is simply 0 - X. - return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, - range_zero (type), - lh); + return range_op_handler (MINUS_EXPR, type).fold_range (r, type, + range_zero (type), lh); } bool @@ -3828,6 +3887,8 @@ operator_negate::op1_range (irange &r, tree type, class operator_addr_expr : public range_operator { + using range_operator::fold_range; + using range_operator::op1_range; public: virtual bool fold_range (irange &r, tree type, const irange &op1, @@ -3978,6 +4039,8 @@ pointer_and_operator::wi_fold (irange &r, tree type, class pointer_or_operator : public range_operator { + using range_operator::op1_range; + using range_operator::op2_range; public: virtual bool op1_range (irange &r, tree type, const irange &lhs, @@ -4139,8 +4202,8 @@ pointer_table::pointer_table () // The tables are hidden and accessed via a simple extern function. -range_operator * -range_op_handler (enum tree_code code, tree type) +static inline range_operator * +get_handler (enum tree_code code, tree type) { // First check if there is a pointer specialization. if (POINTER_TYPE_P (type)) @@ -4150,16 +4213,120 @@ range_op_handler (enum tree_code code, tree type) return NULL; } +range_op_handler::range_op_handler (tree_code code, tree type) +{ + m_op = get_handler (code, type); +} + +range_op_handler::range_op_handler (const gimple *s) +{ + if (const gassign *ass = dyn_cast<const gassign *> (s)) + { + enum tree_code code = gimple_assign_rhs_code (ass); + // The LHS of a comparison is always an int, so we must look at + // the operands. + if (TREE_CODE_CLASS (code) == tcc_comparison) + m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass))); + else + m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass))); + } + else if (const gcond *cond = dyn_cast<const gcond *> (s)) + m_op = get_handler (gimple_cond_code (cond), + TREE_TYPE (gimple_cond_lhs (cond))); + else + m_op = NULL; +} + +bool +range_op_handler::fold_range (vrange &r, tree type, + const vrange &lh, + const vrange &rh, + relation_kind rel) const +{ + if (is_a <irange> (lh)) + return m_op->fold_range (as_a <irange> (r), type, + as_a <irange> (lh), + as_a <irange> (rh), rel); + gcc_unreachable (); + return false; +} + +bool +range_op_handler::op1_range (vrange &r, tree type, + const vrange &lhs, + const vrange &op2, + relation_kind rel) const +{ + if (is_a <irange> (r)) + return m_op->op1_range (as_a <irange> (r), type, + as_a <irange> (lhs), + as_a <irange> (op2), rel); + gcc_unreachable (); + return false; +} + +bool +range_op_handler::op2_range (vrange &r, tree type, + const vrange &lhs, + const vrange &op1, + relation_kind rel) const +{ + if (is_a <irange> (r)) + return m_op->op2_range (as_a <irange> (r), type, + as_a <irange> (lhs), + as_a <irange> (op1), rel); + gcc_unreachable (); + return false; +} + +relation_kind +range_op_handler::lhs_op1_relation (const vrange &lhs, + const vrange &op1, + const vrange &op2, + relation_kind rel) const +{ + if (is_a <irange> (op1)) + return m_op->lhs_op1_relation (as_a <irange> (lhs), + as_a <irange> (op1), as_a <irange> (op2), rel); + gcc_unreachable (); + return VREL_VARYING; +} + +relation_kind +range_op_handler::lhs_op2_relation (const vrange &lhs, + const vrange &op1, + const vrange &op2, + relation_kind rel) const +{ + if (is_a <irange> (op1)) + return m_op->lhs_op2_relation (as_a <irange> (lhs), + as_a <irange> (op1), as_a <irange> (op2), rel); + gcc_unreachable (); + return VREL_VARYING; +} + +relation_kind +range_op_handler::op1_op2_relation (const vrange &lhs) const +{ + return m_op->op1_op2_relation (as_a <irange> (lhs)); +} + // Cast the range in R to TYPE. -void -range_cast (irange &r, tree type) +bool +range_cast (vrange &r, tree type) { - int_range_max tmp = r; - range_operator *op = range_op_handler (CONVERT_EXPR, type); + Value_Range tmp (r); + Value_Range varying (type); + varying.set_varying (type); + range_op_handler op (CONVERT_EXPR, type); // Call op_convert, if it fails, the result is varying. - if (!op->fold_range (r, type, tmp, int_range<1> (type))) - r.set_varying (type); + if (!op || !op.fold_range (r, type, tmp, varying)) + { + r.set_varying (type); + return false; + } + return true; } #if CHECKING_P diff --git a/gcc/range-op.h b/gcc/range-op.h index 300974f..262c796 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -108,8 +108,39 @@ protected: const wide_int &rh_ub) const; }; -extern range_operator *range_op_handler (enum tree_code code, tree type); -extern void range_cast (irange &, tree type); +class range_op_handler +{ +public: + range_op_handler (enum tree_code code, tree type); + range_op_handler (const gimple *s); + operator bool () const { return m_op; } + + bool fold_range (vrange &r, tree type, + const vrange &lh, + const vrange &rh, + relation_kind rel = VREL_VARYING) const; + bool op1_range (vrange &r, tree type, + const vrange &lhs, + const vrange &op2, + relation_kind rel = VREL_VARYING) const; + bool op2_range (vrange &r, tree type, + const vrange &lhs, + const vrange &op1, + relation_kind rel = VREL_VARYING) const; + relation_kind lhs_op1_relation (const vrange &lhs, + const vrange &op1, + const vrange &op2, + relation_kind = VREL_VARYING) const; + relation_kind lhs_op2_relation (const vrange &lhs, + const vrange &op1, + const vrange &op2, + relation_kind = VREL_VARYING) const; + relation_kind op1_op2_relation (const vrange &lhs) const; +private: + range_operator *m_op; +}; + +extern bool range_cast (vrange &, tree type); extern void wi_set_zero_nonzero_bits (tree type, const wide_int &, const wide_int &, wide_int &maybe_nonzero, @@ -124,7 +155,7 @@ relation_kind gt_op1_op2_relation (const irange &lhs); relation_kind ge_op1_op2_relation (const irange &lhs); enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL }; -bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type); +bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type); // If the range of either op1 or op2 is undefined, set the result to // varying and return TRUE. If the caller truely cares about a result, @@ -132,8 +163,8 @@ bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type); // treated as a varying. inline bool -empty_range_varying (irange &r, tree type, - const irange &op1, const irange & op2) +empty_range_varying (vrange &r, tree type, + const vrange &op1, const vrange & op2) { if (op1.undefined_p () || op2.undefined_p ()) { @@ -150,8 +181,8 @@ empty_range_varying (irange &r, tree type, // return false. inline bool -relop_early_resolve (irange &r, tree type, const irange &op1, - const irange &op2, relation_kind rel, +relop_early_resolve (irange &r, tree type, const vrange &op1, + const vrange &op2, relation_kind rel, relation_kind my_rel) { // If known relation is a complete subset of this relation, always true. diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc index 7c29682..d78cc60 100644 --- a/gcc/rtlanal.cc +++ b/gcc/rtlanal.cc @@ -4578,6 +4578,11 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code, switch (code) { case MULT: + case FMA: + case SS_MULT: + case US_MULT: + case SMUL_HIGHPART: + case UMUL_HIGHPART: /* Multiplication has time-complexity O(N*N), where N is the number of units (translated from digits) when using schoolbook long multiplication. */ @@ -4587,6 +4592,8 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code, case UDIV: case MOD: case UMOD: + case SS_DIV: + case US_DIV: /* Similarly, complexity for schoolbook long division. */ total = factor * factor * COSTS_N_INSNS (7); break; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 677e064..b3ac3e4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,227 @@ +2022-06-04 Marek Polacek <polacek@redhat.com> + + PR c++/102399 + PR c++/69585 + * g++.dg/ext/attrib65.C: New test. + * g++.dg/ext/attrib66.C: New test. + * g++.dg/ext/attrib67.C: New test. + +2022-06-04 Roger Sayle <roger@nextmovesoftware.com> + + PR middle-end/95126 + * gcc.target/i386/pr95126-m32-1.c: New test case. + * gcc.target/i386/pr95126-m32-2.c: New test case. + * gcc.target/i386/pr95126-m32-3.c: New test case. + * gcc.target/i386/pr95126-m32-4.c: New test case. + * gcc.target/i386/pr95126-m64-1.c: New test case. + * gcc.target/i386/pr95126-m64-2.c: New test case. + * gcc.target/i386/pr95126-m64-3.c: New test case. + * gcc.target/i386/pr95126-m64-4.c: New test case. + +2022-06-04 Jakub Jelinek <jakub@redhat.com> + + PR target/105825 + * gcc.dg/pr105825.c: New test. + +2022-06-03 Jason Merrill <jason@redhat.com> + + * g++.dg/cpp0x/auto56.C: New test. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/105756 + * g++.dg/cpp0x/decltype82.C: New test. + +2022-06-03 Jason Merrill <jason@redhat.com> + + PR c++/105761 + * g++.dg/cpp1y/auto-fn64.C: New test. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/105637 + * g++.dg/cpp0x/lambda/lambda-this22.C: New test. + * g++.dg/template/non-dependent23.C: New test. + +2022-06-03 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.dg/gomp/scope-6.f90: Fix dg-final scan-tree-dump. + +2022-06-03 Tobias Burnus <tobias@codesourcery.com> + + * gfortran.dg/gomp/scope-5.f90: New test. + * gfortran.dg/gomp/scope-6.f90: New test. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/100374 + * g++.dg/cpp2a/concepts-spec2.C: New test. + * g++.dg/cpp2a/concepts-template-parm11.C: New test. + +2022-06-03 Patrick Palka <ppalka@redhat.com> + + PR c++/105797 + * g++.dg/cpp2a/concepts-decltype4.C: New test. + * g++.dg/cpp2a/concepts-memfun3.C: New test. + +2022-06-03 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/30314 + PR middle-end/105777 + * gcc.dg/tree-ssa/pr30314.c: Add noipa attribute to all functions. + * gcc.dg/tree-ssa/pr105777.c: New test. + * gcc.c-torture/execute/pr30314.c: New test. + * gcc.c-torture/execute/pr105777.c: New test. + +2022-06-03 Alexandre Oliva <oliva@adacore.com> + + PR tree-optimization/105665 + PR tree-optimization/100810 + * gcc.dg/torture/pr105665.c: New. + +2022-06-02 Marek Polacek <polacek@redhat.com> + + PR c++/105803 + * g++.dg/template/new13.C: New test. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * c-c++-common/diagnostic-format-sarif-file-1.c: New test. + * c-c++-common/diagnostic-format-sarif-file-2.c: New test. + * c-c++-common/diagnostic-format-sarif-file-3.c: New test. + * c-c++-common/diagnostic-format-sarif-file-4.c: New test. + * gcc.dg/analyzer/file-meaning-1.c: New test. + * gcc.dg/analyzer/malloc-meaning-1.c: New test. + * gcc.dg/analyzer/malloc-sarif-1.c: New test. + * gcc.dg/plugin/analyzer_gil_plugin.c + (gil_diagnostic::get_meaning_for_state_change): New vfunc impl. + * gcc.dg/plugin/diagnostic-test-paths-5.c: New test. + * gcc.dg/plugin/plugin.exp (plugin_test_list): Add + diagnostic-test-paths-5.c to tests for + diagnostic_plugin_test_paths.c. + * lib/gcc-dg.exp: Load scansarif.exp. + * lib/scansarif.exp: New test. + +2022-06-02 David Malcolm <dmalcolm@redhat.com> + + * c-c++-common/diagnostic-format-json-file-1.c: New test. + * c-c++-common/diagnostic-format-json-stderr-1.c: New test. + +2022-06-02 Jason Merrill <jason@redhat.com> + + PR c++/105795 + * g++.dg/cpp1z/constexpr-aggr-base1.C: New test. + +2022-06-02 Roger Sayle <roger@nextmovesoftware.com> + + PR target/105791 + * gcc.target/i386/pr105791.c: New test case. + +2022-06-02 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/30314 + * gcc.dg/tree-ssa/pr30314.c: Add tests with swapped arguments. + +2022-06-02 Jakub Jelinek <jakub@redhat.com> + + PR target/105778 + * gcc.target/i386/pr105778.c: New test. + +2022-06-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/101668 + * gcc.target/i386/pr101668.c: New testcase. + * gcc.dg/vect/bb-slp-pr101668.c: Likewise. + +2022-06-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105802 + * g++.dg/opt/pr105802.C: New testcase. + +2022-06-01 H.J. Lu <hjl.tools@gmail.com> + + PR rtl-optimization/105638 + * g++.target/i386/pr105638.C: New test. + +2022-06-01 Jason Merrill <jason@redhat.com> + + PR c++/105734 + * g++.dg/cpp0x/auto57.C: New test. + +2022-06-01 Jason Merrill <jason@redhat.com> + + PR c++/105779 + * g++.dg/cpp1y/auto-fn63.C: New test. + +2022-06-01 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/30314 + * gcc.dg/tree-ssa/pr30314.c: New test. + +2022-06-01 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105786 + * gcc.dg/torture/pr105786.c: New testcase. + +2022-06-01 Jakub Jelinek <jakub@redhat.com> + + PR tree-optimization/105770 + * gcc.dg/pr105770.c: New test. + +2022-06-01 Richard Biener <rguenther@suse.de> + + PR tree-optimization/105763 + * gcc.dg/pr105763.c: New testcase. + +2022-05-31 Patrick Palka <ppalka@redhat.com> + + PR c++/105758 + * g++.dg/template/non-dependent24.C: New test. + +2022-05-31 Jakub Jelinek <jakub@redhat.com> + + * c-c++-common/gomp/scope-5.c: New test. + * c-c++-common/gomp/scope-6.c: New test. + * g++.dg/gomp/attrs-1.C (bar): Add firstprivate and allocate clauses + to scope construct. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + +2022-05-30 Harald Anlauf <anlauf@gmx.de> + + PR fortran/91300 + * gfortran.dg/allocate_alloc_opt_15.f90: New test. + +2022-05-30 Roger Sayle <roger@nextmovesoftware.com> + + PR rtl-optimization/101617 + * gcc.target/i386/pr101617.c: New test case. + +2022-05-30 Roger Sayle <roger@nextmovesoftware.com> + + PR target/70321 + * gcc.target/i386/pr70321.c: New test case. + * gcc.target/i386/sse4_1-stv-1.c: New test case. + +2022-05-30 Uroš Bizjak <ubizjak@gmail.com> + + * gcc.target/i386/pr105624.c: New test. + +2022-05-30 Vineet Gupta <vineetg@rivosinc.com> + + * gcc.target/riscv/fmax.c: Add dg-require-effective-target hard_float. + * gcc.target/riscv/fmaxf.c: Ditto. + * gcc.target/riscv/fmin.c: Ditto. + * gcc.target/riscv/fminf.c: Ditto. + * gcc.target/riscv/smax-ieee.c: Ditto. + * gcc.target/riscv/smax.c: Ditto. + * gcc.target/riscv/smaxf-ieee.c: Ditto. + * gcc.target/riscv/smaxf.c: Ditto. + * gcc.target/riscv/smin-ieee.c: Ditto. + * gcc.target/riscv/smin.c: Ditto. + * gcc.target/riscv/sminf-ieee.c: Ditto. + * gcc.target/riscv/sminf.c: Ditto. + * gcc.target/riscv/pr105666.c: Ditto. + 2022-05-29 Jakub Jelinek <jakub@redhat.com> PR preprocessor/105732 diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c new file mode 100644 index 0000000..ddac780 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-file-1.c @@ -0,0 +1,8 @@ +/* Check that -fdiagnostics-format=json-file works. */ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=json-file" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ +/* { dg-final { scan-file "diagnostic-format-json-file-1.c.gcc.json" "\"message\": \"#warning message\"" } } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c new file mode 100644 index 0000000..02f780b --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-json-stderr-1.c @@ -0,0 +1,33 @@ +/* Check that "json" and "json-stderr" are synonymous when used as + arguments to "-fdiagnostics-format=". */ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=json-stderr" } */ + +#error message + +/* Use dg-regexp to consume the JSON output starting with + the innermost values, and working outwards. + We can't rely on any ordering of the keys. */ + +/* { dg-regexp "\"kind\": \"error\"" } */ +/* { dg-regexp "\"column-origin\": 1" } */ +/* { dg-regexp "\"escape-source\": false" } */ +/* { dg-regexp "\"message\": \"#error message\"" } */ + +/* { dg-regexp "\"caret\": \{" } */ +/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-stderr-1.c\"" } */ +/* { dg-regexp "\"line\": 6" } */ +/* { dg-regexp "\"column\": 2" } */ +/* { dg-regexp "\"display-column\": 2" } */ +/* { dg-regexp "\"byte-column\": 2" } */ + +/* { dg-regexp "\"finish\": \{" } */ +/* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-stderr-1.c\"" } */ +/* { dg-regexp "\"line\": 6" } */ +/* { dg-regexp "\"column\": 6" } */ +/* { dg-regexp "\"display-column\": 6" } */ +/* { dg-regexp "\"byte-column\": 6" } */ + +/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */ +/* { dg-regexp "\"children\": \[\[\]\[\]\]" } */ +/* { dg-regexp "\[\[\{\}, \]*\]" } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c new file mode 100644 index 0000000..4d19ae1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ + +#warning message + +/* Verify that some JSON was written to a file with the expected name. */ + +/* We expect various properties. + The indentation here reflects the expected hierarchy, though these tests + don't check for that, merely the string fragments we expect. + { dg-final { scan-sarif-file "\"version\": \"2.1.0\"" } } + { dg-final { scan-sarif-file "\"runs\": \\\[" } } + { dg-final { scan-sarif-file "\"artifacts\": \\\[" } } + { dg-final { scan-sarif-file "\"location\": " } } + { dg-final { scan-sarif-file "\"uri\": " } } + + { dg-final { scan-sarif-file "\"sourceLanguage\": \"c\"" { target c } } } + { dg-final { scan-sarif-file "\"sourceLanguage\": \"cplusplus\"" { target c++ } } } + + { dg-final { scan-sarif-file "\"contents\": " } } + { dg-final { scan-sarif-file "\"text\": " } } + { dg-final { scan-sarif-file "\"tool\": " } } + { dg-final { scan-sarif-file "\"driver\": " } } + { dg-final { scan-sarif-file "\"name\": \"GNU C" } } + { dg-final { scan-sarif-file "\"fullName\": \"GNU C" } } + { dg-final { scan-sarif-file "\"informationUri\": \"" } } + { dg-final { scan-sarif-file "\"results\": \\\[" } } + { dg-final { scan-sarif-file "\"level\": \"warning\"" } } + { dg-final { scan-sarif-file "\"ruleId\": \"-Wcpp\"" } } + { dg-final { scan-sarif-file "\"locations\": \\\[" } } + { dg-final { scan-sarif-file "\"physicalLocation\": " } } + { dg-final { scan-sarif-file "\"contextRegion\": " } } + { dg-final { scan-sarif-file "\"artifactLocation\": " } } + { dg-final { scan-sarif-file "\"region\": " } } + { dg-final { scan-sarif-file "\"startLine\": 4" } } + { dg-final { scan-sarif-file "\"startColumn\": 2" } } + { dg-final { scan-sarif-file "\"endColumn\": 9" } } + + We don't expect logical locations for a top-level warning: + { dg-final { scan-sarif-file-not "\"logicalLocations\": " } } + + { dg-final { scan-sarif-file "\"message\": " } } + { dg-final { scan-sarif-file "\"text\": \"#warning message" } } */ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-2.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-2.c new file mode 100644 index 0000000..8f5814d --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-2.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file -Wmisleading-indentation" } */ + +int test (void) +{ + if (1) + return 3; + return 4; + return 5; +} + +/* + { dg-final { scan-sarif-file "\"level\": \"warning\"" } } + { dg-final { scan-sarif-file "\"ruleId\": \"-Wmisleading-indentation\"" } } + { dg-final { scan-sarif-file "\"text\": \" if " } } + + { dg-final { scan-sarif-file "\"locations\": \\\[" } } + + We expect a logical location for the error (within fn "test"): + { dg-final { scan-sarif-file "\"logicalLocations\": \\\[" } } + { dg-final { scan-sarif-file "\"kind\": \"function\"" } } + { dg-final { scan-sarif-file "\"name\": \"test\"" } } + { dg-final { scan-sarif-file "\"fullyQualifiedName\": \"test\"" } } + { dg-final { scan-sarif-file "\"decoratedName\": \"" } } + + We expect the "note" to become a "relatedLocations" entry: + { dg-final { scan-sarif-file "\"relatedLocations\": \\\[" } } + { dg-final { scan-sarif-file "\"text\": \" return 4;" } } +*/ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-3.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-3.c new file mode 100644 index 0000000..3856782 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-3.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ +/* { dg-excess-errors "The error is sent to the SARIF file, rather than stderr" } */ + +struct s { int color; }; + +int test (struct s *ptr) +{ + return ptr->colour; +} + +/* + { dg-final { scan-sarif-file "\"level\": \"error\"" } } + + We expect a logical location for the error (within fn "test"): + { dg-final { scan-sarif-file "\"locations\": \\\[" } } + { dg-final { scan-sarif-file "\"logicalLocations\": \\\[" } } + { dg-final { scan-sarif-file "\"kind\": \"function\"" } } + { dg-final { scan-sarif-file "\"name\": \"test\"" } } + { dg-final { scan-sarif-file "\"fullyQualifiedName\": \"test\"" } } + { dg-final { scan-sarif-file "\"decoratedName\": \"" } } + + We expect a "fixes" array for the fix-it hint (SARIF v2.1.0 section 3.27.30): + { dg-final { scan-sarif-file "\"fixes\": \\\[" } } + { dg-final { scan-sarif-file "\"artifactChanges\": \\\[" } } + { dg-final { scan-sarif-file "\"replacements\": \\\[" } } + { dg-final { scan-sarif-file "\"insertedContent\": " } } + { dg-final { scan-sarif-file "\"text\": \"color\"" } } + { dg-final { scan-sarif-file "\"deletedRegion\": " } } +*/ diff --git a/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-4.c b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-4.c new file mode 100644 index 0000000..2d22f54 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diagnostic-format-sarif-file-4.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ +/* { dg-excess-errors "The error is sent to the SARIF file, rather than stderr" } */ + +int test (void) +{ + int 文字化け = *42; +} + +/* + { dg-final { scan-sarif-file "\"level\": \"error\"" } } + + We expect the region expressed in display columns: + { dg-final { scan-sarif-file "\"startLine\": 7" } } + { dg-final { scan-sarif-file "\"startColumn\": 18" } } + { dg-final { scan-sarif-file "\"endColumn\": 21" } } + + { dg-final { scan-sarif-file "\"text\": \" int \\u6587\\u5b57\\u5316\\u3051 = " } } +*/ diff --git a/gcc/testsuite/c-c++-common/gomp/scope-5.c b/gcc/testsuite/c-c++-common/gomp/scope-5.c new file mode 100644 index 0000000..6cd4a80 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/scope-5.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +void +foo () +{ + int f = 0; + #pragma omp scope firstprivate(f) /* { dg-error "firstprivate variable 'f' is private in outer context" } */ + f++; +} diff --git a/gcc/testsuite/c-c++-common/gomp/scope-6.c b/gcc/testsuite/c-c++-common/gomp/scope-6.c new file mode 100644 index 0000000..760dd71 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/scope-6.c @@ -0,0 +1,31 @@ +typedef enum omp_allocator_handle_t +#if __cplusplus >= 201103L +: __UINTPTR_TYPE__ +#endif +{ + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; + +int a = 0, b = 42, c = 0; + +void +foo (omp_allocator_handle_t h) +{ + #pragma omp scope private (a) private (b) reduction (+: c) allocate (allocator (h): a, b, c) + { + if (b != 42) + __builtin_abort (); + a = 36; + b = 15; + c++; + } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/auto56.C b/gcc/testsuite/g++.dg/cpp0x/auto56.C new file mode 100644 index 0000000..dd55ebf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/auto56.C @@ -0,0 +1,6 @@ +// Check that we don't prefer #2 because it's more specialized. +// { dg-do compile { target c++11 } } + +template <class T> T f(T); +template <class T> T* f(T*); +auto p = &f<int>; // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/cpp0x/auto57.C b/gcc/testsuite/g++.dg/cpp0x/auto57.C new file mode 100644 index 0000000..fedcfde --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/auto57.C @@ -0,0 +1,15 @@ +// PR c++/105734 +// { dg-do compile { target c++11 } } + +namespace N { + struct A { }; + A f(A); +} + +template <class T> +void bar() { + auto m = f(T()); + m.~A(); +} + +void foo() { bar<N::A>(); } diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype82.C b/gcc/testsuite/g++.dg/cpp0x/decltype82.C new file mode 100644 index 0000000..915e5e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/decltype82.C @@ -0,0 +1,10 @@ +// PR c++/105756 +// { dg-do compile { target c++11 } } + +template<int N> +void f() { + using ty1 = decltype((5 % N) == 0); + using ty2 = decltype((5 / N) == 0); +} + +template void f<0>(); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C new file mode 100644 index 0000000..8c6afe0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-this22.C @@ -0,0 +1,20 @@ +// PR c++/105637 +// { dg-do compile { target c++11 } } + +struct Base { + void foo(); // #1 + void foo() const = delete; // #2 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() { + [this] { Base::foo(); }(); // should select #2, not #1 + } + + void failsToCompile() const { + [this] { Base::foo(); }(); // { dg-error "deleted" } + } +}; + +template struct TopClass<Base>; diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn63.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn63.C new file mode 100644 index 0000000..ca3bc85 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn63.C @@ -0,0 +1,12 @@ +// PR c++/105779 +// { dg-do compile { target c++14 } } + +template<int> +struct struct1 +{ + static auto apply() { return 1; } +}; + +int method(int(*f)()); + +int t = method(struct1<1>::apply); diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn64.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn64.C new file mode 100644 index 0000000..13f3175 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn64.C @@ -0,0 +1,12 @@ +// PR c++/105761 +// { dg-do compile { target c++14 } } +// { dg-additional-options -Wno-non-template-friend } + +template <class T> +class X { + friend auto f(X); +}; + +struct Y : X<long> { + friend auto f(X) { return 0L; } +}; diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-aggr-base1.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-aggr-base1.C new file mode 100644 index 0000000..06acb4a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-aggr-base1.C @@ -0,0 +1,27 @@ +// PR c++/105795 +// { dg-do compile { target c++17 } } + +struct empty +{}; + +template <typename T> +struct tuple_holder +{ + [[no_unique_address]] T value; +}; + +struct tuple : tuple_holder<int>, tuple_holder<empty> +{}; + +constexpr auto make_tuple(int&& i, empty&& e) +{ + return tuple{i, e}; +} + +constexpr int foo() +{ + auto tuple = make_tuple(1, empty{}); + return static_cast<const tuple_holder<int>&>(tuple).value; +} + +static_assert (foo() == 1); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-decltype4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-decltype4.C new file mode 100644 index 0000000..6683d22 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-decltype4.C @@ -0,0 +1,16 @@ +// PR c++/105797 +// { dg-do compile { target c++20 } } + +template<class T> +concept C = requires { T(); }; + +template<class T> +void f(T v) requires C<decltype(v)>; // #1 + +template<class T, class U> +void f(T v) requires C<decltype(v)>; // #2 + +int main() { + f<int, int>(0); + f<int>(0); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun3.C new file mode 100644 index 0000000..beb30d0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun3.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++20 } } + +template<int I> +struct A { + enum E { e = I }; + static void f() requires (e != 0); +}; + +int main() { + A<1>::f(); + A<0>::f(); // { dg-error "no match" } +} diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-spec2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-spec2.C new file mode 100644 index 0000000..4de0735 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-spec2.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++20 } } + +template<class T, int> concept C = true; + +template<class T> struct A { + template<C<sizeof(T)> U> void f(); // #1 + template<C<0> U> void f(); // #2 + template<C<-1> U> void f(); // #3 +}; + +constexpr int n = sizeof(int); +template<> template<C<n> U> void A<int>::f() { } // matches #1 +template<> template<C<0> U> void A<int>::f() { } // matches #2 +template<> template<C<-2> U> void A<int>::f() { } // no match { dg-error "match" } +template<> template<class U> void A<int>::f() requires C<U, -1> { } // shouldn't match #3 +// { dg-error "match" "" { xfail *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C new file mode 100644 index 0000000..498e3c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-template-parm11.C @@ -0,0 +1,20 @@ +// PR c++/100374 +// { dg-do compile { target c++20 } } + +template<class T, class U> +concept C = requires { typename T; }; + +template<class T> +struct A { + template<C<typename T::value_type> U> + void f(); + + template<C<typename T::value_type> U> + struct B; +}; + +int main() { + A<int> a; + a.f<void>(); + using type = A<int>::B<void>; +} diff --git a/gcc/testsuite/g++.dg/ext/attrib65.C b/gcc/testsuite/g++.dg/ext/attrib65.C new file mode 100644 index 0000000..0af1387 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib65.C @@ -0,0 +1,7 @@ +// PR c++/102399 +// { dg-do compile { target c++11 } } +// Test mixing the GNU and standard forms of attributes. + +#define EXPORT __attribute__((visibility("default"))) + +struct [[nodiscard]] EXPORT Foo { Foo(); }; diff --git a/gcc/testsuite/g++.dg/ext/attrib66.C b/gcc/testsuite/g++.dg/ext/attrib66.C new file mode 100644 index 0000000..102ed70 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib66.C @@ -0,0 +1,27 @@ +// PR c++/69585 +// { dg-do compile { target c++11 } } + +struct __attribute__ ((aligned (2))) __attribute__ ((may_alias)) +S1 { }; + +struct __attribute__ ((aligned (2))) [[gnu::may_alias]] +S2 { }; + +struct alignas (2) __attribute__ ((may_alias)) +S3 { }; + +struct alignas (2) [[gnu::may_alias]] +S4 { }; + + +struct __attribute__ ((may_alias)) __attribute__ ((aligned (2))) +S1_2 { }; + +struct [[gnu::may_alias]] __attribute__ ((aligned (2))) +S2_2 { }; + +struct __attribute__ ((may_alias)) alignas (2) +S3_2 { }; + +struct [[gnu::may_alias]] alignas (2) +S4_2 { }; diff --git a/gcc/testsuite/g++.dg/ext/attrib67.C b/gcc/testsuite/g++.dg/ext/attrib67.C new file mode 100644 index 0000000..a510766 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attrib67.C @@ -0,0 +1,27 @@ +// PR c++/69585 +// { dg-do compile { target c++11 } } +// Test mixing the GNU and standard forms of attributes. + +__attribute__((deprecated)) [[maybe_unused]] void f1 (); +[[maybe_unused]] __attribute__((deprecated)) void f2 (); +[[maybe_unused]] __attribute__((deprecated)) [[nodiscard]] int f3 (); +__attribute__((unused)) [[nodiscard]] __attribute__((deprecated)) int f4 (); + +struct [[maybe_unused]] __attribute__((aligned)) S1 { double d; }; +struct __attribute__((aligned)) [[maybe_unused]] S2 { double d; }; + +enum E { + X [[maybe_unused]] __attribute__((unavailable)), + Y __attribute__((unavailable)) [[maybe_unused]], +}; + +void +g ([[maybe_unused]] __attribute__((unavailable)) int i1, + __attribute__((unavailable)) [[maybe_unused]] int i2) +{ + [[maybe_unused]] __attribute__((aligned)) int i3; + __attribute__((aligned)) [[maybe_unused]] int i4; + +[[maybe_unused]] +lab: __attribute__((cold)); +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index f64b078..3f366ae 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -593,9 +593,11 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s, [[omp::directive (cancellation point parallel)]]; } } - [[omp::directive (scope private (p) reduction(+:r) nowait)]] + [[omp::directive (scope private (p) firstprivate (f) reduction(+:r) nowait + allocate (omp_default_mem_alloc: r))]] ; - [[omp::directive (scope private (p) reduction(task, +:r))]] + [[omp::directive (scope private (p) firstprivate (f) reduction(task, +:r) + allocate (omp_default_mem_alloc: f))]] ; extern int t2; [[omp::directive (threadprivate (t2))]]; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index cc91fa2..cb80415 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -593,9 +593,11 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s, [[omp::directive (cancellation point, parallel)]]; } } - [[omp::directive (scope, private (p), reduction(+:r), nowait)]] + [[omp::directive (scope, private (p), firstprivate (f), reduction(+:r), nowait, + allocate(omp_default_mem_alloc: r))]] ; - [[using omp:directive (scope, private (p), reduction(task, +:r))]] + [[using omp:directive (scope, private (p), firstprivate (f), reduction(task, +:r), + allocate (omp_default_mem_alloc: f))]] ; extern int t2; [[omp::directive (threadprivate (t2))]]; diff --git a/gcc/testsuite/g++.dg/opt/pr105802.C b/gcc/testsuite/g++.dg/opt/pr105802.C new file mode 100644 index 0000000..2514245 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/pr105802.C @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-options "-O3" } + +enum E { E0, E1 }; + +void bar (); +void baz (); + +int c; + +void +foo (int i) +{ + E e = (E) i; + while (c) + switch (e) + { + case E0: + bar (); + case E1: + baz (); + } +} diff --git a/gcc/testsuite/g++.dg/template/new13.C b/gcc/testsuite/g++.dg/template/new13.C new file mode 100644 index 0000000..17a19e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/new13.C @@ -0,0 +1,11 @@ +// PR c++/105803 +// { dg-do compile } +// { dg-additional-options "-fchecking=2" } + +namespace std { +template <typename> class shared_ptr {}; +} +struct S {}; +template <int> void build_matrices() { + std::shared_ptr<S>(new S); +} diff --git a/gcc/testsuite/g++.dg/template/non-dependent23.C b/gcc/testsuite/g++.dg/template/non-dependent23.C new file mode 100644 index 0000000..885a641 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent23.C @@ -0,0 +1,25 @@ +// PR c++/105637 + +struct Base { + void foo(); // #1 + void foo() const; // #2 + void foo() volatile; // #3 + void foo() const volatile; // #4 +}; + +template<class T> +struct TopClass : T { + void failsToCompile() const { + Base::foo(); // should select #2, not #1 + } + + void failsToCompile() volatile { + Base::foo(); // should select #3, not #1 + } + + void failsToCompile() const volatile { + Base::foo(); // should select #4, not #1 + } +}; + +template struct TopClass<Base>; diff --git a/gcc/testsuite/g++.dg/template/non-dependent24.C b/gcc/testsuite/g++.dg/template/non-dependent24.C new file mode 100644 index 0000000..0ddc75c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent24.C @@ -0,0 +1,19 @@ +// PR c++/105758 + +struct A { + void foo(int); +}; + +template<class> +struct Z : A { + static Z *z; + void bar(); +}; + +template<class T> +Z<T> *Z<T>::z; + +template<class T> +void Z<T>::bar() { + z->foo(0); +} diff --git a/gcc/testsuite/g++.target/i386/pr105638.C b/gcc/testsuite/g++.target/i386/pr105638.C new file mode 100644 index 0000000..ff40a45 --- /dev/null +++ b/gcc/testsuite/g++.target/i386/pr105638.C @@ -0,0 +1,44 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-std=gnu++20 -O2 -march=skylake" } */ +/* { dg-final { scan-assembler-not "vpxor" } } */ + +#include <stdint.h> +#include <vector> +#include <tr1/array> + +class FastBoard { +public: + typedef std::pair<int, int> movescore_t; + typedef std::tr1::array<movescore_t, 24> scoredlist_t; + +protected: + std::vector<int> m_critical; + + int m_boardsize; +}; + +class FastState { +public: + FastBoard board; + + int movenum; +protected: + FastBoard::scoredlist_t scoredmoves; +}; + +class KoState : public FastState { +private: + std::vector<uint64_t> ko_hash_history; + std::vector<uint64_t> hash_history; +}; + +class GameState : public KoState { +public: + void foo (); +private: + std::vector<KoState> game_history; +}; + +void GameState::foo() { + game_history.resize(movenum); +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr105777.c b/gcc/testsuite/gcc.c-torture/execute/pr105777.c new file mode 100644 index 0000000..4a21750 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr105777.c @@ -0,0 +1,73 @@ +/* PR middle-end/105777 */ + +#include "../../gcc.dg/tree-ssa/pr105777.c" + +int +main () +{ + if (foo (0) != 0 + || foo (__INT_MAX__ / 35) != 0 + || foo (__INT_MAX__ / 35 + 1) != 1 + || foo (__INT_MAX__) != 1 + || foo ((-__INT_MAX__ - 1) / 35) != 0 + || foo ((-__INT_MAX__ - 1) / 35 - 1) != 1 + || foo (-__INT_MAX__ - 1) != 1) + __builtin_abort (); + if (bar (0) != 0 + || bar (__LONG_MAX__ / 35) != 0 + || bar (__LONG_MAX__ / 35 + 1) != 1 + || bar (__LONG_MAX__) != 1 + || bar ((-__LONG_MAX__ - 1) / 35) != 0 + || bar ((-__LONG_MAX__ - 1) / 35 - 1) != 1 + || bar (-__LONG_MAX__ - 1) != 1) + __builtin_abort (); + if (baz (0) != 0 + || baz (__INT_MAX__ / 42) != 0 + || baz (__INT_MAX__ / 42 + 1) != 1 + || baz (__INT_MAX__) != 1 + || baz ((-__INT_MAX__ - 1) / 42) != 0 + || baz ((-__INT_MAX__ - 1) / 42 - 1) != 1 + || baz (-__INT_MAX__ - 1) != 1) + __builtin_abort (); + if (qux (0) != 0 + || qux (__LONG_MAX__ / 42) != 0 + || qux (__LONG_MAX__ / 42 + 1) != 1 + || qux (__LONG_MAX__) != 1 + || qux ((-__LONG_MAX__ - 1) / 42) != 0 + || qux ((-__LONG_MAX__ - 1) / 42 - 1) != 1 + || qux (-__LONG_MAX__ - 1) != 1) + __builtin_abort (); + if (corge (0) != 0 + || corge (__INT_MAX__ / -39) != 0 + || corge (__INT_MAX__ / -39 - 1) != 1 + || corge (__INT_MAX__) != 1 + || corge ((-__INT_MAX__ - 1) / -39) != 0 + || corge ((-__INT_MAX__ - 1) / -39 + 1) != 1 + || corge (-__INT_MAX__ - 1) != 1) + __builtin_abort (); + if (garply (0) != 0 + || garply (__LONG_MAX__ / -39) != 0 + || garply (__LONG_MAX__ / -39 - 1) != 1 + || garply (__LONG_MAX__) != 1 + || garply ((-__LONG_MAX__ - 1) / -39) != 0 + || garply ((-__LONG_MAX__ - 1) / -39 + 1) != 1 + || garply (-__LONG_MAX__ - 1) != 1) + __builtin_abort (); + if (grault (0) != 0 + || grault (__INT_MAX__ / -46) != 0 + || grault (__INT_MAX__ / -46 - 1) != 1 + || grault (__INT_MAX__) != 1 + || grault ((-__INT_MAX__ - 1) / -46) != 0 + || grault ((-__INT_MAX__ - 1) / -46 + 1) != 1 + || grault (-__INT_MAX__ - 1) != 1) + __builtin_abort (); + if (waldo (0) != 0 + || waldo (__LONG_MAX__ / -46) != 0 + || waldo (__LONG_MAX__ / -46 - 1) != 1 + || waldo (__LONG_MAX__) != 1 + || waldo ((-__LONG_MAX__ - 1) / -46) != 0 + || waldo ((-__LONG_MAX__ - 1) / -46 + 1) != 1 + || waldo (-__LONG_MAX__ - 1) != 1) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/pr30314.c b/gcc/testsuite/gcc.c-torture/execute/pr30314.c new file mode 100644 index 0000000..e1d71e2 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr30314.c @@ -0,0 +1,29 @@ +/* PR middle-end/30314 */ + +#include "../../gcc.dg/tree-ssa/pr30314.c" + +int +main () +{ + if (foo (0) != 0 + || foo (~0U / 35) != 0 + || foo (~0U / 35 + 1) != 1 + || foo (~0U) != 1) + __builtin_abort (); + if (bar (0) != 0 + || bar (~0UL / 35) != 0 + || bar (~0UL / 35 + 1) != 1 + || bar (~0UL) != 1) + __builtin_abort (); + if (baz (0) != 0 + || baz (~0U / 42) != 0 + || baz (~0U / 42 + 1) != 1 + || baz (~0U) != 1) + __builtin_abort (); + if (qux (0) != 0 + || qux (~0UL / 42) != 0 + || qux (~0UL / 42 + 1) != 1 + || qux (~0UL) != 1) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/analyzer/file-meaning-1.c b/gcc/testsuite/gcc.dg/analyzer/file-meaning-1.c new file mode 100644 index 0000000..66b72a7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/file-meaning-1.c @@ -0,0 +1,15 @@ +/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */ + +typedef struct FILE FILE; +FILE* fopen (const char*, const char*); +int fclose (FILE*); + +void test_1 (const char *path) +{ + FILE *f = fopen (path, "r"); /* { dg-message "meaning: \\{verb: 'acquire', noun: 'resource'\\}" } */ + if (!f) + return; + + fclose (f); /* { dg-message "meaning: \\{verb: 'release', noun: 'resource'\\}" } */ + fclose (f); /* { dg-warning "double 'fclose' of FILE 'f'" "warning" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-meaning-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-meaning-1.c new file mode 100644 index 0000000..4964e25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-meaning-1.c @@ -0,0 +1,10 @@ +/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */ + +#include <stdlib.h> + +void test_1 (void) +{ + void *ptr = malloc (1024); /* { dg-message "meaning: \\{verb: 'acquire', noun: 'memory'\\}" } */ + free (ptr); /* { dg-message "meaning: \\{verb: 'release', noun: 'memory'\\}" } */ + free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ +} diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c new file mode 100644 index 0000000..3d141b5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-sarif-1.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdiagnostics-format=sarif-file" } */ + +#include <stdlib.h> + +void test_1 (void) +{ + void *ptr = malloc (1024); + free (ptr); + free (ptr); +} + +/* Verify SARIF output. + + The threadFlowLocation objects should have "kinds" properties + reflecting the meanings of the events: + { dg-final { scan-sarif-file "\"kinds\": \\\[\"acquire\", \"memory\"\\\]" } } + { dg-final { scan-sarif-file "\"kinds\": \\\[\"release\", \"memory\"\\\]" } } + { dg-final { scan-sarif-file "\"kinds\": \\\[\"danger\"\\\]" } } +*/ diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c index b5ae128..2a8bf11 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c @@ -109,6 +109,21 @@ public: return label_text (); } + diagnostic_event::meaning + get_meaning_for_state_change (const evdesc::state_change &change) + const final override + { + if (change.is_global_p ()) + { + if (change.m_new_state == m_sm.m_released_gil) + return diagnostic_event::meaning (diagnostic_event::VERB_release, + diagnostic_event::NOUN_lock); + else if (change.m_new_state == m_sm.get_start_state ()) + return diagnostic_event::meaning (diagnostic_event::VERB_acquire, + diagnostic_event::NOUN_lock); + } + return diagnostic_event::meaning (); + } protected: gil_diagnostic (const gil_state_machine &sm) : m_sm (sm) { diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c new file mode 100644 index 0000000..bd09391 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-5.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-format=sarif-file" } */ +/* { dg-excess-errors "The error is sent to the SARIF file, rather than stderr" } */ + +#include <stddef.h> +#include <stdlib.h> + +/* Minimal reimplementation of cpython API. */ +typedef struct PyObject {} PyObject; +extern int PyArg_ParseTuple (PyObject *args, const char *fmt, ...); +extern PyObject *PyList_New (int); +extern PyObject *PyLong_FromLong(long); +extern void PyList_Append(PyObject *list, PyObject *item); + +PyObject * +make_a_list_of_random_ints_badly(PyObject *self, + PyObject *args) +{ + PyObject *list, *item; + long count, i; + + if (!PyArg_ParseTuple(args, "i", &count)) { + return NULL; + } + + list = PyList_New(0); + + for (i = 0; i < count; i++) { + item = PyLong_FromLong(random()); + PyList_Append(list, item); + } + + return list; +} + +/* + { dg-final { scan-sarif-file "\"tool\": " } } + + We expect info about the plugin: + { dg-final { scan-sarif-file "\"extensions\": \\\[" } } + { dg-final { scan-sarif-file "\"name\": \"diagnostic_plugin_test_paths\"" } } + { dg-final { scan-sarif-file "\"fullName\": \"" } } + + { dg-final { scan-sarif-file "\"results\": \\\[" } } + { dg-final { scan-sarif-file "\"level\": \"error\"" } } + { dg-final { scan-sarif-file "\"text\": \"passing NULL as argument 1 to 'PyList_Append' which requires a non-NULL parameter\"" } } + + We expect a path for the diagnostic: + { dg-final { scan-sarif-file "\"codeFlows\": \\\[" } } + { dg-final { scan-sarif-file "\"threadFlows\": \\\[" } } + { dg-final { scan-sarif-file "\"locations\": \\\[" } } + { dg-final { scan-sarif-file "\"text\": \"when 'PyList_New' fails, returning NULL\"" } } + { dg-final { scan-sarif-file "\"text\": \"when 'i < count'\"" } } + { dg-final { scan-sarif-file "\"text\": \"when calling 'PyList_Append', passing NULL from \\(1\\) as argument 1\"" } } + +*/ diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 2ade945..63b117d 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -102,6 +102,7 @@ set plugin_test_list [list \ diagnostic-test-paths-2.c \ diagnostic-test-paths-3.c \ diagnostic-test-paths-4.c \ + diagnostic-test-paths-5.c \ diagnostic-path-format-plain.c \ diagnostic-path-format-none.c \ diagnostic-path-format-separate-events.c \ diff --git a/gcc/testsuite/gcc.dg/pr105763.c b/gcc/testsuite/gcc.dg/pr105763.c new file mode 100644 index 0000000..4c76b17 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr105763.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O3" } */ + +int rl2_decode_png_bit_depth; +int *rl2_decode_png_p_data; +void png_destroy_read_struct (); +int __attribute__((returns_twice)) _setjmp (); +void rl2_decode_png_row_pointers() +{ + unsigned sample_type = 0; + _setjmp(); + switch (rl2_decode_png_bit_depth) + case 6: + sample_type = 7; + png_destroy_read_struct(); + for (;;) + switch (sample_type) + case 3: + case 5: + *rl2_decode_png_p_data; +} diff --git a/gcc/testsuite/gcc.dg/pr105770.c b/gcc/testsuite/gcc.dg/pr105770.c new file mode 100644 index 0000000..c1e0140 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr105770.c @@ -0,0 +1,19 @@ +/* PR tree-optimization/105770 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -funswitch-loops -fno-tree-forwprop" } */ + +char a; + +void +foo (void) +{ + while (a) + switch (a) + { + case ' ': + case '\t': + return; + } + + __builtin_unreachable (); +} diff --git a/gcc/testsuite/gcc.dg/pr105825.c b/gcc/testsuite/gcc.dg/pr105825.c new file mode 100644 index 0000000..d1eb829 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr105825.c @@ -0,0 +1,13 @@ +/* PR target/105825 */ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ +/* { dg-additional-options "-mavx" { target avx } } */ + +__int128 j; +int i; + +void +foo (void) +{ + j <<= __builtin_parityll (i); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr105665.c b/gcc/testsuite/gcc.dg/torture/pr105665.c new file mode 100644 index 0000000..34cfc65 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr105665.c @@ -0,0 +1,20 @@ +/* { dg-do run } */ + +int a, b, c[1], d[2], *e = c; +int main() { + int f = 0; + for (; b < 2; b++) { + int g; + if (f) + g++, b = 40; + a = d[b * b]; + for (f = 0; f < 3; f++) { + if (e) + break; + g--; + if (a) + a = g; + } + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr105786.c b/gcc/testsuite/gcc.dg/torture/pr105786.c new file mode 100644 index 0000000..64aacf7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr105786.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ + +void sink(const char*); +static const char *a; +int main() +{ + const char *b = a; + for (int i = 0; i < 2; ++i) + while (*b++) + ; + sink(b); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr105777.c b/gcc/testsuite/gcc.dg/tree-ssa/pr105777.c new file mode 100644 index 0000000..418708b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr105777.c @@ -0,0 +1,68 @@ +/* PR middle-end/105777 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-not "\.MUL_OVERFLOW " "optimized" } } */ +/* { dg-final { scan-tree-dump " \\+ 61356675;" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " > 122713350" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " \\+ 263524915338707880" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " > 527049830677415760" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " \\+ 51130563" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " > 102261126" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " \\+ 219604096115589900" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " > 439208192231179800" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " \\+ 55063683;" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " > 110127366" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " \\+ 236496718893712200" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " > 472993437787424400" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " \\+ 46684427" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " > 93368854" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " \\+ 200508087757712517" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " > 401016175515425034" "optimized" { target lp64 } } } */ + +__attribute__((noipa)) int +foo (int x) +{ + return __builtin_mul_overflow_p (x, 35, 0); +} + +__attribute__((noipa)) int +bar (long int x) +{ + return __builtin_mul_overflow_p (x, 35L, 0L); +} + +__attribute__((noipa)) int +baz (int x) +{ + return __builtin_mul_overflow_p (42, x, 0); +} + +__attribute__((noipa)) int +qux (long int x) +{ + return __builtin_mul_overflow_p (42, x, 0L); +} + +__attribute__((noipa)) int +corge (int x) +{ + return __builtin_mul_overflow_p (x, -39, 0); +} + +__attribute__((noipa)) int +garply (long int x) +{ + return __builtin_mul_overflow_p (x, -39L, 0L); +} + +__attribute__((noipa)) int +grault (int x) +{ + return __builtin_mul_overflow_p (-46, x, 0); +} + +__attribute__((noipa)) int +waldo (long int x) +{ + return __builtin_mul_overflow_p (-46, x, 0L); +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr30314.c b/gcc/testsuite/gcc.dg/tree-ssa/pr30314.c new file mode 100644 index 0000000..10b0b85 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr30314.c @@ -0,0 +1,32 @@ +/* PR middle-end/30314 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-final { scan-tree-dump-not "\.MUL_OVERFLOW " "optimized" } } */ +/* { dg-final { scan-tree-dump " > 122713351" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " > 527049830677415760" "optimized" { target lp64 } } } */ +/* { dg-final { scan-tree-dump " > 102261126" "optimized" { target int32 } } } */ +/* { dg-final { scan-tree-dump " > 439208192231179800" "optimized" { target lp64 } } } */ + +__attribute__((noipa)) int +foo (unsigned int x) +{ + return __builtin_mul_overflow_p (x, 35U, 0U); +} + +__attribute__((noipa)) int +bar (unsigned long int x) +{ + return __builtin_mul_overflow_p (x, 35UL, 0UL); +} + +__attribute__((noipa)) int +baz (unsigned int x) +{ + return __builtin_mul_overflow_p (42, x, 0U); +} + +__attribute__((noipa)) int +qux (unsigned long int x) +{ + return __builtin_mul_overflow_p (42, x, 0UL); +} diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr101668.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr101668.c new file mode 100644 index 0000000..eb44ad7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr101668.c @@ -0,0 +1,59 @@ +/* { dg-do run } */ +/* { dg-additional-options "-w -Wno-psabi" } */ + +#include "tree-vect.h" + +typedef int v4si __attribute__((vector_size(16))); +typedef int v8si __attribute__((vector_size(32))); + +void __attribute__((noipa)) test_lo (v4si *dst, v8si src) +{ + (*dst)[0] = src[0]; + (*dst)[1] = src[1]; + (*dst)[2] = src[2]; + (*dst)[3] = src[3]; +} + +void __attribute__((noipa)) test_hi (v4si *dst, v8si src) +{ + (*dst)[0] = src[4]; + (*dst)[1] = src[5]; + (*dst)[2] = src[6]; + (*dst)[3] = src[7]; +} + +void __attribute__((noipa)) test_even (v4si *dst, v8si src) +{ + (*dst)[0] = src[0]; + (*dst)[1] = src[2]; + (*dst)[2] = src[4]; + (*dst)[3] = src[6]; +} + +void __attribute__((noipa)) test_odd (v4si *dst, v8si src) +{ + (*dst)[0] = src[1]; + (*dst)[1] = src[3]; + (*dst)[2] = src[5]; + (*dst)[3] = src[7]; +} + +int main() +{ + check_vect (); + v8si v = (v8si) { 0, 1, 2, 3, 4, 5, 6, 7 }; + v4si dst; + test_lo (&dst, v); + if (dst[0] != 0 || dst[1] != 1 || dst[2] != 2 || dst[3] != 3) + abort (); + test_hi (&dst, v); + if (dst[0] != 4 || dst[1] != 5 || dst[2] != 6 || dst[3] != 7) + abort (); + test_even (&dst, v); + if (dst[0] != 0 || dst[1] != 2 || dst[2] != 4 || dst[3] != 6) + abort (); + test_odd (&dst, v); + if (dst[0] != 1 || dst[1] != 3 || dst[2] != 5 || dst[3] != 7) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/pr101617.c b/gcc/testsuite/gcc.target/i386/pr101617.c new file mode 100644 index 0000000..503bf11 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101617.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +int f(int i) +{ + int t = i ? -1 : 0; + return t | 1; +} + +int f1(int i) +{ + int t = i ? -1 : 1; + return t; +} + +/* { dg-final { scan-assembler-times "negl" 2 } } */ +/* { dg-final { scan-assembler-times "sbbl" 2 } } */ +/* { dg-final { scan-assembler-times "orl" 2 } } */ +/* { dg-final { scan-assembler-not "cmpl" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/pr101668.c b/gcc/testsuite/gcc.target/i386/pr101668.c new file mode 100644 index 0000000..07719ec --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101668.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=skylake-avx512 -mprefer-vector-width=512" } */ + +typedef int v16si __attribute__((vector_size (64))); +typedef long long v8di __attribute__((vector_size (64))); + +void +bar_s32_s64 (v8di * dst, v16si src) +{ + long long tem[8]; + tem[0] = src[0]; + tem[1] = src[1]; + tem[2] = src[2]; + tem[3] = src[3]; + tem[4] = src[4]; + tem[5] = src[5]; + tem[6] = src[6]; + tem[7] = src[7]; + dst[0] = *(v8di *) tem; +} + +/* We want to generate + vpmovsxdq %ymm0, %zmm0 + vmovdqa64 %zmm0, (%rdi) + ret + */ +/* { dg-final { scan-assembler "vpmovsxdq" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr105624.c b/gcc/testsuite/gcc.target/i386/pr105624.c index 8ca6c43..aa5895b 100644 --- a/gcc/testsuite/gcc.target/i386/pr105624.c +++ b/gcc/testsuite/gcc.target/i386/pr105624.c @@ -1,5 +1,5 @@ /* PR target/105624 */ -/* { dg-do compile } */ +/* { dg-do compile { target { ! ia32 } } } */ /* { dg-options "-O1 -march=k8" } */ union U { diff --git a/gcc/testsuite/gcc.target/i386/pr105778.c b/gcc/testsuite/gcc.target/i386/pr105778.c new file mode 100644 index 0000000..bf04904 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr105778.c @@ -0,0 +1,45 @@ +/* PR target/105778 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-not "\tand\[^\n\r]*\(31\|63\|127\|255\)" } } */ + +unsigned int f1 (unsigned int x, unsigned long y) { y &= 31; return x << y; } +unsigned int f2 (unsigned int x, unsigned long y) { return x << (y & 31); } +unsigned int f3 (unsigned int x, unsigned long y) { y &= 31; return x >> y; } +unsigned int f4 (unsigned int x, unsigned long y) { return x >> (y & 31); } +int f5 (int x, unsigned long y) { y &= 31; return x >> y; } +int f6 (int x, unsigned long y) { return x >> (y & 31); } +unsigned long long f7 (unsigned long long x, unsigned long y) { y &= 63; return x << y; } +unsigned long long f8 (unsigned long long x, unsigned long y) { return x << (y & 63); } +unsigned long long f9 (unsigned long long x, unsigned long y) { y &= 63; return x >> y; } +unsigned long long f10 (unsigned long long x, unsigned long y) { return x >> (y & 63); } +long long f11 (long long x, unsigned long y) { y &= 63; return x >> y; } +long long f12 (long long x, unsigned long y) { return x >> (y & 63); } +#ifdef __SIZEOF_INT128__ +unsigned __int128 f13 (unsigned __int128 x, unsigned long y) { y &= 127; return x << y; } +unsigned __int128 f14 (unsigned __int128 x, unsigned long y) { return x << (y & 127); } +unsigned __int128 f15 (unsigned __int128 x, unsigned long y) { y &= 127; return x >> y; } +unsigned __int128 f16 (unsigned __int128 x, unsigned long y) { return x >> (y & 127); } +__int128 f17 (__int128 x, unsigned long y) { y &= 127; return x >> y; } +__int128 f18 (__int128 x, unsigned long y) { return x >> (y & 127); } +#endif +unsigned int f19 (unsigned int x, unsigned long y) { y &= 63; return x << y; } +unsigned int f20 (unsigned int x, unsigned long y) { return x << (y & 63); } +unsigned int f21 (unsigned int x, unsigned long y) { y &= 63; return x >> y; } +unsigned int f22 (unsigned int x, unsigned long y) { return x >> (y & 63); } +int f23 (int x, unsigned long y) { y &= 63; return x >> y; } +int f24 (int x, unsigned long y) { return x >> (y & 63); } +unsigned long long f25 (unsigned long long x, unsigned long y) { y &= 127; return x << y; } +unsigned long long f26 (unsigned long long x, unsigned long y) { return x << (y & 127); } +unsigned long long f27 (unsigned long long x, unsigned long y) { y &= 127; return x >> y; } +unsigned long long f28 (unsigned long long x, unsigned long y) { return x >> (y & 127); } +long long f29 (long long x, unsigned long y) { y &= 127; return x >> y; } +long long f30 (long long x, unsigned long y) { return x >> (y & 127); } +#ifdef __SIZEOF_INT128__ +unsigned __int128 f31 (unsigned __int128 x, unsigned long y) { y &= 255; return x << y; } +unsigned __int128 f32 (unsigned __int128 x, unsigned long y) { return x << (y & 255); } +unsigned __int128 f33 (unsigned __int128 x, unsigned long y) { y &= 255; return x >> y; } +unsigned __int128 f34 (unsigned __int128 x, unsigned long y) { return x >> (y & 255); } +__int128 f35 (__int128 x, unsigned long y) { y &= 255; return x >> y; } +__int128 f36 (__int128 x, unsigned long y) { return x >> (y & 255); } +#endif diff --git a/gcc/testsuite/gcc.target/i386/pr105791.c b/gcc/testsuite/gcc.target/i386/pr105791.c new file mode 100644 index 0000000..55e278b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr105791.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2 -mxop" } */ +typedef __int128 __attribute__((__vector_size__ (sizeof (__int128)))) U; +typedef int __attribute__((__vector_size__ (sizeof (int)))) V; + +U u; +V v; + +U +foo (void) +{ + return (0 != __builtin_convertvector (v, U)) <= (0 != u); +} diff --git a/gcc/testsuite/gcc.target/i386/pr70321.c b/gcc/testsuite/gcc.target/i386/pr70321.c new file mode 100644 index 0000000..eaba728 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr70321.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2" } */ + +void foo (long long ixi) +{ + if (ixi != 14348907) + __builtin_abort (); +} + +/* { dg-final { scan-assembler-times "mov" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m32-1.c b/gcc/testsuite/gcc.target/i386/pr95126-m32-1.c new file mode 100644 index 0000000..1d6acd6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m32-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a,b; signed char c; }; + +void call_func(void) +{ + extern int func(struct small X); + static struct small const s = { 1,2,0 }; + func(s); +} + +/* { dg-final { scan-assembler "movl\[ \\t]*\\\$" } } */ +/* { dg-final { scan-assembler "movb\[ \\t]*\\\$0, " } } */ +/* { dg-final { scan-assembler-not "movzwl" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m32-2.c b/gcc/testsuite/gcc.target/i386/pr95126-m32-2.c new file mode 100644 index 0000000..b46be9d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m32-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a,b; signed char c; }; +static const struct small s = { 1,2,0 }; +extern int func(struct small X); + +void call_func(void) +{ + func(s); +} + +/* { dg-final { scan-assembler "movl\[ \\t]*\\\$" } } */ +/* { dg-final { scan-assembler "movb\[ \\t]*\\\$0, " } } */ +/* { dg-final { scan-assembler-not "movzwl" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m32-3.c b/gcc/testsuite/gcc.target/i386/pr95126-m32-3.c new file mode 100644 index 0000000..cc2fe94 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m32-3.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target { ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a; }; + +void call_func(void) +{ + extern int func(struct small X); + static struct small const s = { 2 }; + func(s); +} + +/* { dg-final { scan-assembler "pushl\[ \\t]*\\\$2" } } */ +/* { dg-final { scan-assembler-not "movzwl" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m32-4.c b/gcc/testsuite/gcc.target/i386/pr95126-m32-4.c new file mode 100644 index 0000000..e829335 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m32-4.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target { ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a,b; }; + +void call_func(void) +{ + extern int func(struct small X); + static struct small const s = { 1,2 }; + func(s); +} + +/* { dg-final { scan-assembler "pushl\[ \\t]*\\\$131073" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m64-1.c b/gcc/testsuite/gcc.target/i386/pr95126-m64-1.c new file mode 100644 index 0000000..d5c6dded --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m64-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a,b; signed char c; }; + +void call_func(void) +{ + extern int func(struct small X); + static struct small const s = { 1,2,0 }; + func(s); +} + +/* { dg-final { scan-assembler "movl\[ \\t]*\\\$131073, " } } */ +/* { dg-final { scan-assembler-not "movzwl" } } */ +/* { dg-final { scan-assembler-not "salq" } } */ +/* { dg-final { scan-assembler-not "orq" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m64-2.c b/gcc/testsuite/gcc.target/i386/pr95126-m64-2.c new file mode 100644 index 0000000..0230ffc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m64-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a,b; signed char c; }; +static const struct small s = { 1,2,0 }; +extern int func(struct small X); + +void call_func(void) +{ + func(s); +} + +/* { dg-final { scan-assembler "movl\[ \\t]*\\\$131073, " } } */ +/* { dg-final { scan-assembler-not "movzwl" } } */ +/* { dg-final { scan-assembler-not "salq" } } */ +/* { dg-final { scan-assembler-not "orq" } } */ + diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m64-3.c b/gcc/testsuite/gcc.target/i386/pr95126-m64-3.c new file mode 100644 index 0000000..25afe3a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m64-3.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a; }; + +void call_func(void) +{ + extern int func(struct small X); + static struct small const s = { 2 }; + func(s); +} + +/* { dg-final { scan-assembler "movl\[ \\t]*\\\$2, " } } */ +/* { dg-final { scan-assembler-not "movzwl" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr95126-m64-4.c b/gcc/testsuite/gcc.target/i386/pr95126-m64-4.c new file mode 100644 index 0000000..71c7908 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95126-m64-4.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +struct small{ short a,b; }; + +void call_func(void) +{ + extern int func(struct small X); + static struct small const s = { 1,2 }; + func(s); +} + +/* { dg-final { scan-assembler "movl\[ \\t]*\\\$131073, " } } */ diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-stv-1.c b/gcc/testsuite/gcc.target/i386/sse4_1-stv-1.c new file mode 100644 index 0000000..12db618 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse4_1-stv-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -msse4.1 -mstv -mno-stackrealign" } */ +long long a[1024]; +long long b[1024]; + +int foo() +{ + for (int i=0; i<1024; i++) + { + long long t = (a[i]<<8) | (b[i]<<24); + if (t == 0) + return 1; + } + return 0; +} + +/* { dg-final { scan-assembler "ptest" } } */ +/* { dg-final { scan-assembler-not "pxor" } } */ diff --git a/gcc/testsuite/gfortran.dg/allocate_alloc_opt_15.f90 b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_15.f90 new file mode 100644 index 0000000..3c26e81 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/allocate_alloc_opt_15.f90 @@ -0,0 +1,49 @@ +! { dg-do run } +! { dg-additional-options "-fdump-tree-original" } +! PR fortran/91300 - runtime error message with allocate and errmsg= +! Contributed by zed.three + +program bigarray_prog + use, intrinsic :: iso_c_binding, only: C_INTPTR_T + implicit none + real(4), dimension(:), allocatable :: array, bigarray + integer :: stat1, stat2 + character(len=100) :: errmsg1, errmsg2 + character(*), parameter :: no_error = "no error" + integer(8), parameter :: n1 = huge (1_4) / 3 ! request more than 2GB + integer(8), parameter :: n2 = huge (1_C_INTPTR_T) / 4 ! "safe" for 64bit + integer(8), parameter :: bignumber = max (n1, n2) + + stat1 = -1 + stat2 = -1 + errmsg1 = no_error + errmsg2 = no_error + allocate (array(1), stat=stat1, errmsg=errmsg1) + if (stat1 /= 0 ) stop 1 + if (errmsg1 /= no_error) stop 1 + + ! Obtain stat, errmsg for attempt to allocate an allocated object + allocate (array(1), stat=stat1, errmsg=errmsg1) + if (stat1 == 0 ) stop 2 + if (errmsg1 == no_error) stop 2 + + ! Try to allocate very large object + allocate (bigarray(bignumber), stat=stat2, errmsg=errmsg2) + if (stat2 /= 0) then + print *, "stat1 =", stat1 + print *, "errmsg: ", trim (errmsg1) + print *, "stat2 =", stat2 + print *, "errmsg: ", trim (errmsg2) + ! Ensure different results for stat, errmsg variables (all compilers) + if (stat2 == stat1 ) stop 3 + if (errmsg2 == no_error .or. errmsg2 == errmsg1) stop 4 + + ! Finally verify gfortran-specific error messages + if (errmsg1 /= "Attempt to allocate an allocated object") stop 5 + if (errmsg2 /= "Insufficient virtual memory" ) stop 6 + end if + +end program bigarray_prog + +! { dg-final { scan-tree-dump-times "Attempt to allocate an allocated object" 4 "original" } } +! { dg-final { scan-tree-dump-times "Insufficient virtual memory" 4 "original" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/scope-5.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-5.f90 new file mode 100644 index 0000000..baddae5 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/scope-5.f90 @@ -0,0 +1,9 @@ +! { dg-do compile } + +subroutine foo () + integer f + f = 0; + !$omp scope firstprivate(f) ! { dg-error "firstprivate variable 'f' is private in outer context" } + f = f + 1 + !$omp end scope +end diff --git a/gcc/testsuite/gfortran.dg/gomp/scope-6.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-6.f90 new file mode 100644 index 0000000..4c4f5e0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/scope-6.f90 @@ -0,0 +1,23 @@ +! { dg-additional-options "-fdump-tree-original" } + +module m + use iso_c_binding + !use omp_lib, only: omp_allocator_handle_kind + implicit none + integer, parameter :: omp_allocator_handle_kind = c_intptr_t + integer :: a = 0, b = 42, c = 0 + +contains + subroutine foo (h) + integer(omp_allocator_handle_kind), value :: h + !$omp scope private (a) firstprivate (b) reduction (+: c) allocate ( h : a , b , c) + if (b /= 42) & + error stop + a = 36 + b = 15 + c = c + 1 + !$omp end scope + end +end + +! { dg-final { scan-tree-dump "omp scope private\\(a\\) firstprivate\\(b\\) reduction\\(\\+:c\\) allocate\\(allocator\\(D\\.\[0-9\]+\\):a\\) allocate\\(allocator\\(D\\.\[0-9\]+\\):b\\) allocate\\(allocator\\(D\\.\[0-9\]+\\):c\\)" "original" } } diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp index 8c28997..f58b9e6 100644 --- a/gcc/testsuite/lib/gcc-dg.exp +++ b/gcc/testsuite/lib/gcc-dg.exp @@ -25,6 +25,7 @@ load_lib scanltranstree.exp load_lib scanipa.exp load_lib scanwpaipa.exp load_lib scanlang.exp +load_lib scansarif.exp load_lib timeout.exp load_lib timeout-dg.exp load_lib prune.exp diff --git a/gcc/testsuite/lib/scansarif.exp b/gcc/testsuite/lib/scansarif.exp new file mode 100644 index 0000000..8b7e89c --- /dev/null +++ b/gcc/testsuite/lib/scansarif.exp @@ -0,0 +1,42 @@ +# Copyright (C) 2000-2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Various utilities for scanning SARIF output, used by gcc-dg.exp and +# g++-dg.exp. +# +# This is largely borrowed from scanasm.exp. + +# Look for a pattern in the .sarif file produced by the compiler. See +# dg-scan for details. + +proc scan-sarif-file { args } { + set testcase [testname-for-summary] + # The name might include a list of options; extract the file name. + set filename [lindex $testcase 0] + set output_file "[file tail $filename].sarif" + dg-scan "scan-sarif-file" 1 $testcase $output_file $args +} + +# Check that a pattern is not present in the .sarif file. See dg-scan +# for details. + +proc scan-sarif-file-not { args } { + set testcase [testname-for-summary] + # The name might include a list of options; extract the file name. + set filename [lindex $testcase 0] + set output_file "[file tail $filename].sarif" + dg-scan "scan-sarif-file-not" 0 $testcase $output_file $args +} diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc index 397792c..ae05fe7 100644 --- a/gcc/tree-data-ref.cc +++ b/gcc/tree-data-ref.cc @@ -593,8 +593,8 @@ compute_distributive_range (tree type, value_range &op0_range, gcc_assert (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type)); if (result_range) { - range_operator *op = range_op_handler (code, type); - op->fold_range (*result_range, type, op0_range, op1_range); + range_op_handler op (code, type); + op.fold_range (*result_range, type, op0_range, op1_range); } /* The distributive property guarantees that if TYPE is no narrower @@ -639,10 +639,10 @@ compute_distributive_range (tree type, value_range &op0_range, range_cast (op0_range, ssizetype); range_cast (op1_range, ssizetype); value_range wide_range; - range_operator *op = range_op_handler (code, ssizetype); + range_op_handler op (code, ssizetype); bool saved_flag_wrapv = flag_wrapv; flag_wrapv = 1; - op->fold_range (wide_range, ssizetype, op0_range, op1_range); + op.fold_range (wide_range, ssizetype, op0_range, op1_range); flag_wrapv = saved_flag_wrapv; if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range)) return false; diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc new file mode 100644 index 0000000..f8ff271 --- /dev/null +++ b/gcc/tree-diagnostic-client-data-hooks.cc @@ -0,0 +1,150 @@ +/* Implementation of diagnostic_client_data_hooks for the compilers + (e.g. with knowledge of "tree" and lang_hooks). + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "version.h" +#include "tree.h" +#include "diagnostic.h" +#include "tree-logical-location.h" +#include "diagnostic-client-data-hooks.h" +#include "langhooks.h" +#include "plugin.h" + +/* Concrete class for supplying a diagnostic_context with information + about a specific plugin within the client, when the client is the + compiler (i.e. a GCC plugin). */ + +class compiler_diagnostic_client_plugin_info + : public diagnostic_client_plugin_info +{ +public: + compiler_diagnostic_client_plugin_info (const plugin_name_args *args) + : m_args (args) + { + } + + const char *get_short_name () const final override + { + return m_args->base_name; + } + + const char *get_full_name () const final override + { + return m_args->full_name; + } + + const char *get_version () const final override + { + return m_args->version; + } + +private: + const plugin_name_args *m_args; +}; + +/* Concrete subclass of client_version_info for use by compilers proper, + (i.e. using lang_hooks, and with knowledge of GCC plugins). */ + +class compiler_version_info : public client_version_info +{ +public: + const char *get_tool_name () const final override + { + return lang_hooks.name; + } + + /* Compare with toplev.cc: print_version. + TARGET_NAME is passed in by the Makefile. */ + char * + maybe_make_full_name () const final override + { + return xasprintf ("%s %sversion %s (%s)", + get_tool_name (), pkgversion_string, version_string, + TARGET_NAME); + } + + const char *get_version_string () const final override + { + return version_string; + } + + char *maybe_make_version_url () const final override + { + return xasprintf ("https://gcc.gnu.org/gcc-%i/", GCC_major_version); + } + + void for_each_plugin (plugin_visitor &visitor) const final override + { + ::for_each_plugin (on_plugin_cb, &visitor); + } + +private: + static void + on_plugin_cb (const plugin_name_args *args, + void *user_data) + { + compiler_diagnostic_client_plugin_info cpi (args); + client_version_info::plugin_visitor *visitor + = (client_version_info::plugin_visitor *)user_data; + visitor->on_plugin (cpi); + } +}; + +/* Subclass of diagnostic_client_data_hooks for use by compilers proper + i.e. with knowledge of "tree", access to langhooks, etc. */ + +class compiler_data_hooks : public diagnostic_client_data_hooks +{ +public: + const client_version_info *get_any_version_info () const final override + { + return &m_version_info; + } + + const logical_location *get_current_logical_location () const final override + { + if (current_function_decl) + return &m_current_fndecl_logical_loc; + else + return NULL; + } + + const char * + maybe_get_sarif_source_language (const char *filename) const final override + { + return lang_hooks.get_sarif_source_language (filename); + } + +private: + compiler_version_info m_version_info; + current_fndecl_logical_location m_current_fndecl_logical_loc; +}; + +/* Create a compiler_data_hooks (so that the class can be local + to this file). */ + +diagnostic_client_data_hooks * +make_compiler_data_hooks () +{ + return new compiler_data_hooks (); +} diff --git a/gcc/tree-diagnostic.cc b/gcc/tree-diagnostic.cc index 40a4c5f..0d79fe3 100644 --- a/gcc/tree-diagnostic.cc +++ b/gcc/tree-diagnostic.cc @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pretty-print.h" #include "gimple-pretty-print.h" #include "tree-diagnostic.h" +#include "diagnostic-client-data-hooks.h" #include "langhooks.h" #include "intl.h" @@ -373,4 +374,5 @@ tree_diagnostics_defaults (diagnostic_context *context) context->print_path = default_tree_diagnostic_path_printer; context->make_json_for_path = default_tree_make_json_for_path; context->set_locations_cb = set_inlining_locations; + context->m_client_data_hooks = make_compiler_data_hooks (); } diff --git a/gcc/tree-logical-location.cc b/gcc/tree-logical-location.cc new file mode 100644 index 0000000..79d8add --- /dev/null +++ b/gcc/tree-logical-location.cc @@ -0,0 +1,148 @@ +/* Subclasses of logical_location with knowledge of "tree". + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "pretty-print.h" +#include "tree-logical-location.h" +#include "langhooks.h" + +/* class compiler_logical_location : public logical_location. */ + +/* Get a string for DECL suitable for use by the SARIF logicalLocation + "name" property (SARIF v2.1.0 section 3.33.4). */ + +const char * +compiler_logical_location::get_short_name_for_tree (tree decl) +{ + gcc_assert (decl); + return identifier_to_locale (lang_hooks.decl_printable_name (decl, 0)); +} + +/* Get a string for DECL suitable for use by the SARIF logicalLocation + "fullyQualifiedName" property (SARIF v2.1.0 section 3.33.5). */ + +const char * +compiler_logical_location::get_name_with_scope_for_tree (tree decl) +{ + gcc_assert (decl); + return identifier_to_locale (lang_hooks.decl_printable_name (decl, 1)); +} + +/* Get a string for DECL suitable for use by the SARIF logicalLocation + "decoratedName" property (SARIF v2.1.0 section 3.33.6). */ + +const char * +compiler_logical_location::get_internal_name_for_tree (tree decl) +{ + gcc_assert (decl); + if (HAS_DECL_ASSEMBLER_NAME_P (decl)) + if (tree id = DECL_ASSEMBLER_NAME (decl)) + return IDENTIFIER_POINTER (id); + return NULL; +} + +/* Get what kind of SARIF logicalLocation DECL is (if any). */ + +enum logical_location_kind +compiler_logical_location::get_kind_for_tree (tree decl) +{ + if (!decl) + return LOGICAL_LOCATION_KIND_UNKNOWN; + + switch (TREE_CODE (decl)) + { + default: + return LOGICAL_LOCATION_KIND_UNKNOWN; + case FUNCTION_DECL: + return LOGICAL_LOCATION_KIND_FUNCTION; + case PARM_DECL: + return LOGICAL_LOCATION_KIND_PARAMETER; + case VAR_DECL: + return LOGICAL_LOCATION_KIND_VARIABLE; + } +} + +/* class tree_logical_location : public compiler_logical_location. */ + +/* Implementation of the logical_location vfuncs, using m_decl. */ + +const char * +tree_logical_location::get_short_name () const +{ + gcc_assert (m_decl); + return get_short_name_for_tree (m_decl); +} + +const char * +tree_logical_location::get_name_with_scope () const +{ + gcc_assert (m_decl); + return get_name_with_scope_for_tree (m_decl); +} + +const char * +tree_logical_location::get_internal_name () const +{ + gcc_assert (m_decl); + return get_internal_name_for_tree (m_decl); +} + +enum logical_location_kind +tree_logical_location::get_kind () const +{ + gcc_assert (m_decl); + return get_kind_for_tree (m_decl); +} + +/* class current_fndecl_logical_location : public compiler_logical_location. */ + +/* Implementation of the logical_location vfuncs, using + current_function_decl. */ + +const char * +current_fndecl_logical_location::get_short_name () const +{ + gcc_assert (current_function_decl); + return get_short_name_for_tree (current_function_decl); +} + +const char * +current_fndecl_logical_location::get_name_with_scope () const +{ + gcc_assert (current_function_decl); + return get_name_with_scope_for_tree (current_function_decl); +} + +const char * +current_fndecl_logical_location::get_internal_name () const +{ + gcc_assert (current_function_decl); + return get_internal_name_for_tree (current_function_decl); +} + +enum logical_location_kind +current_fndecl_logical_location::get_kind () const +{ + gcc_assert (current_function_decl); + return get_kind_for_tree (current_function_decl); +} diff --git a/gcc/tree-logical-location.h b/gcc/tree-logical-location.h new file mode 100644 index 0000000..3086cac --- /dev/null +++ b/gcc/tree-logical-location.h @@ -0,0 +1,67 @@ +/* Subclasses of logical_location with knowledge of "tree". + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_TREE_LOGICAL_LOCATION_H +#define GCC_TREE_LOGICAL_LOCATION_H + +#include "logical-location.h" + +/* Abstract subclass of logical_location, with knowledge of "tree", but + for no specific tree. */ + +class compiler_logical_location : public logical_location +{ + protected: + static const char *get_short_name_for_tree (tree); + static const char *get_name_with_scope_for_tree (tree); + static const char *get_internal_name_for_tree (tree); + static enum logical_location_kind get_kind_for_tree (tree); +}; + +/* Concrete subclass of logical_location, with reference to a specific + tree. */ + +class tree_logical_location : public compiler_logical_location +{ +public: + tree_logical_location (tree decl) : m_decl (decl) {} + + const char *get_short_name () const final override; + const char *get_name_with_scope () const final override; + const char *get_internal_name () const final override; + enum logical_location_kind get_kind () const final override; + +private: + tree m_decl; +}; + +/* Concrete subclass of logical_location, with reference to + current_function_decl. */ + +class current_fndecl_logical_location : public compiler_logical_location +{ +public: + const char *get_short_name () const final override; + const char *get_name_with_scope () const final override; + const char *get_internal_name () const final override; + enum logical_location_kind get_kind () const final override; +}; + +#endif /* GCC_TREE_LOGICAL_LOCATION_H. */ diff --git a/gcc/tree-loop-distribution.cc b/gcc/tree-loop-distribution.cc index db6e909..086b59c 100644 --- a/gcc/tree-loop-distribution.cc +++ b/gcc/tree-loop-distribution.cc @@ -3658,6 +3658,7 @@ loop_distribution::transform_reduction_loop (loop_p loop) /* Handle strlen like loops. */ if (store_dr == NULL && integer_zerop (pattern) + && INTEGRAL_TYPE_P (TREE_TYPE (reduction_var)) && TREE_CODE (reduction_iv.base) == INTEGER_CST && TREE_CODE (reduction_iv.step) == INTEGER_CST && integer_onep (reduction_iv.step)) diff --git a/gcc/tree-ssa-loop-ch.cc b/gcc/tree-ssa-loop-ch.cc index 2f5a390..26d96c0 100644 --- a/gcc/tree-ssa-loop-ch.cc +++ b/gcc/tree-ssa-loop-ch.cc @@ -55,7 +55,7 @@ entry_loop_condition_is_static (class loop *l, path_range_query *query) gcond *last = safe_dyn_cast <gcond *> (last_stmt (e->dest)); if (!last - || !irange::supports_type_p (TREE_TYPE (gimple_cond_lhs (last)))) + || !irange::supports_p (TREE_TYPE (gimple_cond_lhs (last)))) return false; edge true_e, false_e; diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc index 81b536f..549168a 100644 --- a/gcc/tree-ssa-loop-ivopts.cc +++ b/gcc/tree-ssa-loop-ivopts.cc @@ -3071,13 +3071,129 @@ get_loop_invariant_expr (struct ivopts_data *data, tree inv_expr) return *slot; } -/* Find the first undefined SSA name in *TP. */ +/* Return TRUE iff VAR is marked as maybe-undefined. See + mark_ssa_maybe_undefs. */ + +static inline bool +ssa_name_maybe_undef_p (tree var) +{ + gcc_checking_assert (TREE_CODE (var) == SSA_NAME); + return TREE_VISITED (var); +} + +/* Set (or clear, depending on VALUE) VAR's maybe-undefined mark. */ + +static inline void +ssa_name_set_maybe_undef (tree var, bool value = true) +{ + gcc_checking_assert (TREE_CODE (var) == SSA_NAME); + TREE_VISITED (var) = value; +} + +/* Return TRUE iff there are any non-PHI uses of VAR that dominate the + end of BB. If we return TRUE and BB is a loop header, then VAR we + be assumed to be defined within the loop, even if it is marked as + maybe-undefined. */ + +static inline bool +ssa_name_any_use_dominates_bb_p (tree var, basic_block bb) +{ + imm_use_iterator iter; + use_operand_p use_p; + FOR_EACH_IMM_USE_FAST (use_p, iter, var) + { + if (is_a <gphi *> (USE_STMT (use_p)) + || is_gimple_debug (USE_STMT (use_p))) + continue; + basic_block dombb = gimple_bb (USE_STMT (use_p)); + if (dominated_by_p (CDI_DOMINATORS, bb, dombb)) + return true; + } + + return false; +} + +/* Mark as maybe_undef any SSA_NAMEs that are unsuitable as ivopts + candidates for potentially involving undefined behavior. */ + +static void +mark_ssa_maybe_undefs (void) +{ + auto_vec<tree> queue; + + /* Scan all SSA_NAMEs, marking the definitely-undefined ones as + maybe-undefined and queuing them for propagation, while clearing + the mark on others. */ + unsigned int i; + tree var; + FOR_EACH_SSA_NAME (i, var, cfun) + { + if (SSA_NAME_IS_VIRTUAL_OPERAND (var) + || !ssa_undefined_value_p (var, false)) + ssa_name_set_maybe_undef (var, false); + else + { + ssa_name_set_maybe_undef (var); + queue.safe_push (var); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "marking _%i as maybe-undef\n", + SSA_NAME_VERSION (var)); + } + } + + /* Now propagate maybe-undefined from a DEF to any other PHI that + uses it, as long as there isn't any intervening use of DEF. */ + while (!queue.is_empty ()) + { + var = queue.pop (); + imm_use_iterator iter; + use_operand_p use_p; + FOR_EACH_IMM_USE_FAST (use_p, iter, var) + { + /* Any uses of VAR that aren't PHI args imply VAR must be + defined, otherwise undefined behavior would have been + definitely invoked. Only PHI args may hold + maybe-undefined values without invoking undefined + behavior for that reason alone. */ + if (!is_a <gphi *> (USE_STMT (use_p))) + continue; + gphi *phi = as_a <gphi *> (USE_STMT (use_p)); + + tree def = gimple_phi_result (phi); + if (ssa_name_maybe_undef_p (def)) + continue; + + /* Look for any uses of the maybe-unused SSA_NAME that + dominates the block that reaches the incoming block + corresponding to the PHI arg in which it is mentioned. + That means we can assume the SSA_NAME is defined in that + path, so we only mark a PHI result as maybe-undef if we + find an unused reaching SSA_NAME. */ + int idx = phi_arg_index_from_use (use_p); + basic_block bb = gimple_phi_arg_edge (phi, idx)->src; + if (ssa_name_any_use_dominates_bb_p (var, bb)) + continue; + + ssa_name_set_maybe_undef (def); + queue.safe_push (def); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "marking _%i as maybe-undef because of _%i\n", + SSA_NAME_VERSION (def), SSA_NAME_VERSION (var)); + } + } +} + +/* Return *TP if it is an SSA_NAME marked with TREE_VISITED, i.e., as + unsuitable as ivopts candidates for potentially involving undefined + behavior. */ static tree -find_ssa_undef (tree *tp, int *walk_subtrees, void *) +find_ssa_undef (tree *tp, int *walk_subtrees, void *bb_) { + basic_block bb = (basic_block) bb_; if (TREE_CODE (*tp) == SSA_NAME - && ssa_undefined_value_p (*tp, false)) + && ssa_name_maybe_undef_p (*tp) + && !ssa_name_any_use_dominates_bb_p (*tp, bb)) return *tp; if (!EXPR_P (*tp)) *walk_subtrees = 0; @@ -3114,7 +3230,7 @@ add_candidate_1 (struct ivopts_data *data, tree base, tree step, bool important, /* If BASE contains undefined SSA names make sure we only record the original IV. */ bool involves_undefs = false; - if (walk_tree (&base, find_ssa_undef, NULL, NULL)) + if (walk_tree (&base, find_ssa_undef, data->current_loop->header, NULL)) { if (pos != IP_ORIGINAL) return NULL; @@ -8192,6 +8308,7 @@ tree_ssa_iv_optimize (void) auto_bitmap toremove; tree_ssa_iv_optimize_init (&data); + mark_ssa_maybe_undefs (); /* Optimize the loops starting with the innermost ones. */ for (auto loop : loops_list (cfun, LI_FROM_INNERMOST)) diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc index afa5106..1e0f609 100644 --- a/gcc/tree-ssa-loop-niter.cc +++ b/gcc/tree-ssa-loop-niter.cc @@ -221,7 +221,7 @@ refine_value_range_using_guard (tree type, tree var, get_type_static_bounds (type, mint, maxt); mpz_init (minc1); mpz_init (maxc1); - value_range r; + Value_Range r (TREE_TYPE (varc1)); /* Setup range information for varc1. */ if (integer_zerop (varc1)) { @@ -374,7 +374,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, gphi_iterator gsi; /* Either for VAR itself... */ - value_range var_range; + Value_Range var_range (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (var_range, var); rtype = var_range.kind (); if (!var_range.undefined_p ()) @@ -385,10 +385,10 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, /* Or for PHI results in loop->header where VAR is used as PHI argument from the loop preheader edge. */ + Value_Range phi_range (TREE_TYPE (var)); for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi)) { gphi *phi = gsi.phi (); - value_range phi_range; if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var && get_range_query (cfun)->range_of_expr (phi_range, gimple_phi_result (phi)) @@ -410,7 +410,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off, involved. */ if (wi::gt_p (minv, maxv, sgn)) { - value_range vr; + Value_Range vr (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (vr, var); rtype = vr.kind (); if (!vr.undefined_p ()) @@ -3650,7 +3650,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt, if (tree_int_cst_sign_bit (step)) { wide_int max; - value_range base_range; + Value_Range base_range (TREE_TYPE (orig_base)); if (get_range_query (cfun)->range_of_expr (base_range, orig_base) && !base_range.undefined_p ()) max = base_range.upper_bound (); @@ -3672,7 +3672,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt, else { wide_int min; - value_range base_range; + Value_Range base_range (TREE_TYPE (orig_base)); if (get_range_query (cfun)->range_of_expr (base_range, orig_base) && !base_range.undefined_p ()) min = base_range.lower_bound (); @@ -3947,7 +3947,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt) low = lower_bound_in_type (type, type); high = upper_bound_in_type (type, type); - value_range r; + Value_Range r (TREE_TYPE (def)); get_range_query (cfun)->range_of_expr (r, def); if (r.kind () == VR_RANGE) { @@ -4997,7 +4997,7 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop) if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb)) return false; - value_range r; + Value_Range r (TREE_TYPE (var)); get_range_query (cfun)->range_of_expr (r, var); if (r.kind () != VR_RANGE) return false; diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc index f32f1a7..50b66c1 100644 --- a/gcc/tree-ssa-loop-unswitch.cc +++ b/gcc/tree-ssa-loop-unswitch.cc @@ -113,7 +113,7 @@ struct unswitch_predicate true_range (edge_range), edge_index (edge_index_), switch_p (true) { gcc_assert (!(e->flags & (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE)) - && irange::supports_type_p (TREE_TYPE (lhs))); + && irange::supports_p (TREE_TYPE (lhs))); false_range = true_range; if (!false_range.varying_p () && !false_range.undefined_p ()) @@ -134,19 +134,19 @@ struct unswitch_predicate tree rhs = gimple_cond_rhs (stmt); enum tree_code code = gimple_cond_code (stmt); condition = build2 (code, boolean_type_node, lhs, rhs); - if (irange::supports_type_p (TREE_TYPE (lhs))) + if (irange::supports_p (TREE_TYPE (lhs))) { auto range_op = range_op_handler (code, TREE_TYPE (lhs)); int_range<2> rhs_range (TREE_TYPE (rhs)); if (CONSTANT_CLASS_P (rhs)) rhs_range.set (rhs); - if (!range_op->op1_range (true_range, TREE_TYPE (lhs), - int_range<2> (boolean_true_node, - boolean_true_node), rhs_range) - || !range_op->op1_range (false_range, TREE_TYPE (lhs), - int_range<2> (boolean_false_node, - boolean_false_node), - rhs_range)) + if (!range_op.op1_range (true_range, TREE_TYPE (lhs), + int_range<2> (boolean_true_node, + boolean_true_node), rhs_range) + || !range_op.op1_range (false_range, TREE_TYPE (lhs), + int_range<2> (boolean_false_node, + boolean_false_node), + rhs_range)) { true_range.set_varying (TREE_TYPE (lhs)); false_range.set_varying (TREE_TYPE (lhs)); @@ -494,8 +494,8 @@ find_unswitching_predicates_for_bb (basic_block bb, class loop *loop, { unsigned nlabels = gimple_switch_num_labels (stmt); tree idx = gimple_switch_index (stmt); - if (TREE_CODE (idx) != SSA_NAME - || nlabels < 1) + tree idx_type = TREE_TYPE (idx); + if (!gimple_range_ssa_p (idx) || nlabels < 1) return; /* Index must be invariant. */ def = SSA_NAME_DEF_STMT (idx); @@ -523,20 +523,19 @@ find_unswitching_predicates_for_bb (basic_block bb, class loop *loop, tree lab = gimple_switch_label (stmt, i); tree cmp; int_range<2> lab_range; + tree low = fold_convert (idx_type, CASE_LOW (lab)); if (CASE_HIGH (lab) != NULL_TREE) { - tree cmp1 = fold_build2 (GE_EXPR, boolean_type_node, idx, - CASE_LOW (lab)); - tree cmp2 = fold_build2 (LE_EXPR, boolean_type_node, idx, - CASE_HIGH (lab)); + tree high = fold_convert (idx_type, CASE_HIGH (lab)); + tree cmp1 = fold_build2 (GE_EXPR, boolean_type_node, idx, low); + tree cmp2 = fold_build2 (LE_EXPR, boolean_type_node, idx, high); cmp = fold_build2 (BIT_AND_EXPR, boolean_type_node, cmp1, cmp2); - lab_range.set (CASE_LOW (lab), CASE_HIGH (lab)); + lab_range.set (low, high); } else { - cmp = fold_build2 (EQ_EXPR, boolean_type_node, idx, - CASE_LOW (lab)); - lab_range.set (CASE_LOW (lab)); + cmp = fold_build2 (EQ_EXPR, boolean_type_node, idx, low); + lab_range.set (low); } /* Combine the expression with the existing one. */ @@ -647,7 +646,7 @@ evaluate_control_stmt_using_entry_checks (gimple *stmt, TREE_OPERAND (last_predicate->condition, 1))) return true_edge ? boolean_true_node : boolean_false_node; /* Else try ranger if it supports LHS. */ - else if (irange::supports_type_p (TREE_TYPE (lhs))) + else if (irange::supports_p (TREE_TYPE (lhs))) { int_range<2> r; int_range_max path_range; diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc index 4eb65ca..a70aebd 100644 --- a/gcc/tree-ssa-threadedge.cc +++ b/gcc/tree-ssa-threadedge.cc @@ -1409,19 +1409,19 @@ tree hybrid_jt_simplifier::simplify (gimple *stmt, gimple *, basic_block, jt_state *state) { - int_range_max r; - compute_ranges_from_state (stmt, state); if (gimple_code (stmt) == GIMPLE_COND || gimple_code (stmt) == GIMPLE_ASSIGN) { + Value_Range r (gimple_range_type (stmt)); tree ret; if (m_query->range_of_stmt (r, stmt) && r.singleton_p (&ret)) return ret; } else if (gimple_code (stmt) == GIMPLE_SWITCH) { + int_range_max r; gswitch *switch_stmt = dyn_cast <gswitch *> (stmt); tree index = gimple_switch_index (switch_stmt); if (m_query->range_of_expr (r, index, stmt)) @@ -1452,7 +1452,7 @@ hybrid_jt_simplifier::compute_ranges_from_state (gimple *stmt, jt_state *state) tree op = gimple_op (stmt, i); if (op && TREE_CODE (op) == SSA_NAME - && irange::supports_type_p (TREE_TYPE (op))) + && Value_Range::supports_type_p (TREE_TYPE (op))) bitmap_set_bit (imports, SSA_NAME_VERSION (op)); } } diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc index fe9361c..dab5dad 100644 --- a/gcc/tree-vect-slp.cc +++ b/gcc/tree-vect-slp.cc @@ -1086,8 +1086,13 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap, tree vec = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0); if (!is_a <bb_vec_info> (vinfo) || TREE_CODE (vec) != SSA_NAME - || !operand_equal_p (TYPE_SIZE (vectype), - TYPE_SIZE (TREE_TYPE (vec)))) + /* When the element types are not compatible we pun the + source to the target vectype which requires equal size. */ + || ((!VECTOR_TYPE_P (TREE_TYPE (vec)) + || !types_compatible_p (TREE_TYPE (vectype), + TREE_TYPE (TREE_TYPE (vec)))) + && !operand_equal_p (TYPE_SIZE (vectype), + TYPE_SIZE (TREE_TYPE (vec))))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -1796,11 +1801,21 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node, lperm.safe_push (std::make_pair (0, (unsigned)lane)); } slp_tree vnode = vect_create_new_slp_node (vNULL); - /* ??? We record vectype here but we hide eventually necessary - punning and instead rely on code generation to materialize - VIEW_CONVERT_EXPRs as necessary. We instead should make - this explicit somehow. */ - SLP_TREE_VECTYPE (vnode) = vectype; + if (operand_equal_p (TYPE_SIZE (vectype), TYPE_SIZE (TREE_TYPE (vec)))) + /* ??? We record vectype here but we hide eventually necessary + punning and instead rely on code generation to materialize + VIEW_CONVERT_EXPRs as necessary. We instead should make + this explicit somehow. */ + SLP_TREE_VECTYPE (vnode) = vectype; + else + { + /* For different size but compatible elements we can still + use VEC_PERM_EXPR without punning. */ + gcc_assert (VECTOR_TYPE_P (TREE_TYPE (vec)) + && types_compatible_p (TREE_TYPE (vectype), + TREE_TYPE (TREE_TYPE (vec)))); + SLP_TREE_VECTYPE (vnode) = TREE_TYPE (vec); + } SLP_TREE_VEC_DEFS (vnode).safe_push (vec); /* We are always building a permutation node even if it is an identity permute to shield the rest of the vectorizer from the odd node @@ -6900,7 +6915,8 @@ vect_add_slp_permutation (vec_info *vinfo, gimple_stmt_iterator *gsi, /* ??? We SLP match existing vector element extracts but allow punning which we need to re-instantiate at uses but have no good way of explicitly representing. */ - if (!types_compatible_p (TREE_TYPE (first_def), vectype)) + if (operand_equal_p (TYPE_SIZE (TREE_TYPE (first_def)), TYPE_SIZE (vectype)) + && !types_compatible_p (TREE_TYPE (first_def), vectype)) { gassign *conv_stmt = gimple_build_assign (make_ssa_name (vectype), @@ -6912,7 +6928,9 @@ vect_add_slp_permutation (vec_info *vinfo, gimple_stmt_iterator *gsi, tree perm_dest = make_ssa_name (vectype); if (mask_vec) { - if (!types_compatible_p (TREE_TYPE (second_def), vectype)) + if (operand_equal_p (TYPE_SIZE (TREE_TYPE (first_def)), + TYPE_SIZE (vectype)) + && !types_compatible_p (TREE_TYPE (second_def), vectype)) { gassign *conv_stmt = gimple_build_assign (make_ssa_name (vectype), @@ -6925,9 +6943,34 @@ vect_add_slp_permutation (vec_info *vinfo, gimple_stmt_iterator *gsi, first_def, second_def, mask_vec); } + else if (!types_compatible_p (TREE_TYPE (first_def), vectype)) + { + /* For identity permutes we still need to handle the case + of lowpart extracts or concats. */ + unsigned HOST_WIDE_INT c; + auto first_def_nunits + = TYPE_VECTOR_SUBPARTS (TREE_TYPE (first_def)); + if (known_le (TYPE_VECTOR_SUBPARTS (vectype), first_def_nunits)) + { + tree lowpart = build3 (BIT_FIELD_REF, vectype, first_def, + TYPE_SIZE (vectype), bitsize_zero_node); + perm_stmt = gimple_build_assign (perm_dest, lowpart); + } + else if (constant_multiple_p (TYPE_VECTOR_SUBPARTS (vectype), + first_def_nunits, &c) && c == 2) + { + tree ctor = build_constructor_va (vectype, 2, NULL_TREE, first_def, + NULL_TREE, second_def); + perm_stmt = gimple_build_assign (perm_dest, ctor); + } + else + gcc_unreachable (); + } else - /* We need a copy here in case the def was external. */ - perm_stmt = gimple_build_assign (perm_dest, first_def); + { + /* We need a copy here in case the def was external. */ + perm_stmt = gimple_build_assign (perm_dest, first_def); + } vect_finish_stmt_generation (vinfo, NULL, perm_stmt, gsi); /* Store the vector statement in NODE. */ SLP_TREE_VEC_STMTS (node).quick_push (perm_stmt); @@ -6950,21 +6993,32 @@ vectorizable_slp_permutation (vec_info *vinfo, gimple_stmt_iterator *gsi, { tree vectype = SLP_TREE_VECTYPE (node); - /* ??? We currently only support all same vector input and output types + /* ??? We currently only support all same vector input types while the SLP IL should really do a concat + select and thus accept arbitrary mismatches. */ slp_tree child; unsigned i; poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype); bool repeating_p = multiple_p (nunits, SLP_TREE_LANES (node)); + tree op_vectype = NULL_TREE; + FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child) + if (SLP_TREE_VECTYPE (child)) + { + op_vectype = SLP_TREE_VECTYPE (child); + break; + } + if (!op_vectype) + op_vectype = vectype; FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child) { - if (!vect_maybe_update_slp_op_vectype (child, vectype) - || !types_compatible_p (SLP_TREE_VECTYPE (child), vectype)) + if ((SLP_TREE_DEF_TYPE (child) != vect_internal_def + && !vect_maybe_update_slp_op_vectype (child, op_vectype)) + || !types_compatible_p (SLP_TREE_VECTYPE (child), op_vectype) + || !types_compatible_p (TREE_TYPE (vectype), TREE_TYPE (op_vectype))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "Unsupported lane permutation\n"); + "Unsupported vector types in lane permutation\n"); return false; } if (SLP_TREE_LANES (child) != SLP_TREE_LANES (node)) @@ -7121,11 +7175,20 @@ vectorizable_slp_permutation (vec_info *vinfo, gimple_stmt_iterator *gsi, if (index == count) { - indices.new_vector (mask, second_vec.first == -1U ? 1 : 2, nunits); + indices.new_vector (mask, second_vec.first == -1U ? 1 : 2, + TYPE_VECTOR_SUBPARTS (op_vectype)); bool identity_p = indices.series_p (0, 1, 0, 1); machine_mode vmode = TYPE_MODE (vectype); - if (!identity_p - && !can_vec_perm_const_p (vmode, vmode, indices)) + machine_mode op_vmode = TYPE_MODE (op_vectype); + unsigned HOST_WIDE_INT c; + if ((!identity_p + && !can_vec_perm_const_p (vmode, op_vmode, indices)) + || (identity_p + && !known_le (nunits, + TYPE_VECTOR_SUBPARTS (op_vectype)) + && (!constant_multiple_p (nunits, + TYPE_VECTOR_SUBPARTS (op_vectype), + &c) || c != 2))) { if (dump_enabled_p ()) { diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 62ae5a9..30022da 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -924,20 +924,6 @@ extract_range_from_plus_minus_expr (value_range *vr, vr->set (min, max, kind); } -/* Return the range-ops handler for CODE and EXPR_TYPE. If no - suitable operator is found, return NULL and set VR to VARYING. */ - -static const range_operator * -get_range_op_handler (value_range *vr, - enum tree_code code, - tree expr_type) -{ - const range_operator *op = range_op_handler (code, expr_type); - if (!op) - vr->set_varying (expr_type); - return op; -} - /* If the types passed are supported, return TRUE, otherwise set VR to VARYING and return FALSE. */ @@ -946,8 +932,8 @@ supported_types_p (value_range *vr, tree type0, tree type1 = NULL) { - if (!value_range::supports_type_p (type0) - || (type1 && !value_range::supports_type_p (type1))) + if (!value_range_equiv::supports_p (type0) + || (type1 && !value_range_equiv::supports_p (type1))) { vr->set_varying (type0); return false; @@ -1005,10 +991,12 @@ range_fold_binary_symbolics_p (value_range *vr, &vr0, &vr1); return true; } - const range_operator *op = get_range_op_handler (vr, code, expr_type); + range_op_handler op (code, expr_type); + if (!op) + vr->set_varying (expr_type); vr0.normalize_symbolics (); vr1.normalize_symbolics (); - return op->fold_range (*vr, expr_type, vr0, vr1); + return op.fold_range (*vr, expr_type, vr0, vr1); } return false; } @@ -1040,10 +1028,12 @@ range_fold_unary_symbolics_p (value_range *vr, range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0); return true; } - const range_operator *op = get_range_op_handler (vr, code, expr_type); + range_op_handler op (code, expr_type); + if (!op) + vr->set_varying (expr_type); value_range vr0_cst (*vr0); vr0_cst.normalize_symbolics (); - return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type)); + return op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type)); } return false; } @@ -1060,9 +1050,12 @@ range_fold_binary_expr (value_range *vr, if (!supported_types_p (vr, expr_type) || !defined_ranges_p (vr, vr0_, vr1_)) return; - const range_operator *op = get_range_op_handler (vr, code, expr_type); + range_op_handler op (code, expr_type); if (!op) - return; + { + vr->set_varying (expr_type); + return; + } if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_)) return; @@ -1075,7 +1068,7 @@ range_fold_binary_expr (value_range *vr, vr1.set_varying (expr_type); vr0.normalize_addresses (); vr1.normalize_addresses (); - op->fold_range (*vr, expr_type, vr0, vr1); + op.fold_range (*vr, expr_type, vr0, vr1); } /* Perform a unary operation on a range. */ @@ -1089,16 +1082,19 @@ range_fold_unary_expr (value_range *vr, if (!supported_types_p (vr, expr_type, vr0_type) || !defined_ranges_p (vr, vr0)) return; - const range_operator *op = get_range_op_handler (vr, code, expr_type); + range_op_handler op (code, expr_type); if (!op) - return; + { + vr->set_varying (expr_type); + return; + } if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0)) return; value_range vr0_cst (*vr0); vr0_cst.normalize_addresses (); - op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type)); + op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type)); } /* If the range of values taken by OP can be inferred after STMT executes, diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 9ccd802..1d7541c 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -57,13 +57,13 @@ value_query::value_of_stmt (gimple *stmt, tree name) // range_query default methods. bool -range_query::range_on_edge (irange &r, edge, tree expr) +range_query::range_on_edge (vrange &r, edge, tree expr) { return range_of_expr (r, expr); } bool -range_query::range_of_stmt (irange &r, gimple *stmt, tree name) +range_query::range_of_stmt (vrange &r, gimple *stmt, tree name) { if (!name) name = gimple_get_lhs (stmt); @@ -79,11 +79,12 @@ tree range_query::value_of_expr (tree expr, gimple *stmt) { tree t; - int_range_max r; - if (!irange::supports_type_p (TREE_TYPE (expr))) + if (!Value_Range::supports_type_p (TREE_TYPE (expr))) return NULL_TREE; + Value_Range r (TREE_TYPE (expr)); + if (range_of_expr (r, expr, stmt)) { // A constant used in an unreachable block oftens returns as UNDEFINED. @@ -100,10 +101,10 @@ tree range_query::value_on_edge (edge e, tree expr) { tree t; - int_range_max r; - if (!irange::supports_type_p (TREE_TYPE (expr))) + if (!Value_Range::supports_type_p (TREE_TYPE (expr))) return NULL_TREE; + Value_Range r (TREE_TYPE (expr)); if (range_on_edge (r, e, expr)) { // A constant used in an unreachable block oftens returns as UNDEFINED. @@ -121,15 +122,15 @@ tree range_query::value_of_stmt (gimple *stmt, tree name) { tree t; - int_range_max r; if (!name) name = gimple_get_lhs (stmt); gcc_checking_assert (!name || name == gimple_get_lhs (stmt)); - if (!name || !irange::supports_type_p (TREE_TYPE (name))) + if (!name || !Value_Range::supports_type_p (TREE_TYPE (name))) return NULL_TREE; + Value_Range r (TREE_TYPE (name)); if (range_of_stmt (r, stmt, name) && r.singleton_p (&t)) return t; return NULL_TREE; @@ -187,7 +188,7 @@ range_query::~range_query () // representable, and UNDEFINED/false if not. bool -range_query::get_tree_range (irange &r, tree expr, gimple *stmt) +range_query::get_tree_range (vrange &r, tree expr, gimple *stmt) { tree type; if (TYPE_P (expr)) @@ -195,7 +196,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) else type = TREE_TYPE (expr); - if (!irange::supports_type_p (type)) + if (!Value_Range::supports_type_p (type)) { r.set_undefined (); return false; @@ -214,7 +215,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) return true; case SSA_NAME: - r = gimple_range_global (expr); + gimple_range_global (r, expr); return true; case ADDR_EXPR: @@ -223,7 +224,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) bool ov; if (tree_single_nonzero_warnv_p (expr, &ov)) { - r = range_nonzero (type); + r.set_nonzero (type); return true; } break; @@ -234,13 +235,14 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) } if (BINARY_CLASS_P (expr)) { - range_operator *op = range_op_handler (TREE_CODE (expr), type); + range_op_handler op (TREE_CODE (expr), type); if (op) { - int_range_max r0, r1; + Value_Range r0 (TREE_TYPE (TREE_OPERAND (expr, 0))); + Value_Range r1 (TREE_TYPE (TREE_OPERAND (expr, 1))); range_of_expr (r0, TREE_OPERAND (expr, 0), stmt); range_of_expr (r1, TREE_OPERAND (expr, 1), stmt); - op->fold_range (r, type, r0, r1); + op.fold_range (r, type, r0, r1); } else r.set_varying (type); @@ -248,12 +250,15 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) } if (UNARY_CLASS_P (expr)) { - range_operator *op = range_op_handler (TREE_CODE (expr), type); - if (op) + range_op_handler op (TREE_CODE (expr), type); + tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0)); + if (op && Value_Range::supports_type_p (op0_type)) { - int_range_max r0; + Value_Range r0 (TREE_TYPE (TREE_OPERAND (expr, 0))); + Value_Range r1 (type); + r1.set_varying (type); range_of_expr (r0, TREE_OPERAND (expr, 0), stmt); - op->fold_range (r, type, r0, int_range<1> (type)); + op.fold_range (r, type, r0, r1); } else r.set_varying (type); @@ -310,7 +315,7 @@ get_ssa_name_ptr_info_nonnull (const_tree name) // updated. bool -update_global_range (irange &r, tree name) +update_global_range (vrange &r, tree name) { tree type = TREE_TYPE (name); @@ -329,8 +334,7 @@ update_global_range (irange &r, tree name) if (r.undefined_p ()) return false; - value_range vr = r; - set_range_info (name, vr); + set_range_info (name, as_a <irange> (r)); return true; } else if (POINTER_TYPE_P (type)) @@ -348,7 +352,7 @@ update_global_range (irange &r, tree name) // return VARYING. static void -get_range_global (irange &r, tree name) +get_range_global (vrange &r, tree name) { tree type = TREE_TYPE (name); @@ -368,7 +372,7 @@ get_range_global (irange &r, tree name) r.set_nonzero (type); else if (INTEGRAL_TYPE_P (type)) { - get_ssa_name_range_info (r, name); + get_ssa_name_range_info (as_a <irange> (r), name); if (r.undefined_p ()) r.set_varying (type); } @@ -383,7 +387,8 @@ get_range_global (irange &r, tree name) } else if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name)) { - get_ssa_name_range_info (r, name); + gcc_checking_assert (irange::supports_p (TREE_TYPE (name))); + get_ssa_name_range_info (as_a <irange> (r), name); if (r.undefined_p ()) r.set_varying (type); } @@ -413,21 +418,19 @@ get_range_global (irange &r, tree name) // See discussion here: // https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html -value_range -gimple_range_global (tree name) +void +gimple_range_global (vrange &r, tree name) { tree type = TREE_TYPE (name); - gcc_checking_assert (TREE_CODE (name) == SSA_NAME - && irange::supports_type_p (type)); + gcc_checking_assert (TREE_CODE (name) == SSA_NAME); if (SSA_NAME_IS_DEFAULT_DEF (name) || (cfun && cfun->after_inlining) || is_a<gphi *> (SSA_NAME_DEF_STMT (name))) { - value_range vr; - get_range_global (vr, name); - return vr; + get_range_global (r, name); + return; } - return value_range (type); + r.set_varying (type); } // ---------------------------------------------- @@ -436,11 +439,9 @@ gimple_range_global (tree name) global_range_query global_ranges; bool -global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt) +global_range_query::range_of_expr (vrange &r, tree expr, gimple *stmt) { - tree type = TREE_TYPE (expr); - - if (!irange::supports_type_p (type) || !gimple_range_ssa_p (expr)) + if (!gimple_range_ssa_p (expr)) return get_tree_range (r, expr, stmt); get_range_global (r, expr); @@ -455,15 +456,16 @@ global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt) relation_kind range_query::query_relation (gimple *s, tree ssa1, tree ssa2, bool get_range) { - int_range_max tmp; if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME) return VREL_VARYING; // Ensure ssa1 and ssa2 have both been evaluated. if (get_range) { - range_of_expr (tmp, ssa1, s); - range_of_expr (tmp, ssa2, s); + Value_Range tmp1 (TREE_TYPE (ssa1)); + Value_Range tmp2 (TREE_TYPE (ssa2)); + range_of_expr (tmp1, ssa1, s); + range_of_expr (tmp2, ssa2, s); } return m_oracle->query_relation (gimple_bb (s), ssa1, ssa2); } @@ -476,7 +478,6 @@ relation_kind range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range) { basic_block bb; - int_range_max tmp; if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME) return VREL_VARYING; @@ -491,6 +492,7 @@ range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range) // Ensure ssa1 and ssa2 have both been evaluated. if (get_range) { + Value_Range tmp (TREE_TYPE (ssa1)); range_on_edge (tmp, e, ssa1); range_on_edge (tmp, e, ssa2); } diff --git a/gcc/value-query.h b/gcc/value-query.h index cf1a1d7..280e47e 100644 --- a/gcc/value-query.h +++ b/gcc/value-query.h @@ -89,9 +89,9 @@ public: // // Note that range_of_expr must always return TRUE unless ranges are // unsupported for EXPR's type (supports_type_p is false). - virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) = 0; - virtual bool range_on_edge (irange &r, edge, tree expr); - virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL); + virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL) = 0; + virtual bool range_on_edge (vrange &r, edge, tree expr); + virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL); // Query if there is any relation between SSA1 and SSA2. relation_kind query_relation (gimple *s, tree ssa1, tree ssa2, @@ -110,8 +110,8 @@ public: protected: class value_range_equiv *allocate_value_range_equiv (); void free_value_range_equiv (class value_range_equiv *); - bool get_tree_range (irange &r, tree expr, gimple *stmt); - bool get_arith_expr_range (irange &r, tree expr, gimple *stmt); + bool get_tree_range (vrange &v, tree expr, gimple *stmt); + bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt); relation_oracle *m_oracle; private: @@ -123,7 +123,7 @@ private: class global_range_query : public range_query { public: - bool range_of_expr (irange &r, tree expr, gimple * = NULL) override; + bool range_of_expr (vrange &r, tree expr, gimple * = NULL) override; }; extern global_range_query global_ranges; @@ -143,7 +143,7 @@ get_range_query (const struct function *fun) return fun->x_range_query ? fun->x_range_query : &global_ranges; } -extern value_range gimple_range_global (tree name); -extern bool update_global_range (irange &r, tree name); +extern void gimple_range_global (vrange &v, tree name); +extern bool update_global_range (vrange &v, tree name); #endif // GCC_QUERY_H diff --git a/gcc/value-range-equiv.cc b/gcc/value-range-equiv.cc index 77c6f5c..b0ae128 100644 --- a/gcc/value-range-equiv.cc +++ b/gcc/value-range-equiv.cc @@ -51,6 +51,12 @@ value_range_equiv::set (tree min, tree max, bitmap equiv, } void +value_range_equiv::set (tree min, tree max, value_range_kind kind) +{ + set (min, max, m_equiv, kind); +} + +void value_range_equiv::set (tree val) { gcc_assert (TREE_CODE (val) == SSA_NAME || is_gimple_min_invariant (val)); diff --git a/gcc/value-range-equiv.h b/gcc/value-range-equiv.h index 0aa1069..0a52d13 100644 --- a/gcc/value-range-equiv.h +++ b/gcc/value-range-equiv.h @@ -41,9 +41,10 @@ class GTY((user)) value_range_equiv : public value_range void move (value_range_equiv *); /* Leaves equiv bitmap alone. */ + virtual void set (tree, tree, value_range_kind = VR_RANGE) override; void update (tree, tree, value_range_kind = VR_RANGE); /* Deep-copies equiv bitmap argument. */ - void set (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE); + void set (tree, tree, bitmap, value_range_kind = VR_RANGE); void set (tree); bool operator== (const value_range_equiv &) const /* = delete */; @@ -66,6 +67,10 @@ class GTY((user)) value_range_equiv : public value_range void deep_copy (const value_range_equiv *); void dump (FILE *) const; void dump () const; + static bool supports_p (tree type) + { + return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); + } private: /* Deep-copies bitmap argument. */ diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 2e7385a..815cb78 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -30,6 +30,219 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "gimple-range.h" +// Convenience function only available for integers and pointers. + +wide_int +Value_Range::lower_bound () const +{ + if (is_a <irange> (*m_vrange)) + return as_a <irange> (*m_vrange).lower_bound (); + gcc_unreachable (); +} + +// Convenience function only available for integers and pointers. + +wide_int +Value_Range::upper_bound () const +{ + if (is_a <irange> (*m_vrange)) + return as_a <irange> (*m_vrange).upper_bound (); + gcc_unreachable (); +} + +void +Value_Range::dump (FILE *out) const +{ + if (m_vrange) + m_vrange->dump (out); + else + fprintf (out, "NULL"); +} + +DEBUG_FUNCTION void +debug (const Value_Range &r) +{ + r.dump (stderr); + fprintf (stderr, "\n"); +} + +// Default vrange definitions. + +bool +vrange::contains_p (tree) const +{ + return varying_p (); +} + +bool +vrange::singleton_p (tree *) const +{ + return false; +} + +void +vrange::set (tree, tree, value_range_kind) +{ +} + +tree +vrange::type () const +{ + return void_type_node; +} + +bool +vrange::supports_type_p (tree) const +{ + return false; +} + +void +vrange::set_undefined () +{ + m_kind = VR_UNDEFINED; +} + +void +vrange::set_varying (tree) +{ + m_kind = VR_VARYING; +} + +bool +vrange::union_ (const vrange &r) +{ + if (r.undefined_p () || varying_p ()) + return false; + if (undefined_p () || r.varying_p ()) + { + operator= (r); + return true; + } + gcc_unreachable (); + return false; +} + +bool +vrange::intersect (const vrange &r) +{ + if (undefined_p () || r.varying_p ()) + return false; + if (r.undefined_p ()) + { + set_undefined (); + return true; + } + if (varying_p ()) + { + operator= (r); + return true; + } + gcc_unreachable (); + return false; +} + +bool +vrange::zero_p () const +{ + return false; +} + +bool +vrange::nonzero_p () const +{ + return false; +} + +void +vrange::set_nonzero (tree) +{ +} + +void +vrange::set_zero (tree) +{ +} + +void +vrange::set_nonnegative (tree) +{ +} + +bool +vrange::fits_p (const vrange &) const +{ + return true; +} + +// Assignment operator for generic ranges. Copying incompatible types +// is not allowed. + +vrange & +vrange::operator= (const vrange &src) +{ + if (is_a <irange> (src)) + { + as_a <irange> (*this) = as_a <irange> (src); + return *this; + } + else + gcc_unreachable (); +} + +// Equality operator for generic ranges. + +bool +vrange::operator== (const vrange &src) const +{ + if (is_a <irange> (src)) + return as_a <irange> (*this) == as_a <irange> (src); + gcc_unreachable (); +} + +bool +irange::supports_type_p (tree type) const +{ + return supports_p (type); +} + +// Return TRUE if R fits in THIS. + +bool +irange::fits_p (const vrange &r) const +{ + return m_max_ranges >= as_a <irange> (r).num_pairs (); +} + +void +irange::set_nonnegative (tree type) +{ + set (build_int_cst (type, 0), TYPE_MAX_VALUE (type)); +} + +unsupported_range::unsupported_range () +{ + m_discriminator = VR_UNKNOWN; + set_undefined (); +} + +void +unsupported_range::dump (FILE *file) const +{ + fprintf (file, "[unsupported_range] "); + if (undefined_p ()) + { + fprintf (file, "UNDEFINED"); + return; + } + if (varying_p ()) + { + fprintf (file, "VARYING"); + return; + } + gcc_unreachable (); +} + // Here we copy between any two irange's. The ranges can be legacy or // multi-ranges, and copying between any combination works correctly. @@ -291,7 +504,7 @@ irange::set (tree min, tree max, value_range_kind kind) } if (kind == VR_UNDEFINED) { - set_undefined (); + irange::set_undefined (); return; } @@ -370,6 +583,7 @@ irange::set (tree min, tree max, value_range_kind kind) void irange::verify_range () { + gcc_checking_assert (m_discriminator == VR_IRANGE); if (m_kind == VR_UNDEFINED) { gcc_checking_assert (m_num_ranges == 0); @@ -2087,6 +2301,7 @@ dump_bound_with_infinite_markers (FILE *file, tree bound) void irange::dump (FILE *file) const { + fprintf (file, "[irange] "); if (undefined_p ()) { fprintf (file, "UNDEFINED"); @@ -2121,27 +2336,27 @@ irange::dump (FILE *file) const } void -irange::debug () const +vrange::debug () const { dump (stderr); fprintf (stderr, "\n"); } void -dump_value_range (FILE *file, const irange *vr) +dump_value_range (FILE *file, const vrange *vr) { vr->dump (file); } DEBUG_FUNCTION void -debug (const irange *vr) +debug (const vrange *vr) { dump_value_range (stderr, vr); fprintf (stderr, "\n"); } DEBUG_FUNCTION void -debug (const irange &vr) +debug (const vrange &vr) { debug (&vr); } diff --git a/gcc/value-range.h b/gcc/value-range.h index ec59d2e..dc6f6b0 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_VALUE_RANGE_H #define GCC_VALUE_RANGE_H +class irange; + // Types of value ranges. enum value_range_kind { @@ -37,24 +39,89 @@ enum value_range_kind VR_LAST }; -// Range of values that can be associated with an SSA_NAME. +// Discriminator between different vrange types. + +enum value_range_discriminator +{ + // Range holds an integer or pointer. + VR_IRANGE, + // Range holds an unsupported type. + VR_UNKNOWN +}; + +// Abstract class for ranges of any of the supported types. // -// This is the base class without any storage. +// To query what types ranger and the entire ecosystem can support, +// use Value_Range::supports_type_p(tree type). This is a static +// method available independently of any vrange object. +// +// To query what a given vrange variant can support, use: +// irange::supports_p () +// frange::supports_p () +// etc +// +// To query what a range object can support, use: +// void foo (vrange &v, irange &i, frange &f) +// { +// if (v.supports_type_p (type)) ... +// if (i.supports_type_p (type)) ... +// if (f.supports_type_p (type)) ... +// } + +class vrange +{ + template <typename T> friend bool is_a (vrange &); + friend class Value_Range; +public: + virtual void set (tree, tree, value_range_kind = VR_RANGE); + virtual tree type () const; + virtual bool supports_type_p (tree type) const; + virtual void set_varying (tree type); + virtual void set_undefined (); + virtual void dump (FILE * = stderr) const = 0; + virtual bool union_ (const vrange &); + virtual bool intersect (const vrange &); + virtual bool singleton_p (tree *result = NULL) const; + virtual bool contains_p (tree cst) const; + virtual bool zero_p () const; + virtual bool nonzero_p () const; + virtual void set_nonzero (tree type); + virtual void set_zero (tree type); + virtual void set_nonnegative (tree type); + virtual bool fits_p (const vrange &r) const; -class GTY((user)) irange + bool varying_p () const; + bool undefined_p () const; + vrange& operator= (const vrange &); + bool operator== (const vrange &) const; + bool operator!= (const vrange &r) const { return !(*this == r); } + + enum value_range_kind kind () const; // DEPRECATED + void debug () const; + +protected: + ENUM_BITFIELD(value_range_kind) m_kind : 8; + ENUM_BITFIELD(value_range_discriminator) m_discriminator : 4; +}; + +// An integer range without any storage. + +class GTY((user)) irange : public vrange { - friend class irange_allocator; + friend class vrange_allocator; public: // In-place setters. - void set (tree, tree, value_range_kind = VR_RANGE); - void set_nonzero (tree); - void set_zero (tree); - void set_varying (tree type); - void set_undefined (); + virtual void set (tree, tree, value_range_kind = VR_RANGE) override; + virtual void set_nonzero (tree type) override; + virtual void set_zero (tree type) override; + virtual void set_nonnegative (tree type) override; + virtual void set_varying (tree type) override; + virtual void set_undefined () override; // Range types. - static bool supports_type_p (tree); - tree type () const; + static bool supports_p (tree type); + virtual bool supports_type_p (tree type) const override; + virtual tree type () const override; // Iteration over sub-ranges. unsigned num_pairs () const; @@ -63,16 +130,14 @@ public: wide_int upper_bound () const; // Predicates. - bool zero_p () const; - bool nonzero_p () const; - bool undefined_p () const; - bool varying_p () const; - bool singleton_p (tree *result = NULL) const; - bool contains_p (tree) const; + virtual bool zero_p () const override; + virtual bool nonzero_p () const override; + virtual bool singleton_p (tree *result = NULL) const override; + virtual bool contains_p (tree cst) const override; // In-place operators. - bool union_ (const irange &); - bool intersect (const irange &); + virtual bool union_ (const vrange &) override; + virtual bool intersect (const vrange &) override; void invert (); // Operator overloads. @@ -81,12 +146,10 @@ public: bool operator!= (const irange &r) const { return !(*this == r); } // Misc methods. - bool fits_p (const irange &r) { return m_max_ranges >= r.num_pairs (); } - void dump (FILE * = stderr) const; - void debug () const; + virtual bool fits_p (const vrange &r) const override; + virtual void dump (FILE * = stderr) const override; // Deprecated legacy public methods. - enum value_range_kind kind () const; // DEPRECATED tree min () const; // DEPRECATED tree max () const; // DEPRECATED bool symbolic_p () const; // DEPRECATED @@ -139,7 +202,6 @@ private: bool intersect (const wide_int& lb, const wide_int& ub); unsigned char m_num_ranges; unsigned char m_max_ranges; - ENUM_BITFIELD(value_range_kind) m_kind : 8; tree *m_base; }; @@ -173,6 +235,61 @@ private: tree m_ranges[N*2]; }; +// Unsupported temporaries may be created by ranger before it's known +// they're unsupported, or by vr_values::get_value_range. + +class unsupported_range : public vrange +{ +public: + unsupported_range (); + virtual void dump (FILE *) const override; +}; + +// is_a<> and as_a<> implementation for vrange. + +// Anything we haven't specialized is a hard fail. +template <typename T> +inline bool +is_a (vrange &) +{ + gcc_unreachable (); + return false; +} + +template <typename T> +inline bool +is_a (const vrange &v) +{ + // Reuse is_a <vrange> to implement the const version. + const T &derived = static_cast<const T &> (v); + return is_a <T> (const_cast<T &> (derived)); +} + +template <typename T> +inline T & +as_a (vrange &v) +{ + gcc_checking_assert (is_a <T> (v)); + return static_cast <T &> (v); +} + +template <typename T> +inline const T & +as_a (const vrange &v) +{ + gcc_checking_assert (is_a <T> (v)); + return static_cast <const T &> (v); +} + +// Specializations for the different range types. + +template <> +inline bool +is_a <irange> (vrange &v) +{ + return v.m_discriminator == VR_IRANGE; +} + // This is a special int_range<1> with only one pair, plus // VR_ANTI_RANGE magic to describe slightly more than can be described // in one pair. It is described in the code as a "legacy range" (as @@ -187,6 +304,151 @@ typedef int_range<1> value_range; // calculations. typedef int_range<255> int_range_max; +// This is an "infinite" precision range object for use in temporary +// calculations for any of the handled types. The object can be +// transparently used as a vrange. + +class Value_Range +{ +public: + Value_Range (); + Value_Range (const vrange &r); + Value_Range (tree type); + Value_Range (const Value_Range &); + void set_type (tree type); + vrange& operator= (const vrange &); + bool operator== (const Value_Range &r) const; + bool operator!= (const Value_Range &r) const; + operator vrange &(); + operator const vrange &() const; + void dump (FILE *out = stderr) const; + static bool supports_type_p (tree type); + + // Convenience methods for vrange compatability. + void set (tree min, tree max, value_range_kind kind = VR_RANGE) + { return m_vrange->set (min, max, kind); } + tree type () { return m_vrange->type (); } + enum value_range_kind kind () { return m_vrange->kind (); } + bool varying_p () const { return m_vrange->varying_p (); } + bool undefined_p () const { return m_vrange->undefined_p (); } + void set_varying (tree type) { m_vrange->set_varying (type); } + void set_undefined () { m_vrange->set_undefined (); } + bool union_ (const vrange &r) { return m_vrange->union_ (r); } + bool intersect (const vrange &r) { return m_vrange->intersect (r); } + bool singleton_p (tree *result = NULL) const + { return m_vrange->singleton_p (result); } + bool zero_p () const { return m_vrange->zero_p (); } + wide_int lower_bound () const; // For irange/prange compatability. + wide_int upper_bound () const; // For irange/prange compatability. +private: + void init (tree type); + unsupported_range m_unsupported; + vrange *m_vrange; + int_range_max m_irange; +}; + +inline +Value_Range::Value_Range () +{ + m_vrange = &m_unsupported; +} + +// Copy constructor from a vrange. + +inline +Value_Range::Value_Range (const vrange &r) +{ + *this = r; +} + +// Copy constructor from a TYPE. The range of the temporary is set to +// UNDEFINED. + +inline +Value_Range::Value_Range (tree type) +{ + init (type); +} + +inline +Value_Range::Value_Range (const Value_Range &r) +{ + m_vrange = r.m_vrange; +} + +// Initialize object so it is possible to store temporaries of TYPE +// into it. + +inline void +Value_Range::init (tree type) +{ + gcc_checking_assert (TYPE_P (type)); + + if (irange::supports_p (type)) + m_vrange = &m_irange; + else + m_vrange = &m_unsupported; +} + +// Set the temporary to allow storing temporaries of TYPE. The range +// of the temporary is set to UNDEFINED. + +inline void +Value_Range::set_type (tree type) +{ + init (type); + m_vrange->set_undefined (); +} + +// Assignment operator for temporaries. Copying incompatible types is +// allowed. + +inline vrange & +Value_Range::operator= (const vrange &r) +{ + if (is_a <irange> (r)) + { + m_irange = as_a <irange> (r); + m_vrange = &m_irange; + } + else + gcc_unreachable (); + + return *m_vrange; +} + +inline bool +Value_Range::operator== (const Value_Range &r) const +{ + return *m_vrange == *r.m_vrange; +} + +inline bool +Value_Range::operator!= (const Value_Range &r) const +{ + return *m_vrange != *r.m_vrange; +} + +inline +Value_Range::operator vrange &() +{ + return *m_vrange; +} + +inline +Value_Range::operator const vrange &() const +{ + return *m_vrange; +} + +// Return TRUE if TYPE is supported by the vrange infrastructure. + +inline bool +Value_Range::supports_type_p (tree type) +{ + return irange::supports_p (type); +} + // Returns true for an old-school value_range as described above. inline bool irange::legacy_mode_p () const @@ -197,13 +459,13 @@ irange::legacy_mode_p () const extern bool range_has_numeric_bounds_p (const irange *); extern bool ranges_from_anti_range (const value_range *, value_range *, value_range *); -extern void dump_value_range (FILE *, const irange *); +extern void dump_value_range (FILE *, const vrange *); extern bool vrp_val_is_min (const_tree); extern bool vrp_val_is_max (const_tree); extern bool vrp_operand_equal_p (const_tree, const_tree); inline value_range_kind -irange::kind () const +vrange::kind () const { return m_kind; } @@ -293,13 +555,13 @@ irange::varying_compatible_p () const } inline bool -irange::varying_p () const +vrange::varying_p () const { return m_kind == VR_VARYING; } inline bool -irange::undefined_p () const +vrange::undefined_p () const { return m_kind == VR_UNDEFINED; } @@ -323,11 +585,9 @@ irange::nonzero_p () const } inline bool -irange::supports_type_p (tree type) +irange::supports_p (tree type) { - if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))) - return type; - return false; + return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); } inline bool @@ -398,6 +658,7 @@ gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie) inline irange::irange (tree *base, unsigned nranges) { + m_discriminator = VR_IRANGE; m_base = base; m_max_ranges = nranges; set_undefined (); @@ -547,21 +808,21 @@ irange::upper_bound () const } inline bool -irange::union_ (const irange &r) +irange::union_ (const vrange &r) { dump_flags_t m_flags = dump_flags; dump_flags &= ~TDF_DETAILS; - bool ret = irange::legacy_verbose_union_ (&r); + bool ret = irange::legacy_verbose_union_ (&as_a <irange> (r)); dump_flags = m_flags; return ret; } inline bool -irange::intersect (const irange &r) +irange::intersect (const vrange &r) { dump_flags_t m_flags = dump_flags; dump_flags &= ~TDF_DETAILS; - bool ret = irange::legacy_verbose_intersect (&r); + bool ret = irange::legacy_verbose_intersect (&as_a <irange> (r)); dump_flags = m_flags; return ret; } @@ -635,56 +896,63 @@ vrp_val_min (const_tree type) return NULL_TREE; } -// This is the irange storage class. It is used to allocate the -// minimum amount of storage needed for a given irange. Storage is -// automatically freed at destruction of the storage class. -// -// It is meant for long term storage, as opposed to int_range_max -// which is meant for intermediate temporary results on the stack. -// -// The newly allocated irange is initialized to the empty set -// (undefined_p() is true). +// This is the range storage class. It is used to allocate the +// minimum amount of storage needed for a given range. Storage is +// automatically freed at destruction of the class. -class irange_allocator +class vrange_allocator { public: - irange_allocator (); - ~irange_allocator (); - // Return a new range with NUM_PAIRS. - irange *allocate (unsigned num_pairs); - // Return a copy of SRC with the minimum amount of sub-ranges needed - // to represent it. - irange *allocate (const irange &src); - void *get_memory (unsigned num_bytes); + vrange_allocator (); + ~vrange_allocator (); + // Allocate a range of TYPE. + vrange *alloc_vrange (tree type); + // Allocate a memory block of BYTES. + void *alloc (unsigned bytes); + // Return a clone of SRC. + template <typename T> T *clone (const T &src); private: - DISABLE_COPY_AND_ASSIGN (irange_allocator); + irange *alloc_irange (unsigned pairs); + DISABLE_COPY_AND_ASSIGN (vrange_allocator); struct obstack m_obstack; }; inline -irange_allocator::irange_allocator () +vrange_allocator::vrange_allocator () { obstack_init (&m_obstack); } inline -irange_allocator::~irange_allocator () +vrange_allocator::~vrange_allocator () { obstack_free (&m_obstack, NULL); } // Provide a hunk of memory from the obstack. + inline void * -irange_allocator::get_memory (unsigned num_bytes) +vrange_allocator::alloc (unsigned bytes) { - void *r = obstack_alloc (&m_obstack, num_bytes); - return r; + return obstack_alloc (&m_obstack, bytes); +} + +// Return a new range to hold ranges of TYPE. The newly allocated +// range is initialized to VR_UNDEFINED. + +inline vrange * +vrange_allocator::alloc_vrange (tree type) +{ + if (irange::supports_p (type)) + return alloc_irange (2); + + gcc_unreachable (); } // Return a new range with NUM_PAIRS. inline irange * -irange_allocator::allocate (unsigned num_pairs) +vrange_allocator::alloc_irange (unsigned num_pairs) { // Never allocate 0 pairs. // Don't allocate 1 either, or we get legacy value_range's. @@ -694,17 +962,32 @@ irange_allocator::allocate (unsigned num_pairs) size_t nbytes = sizeof (tree) * 2 * num_pairs; // Allocate the irange and required memory for the vector. - void *r = obstack_alloc (&m_obstack, sizeof (irange)); - tree *mem = (tree *) obstack_alloc (&m_obstack, nbytes); + void *r = alloc (sizeof (irange)); + tree *mem = static_cast <tree *> (alloc (nbytes)); return new (r) irange (mem, num_pairs); } +// Return a clone of an irange. + +template <> inline irange * -irange_allocator::allocate (const irange &src) +vrange_allocator::clone <irange> (const irange &src) { - irange *r = allocate (src.num_pairs ()); + irange *r = alloc_irange (src.num_pairs ()); *r = src; return r; } +// Return a clone of a vrange. + +template <> +inline vrange * +vrange_allocator::clone <vrange> (const vrange &src) +{ + if (is_a <irange> (src)) + return clone <irange> (as_a <irange> (src)); + + gcc_unreachable (); +} + #endif // GCC_VALUE_RANGE_H diff --git a/gcc/varasm.cc b/gcc/varasm.cc index 6454f1c..826a9ca 100644 --- a/gcc/varasm.cc +++ b/gcc/varasm.cc @@ -5069,7 +5069,7 @@ initializer_constant_valid_p (tree value, tree endtype, bool reverse) an element of a "constant" initializer. */ bool -initializer_constant_valid_for_bitfield_p (tree value) +initializer_constant_valid_for_bitfield_p (const_tree value) { /* For bitfields we support integer constants or possibly nested aggregates of such. */ @@ -5078,7 +5078,7 @@ initializer_constant_valid_for_bitfield_p (tree value) case CONSTRUCTOR: { unsigned HOST_WIDE_INT idx; - tree elt; + const_tree elt; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt) if (!initializer_constant_valid_for_bitfield_p (elt)) diff --git a/gcc/varasm.h b/gcc/varasm.h index 8ba8374..acbd9fa 100644 --- a/gcc/varasm.h +++ b/gcc/varasm.h @@ -65,7 +65,7 @@ extern tree initializer_constant_valid_p (tree, tree, bool = false); /* Return true if VALUE is a valid constant-valued expression for use in initializing a static bit-field; one that can be an element of a "constant" initializer. */ -extern bool initializer_constant_valid_for_bitfield_p (tree); +extern bool initializer_constant_valid_for_bitfield_p (const_tree); /* Whether a constructor CTOR is a valid static constant initializer if all its elements are. This used to be internal to initializer_constant_valid_p diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc index 47faa4f..38f204e 100644 --- a/gcc/vr-values.cc +++ b/gcc/vr-values.cc @@ -177,7 +177,7 @@ vr_values::get_value_range (const_tree var, } bool -vr_values::range_of_expr (irange &r, tree expr, gimple *stmt) +vr_values::range_of_expr (vrange &r, tree expr, gimple *stmt) { if (!gimple_range_ssa_p (expr)) return get_tree_range (r, expr, stmt); @@ -883,7 +883,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr, wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max))); tree range_min = build_zero_cst (expr_type); tree range_max = wide_int_to_tree (expr_type, wmax - 1); - vr->set (range_min, range_max); + vr->set (range_min, range_max, NULL); return; } } @@ -1275,7 +1275,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt) /* This is the boolean return value whether compare and exchange changed anything or not. */ vr->set (build_int_cst (type, 0), - build_int_cst (type, 1)); + build_int_cst (type, 1), NULL); return; } break; @@ -1297,7 +1297,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt) vr->set_varying (type); else vr->set (build_int_cst (type, 0), - build_int_cst (type, 1)); + build_int_cst (type, 1), NULL); } else if (types_compatible_p (type, TREE_TYPE (op0)) && types_compatible_p (type, TREE_TYPE (op1))) @@ -1630,6 +1630,20 @@ compare_range_with_value (enum tree_code comp, const value_range *vr, gcc_unreachable (); } +static inline void +fix_overflow (tree *min, tree *max) +{ + /* Even for valid range info, sometimes overflow flag will leak in. + As GIMPLE IL should have no constants with TREE_OVERFLOW set, we + drop them. */ + if (TREE_OVERFLOW_P (*min)) + *min = drop_tree_overflow (*min); + if (TREE_OVERFLOW_P (*max)) + *max = drop_tree_overflow (*max); + + gcc_checking_assert (compare_values (*min, *max) != 1); +} + /* Given a VAR in STMT within LOOP, determine the bounds of the variable and store it in MIN/MAX and return TRUE. If no bounds could be determined, return FALSE. */ @@ -1640,6 +1654,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, { tree init, step, chrec, tmin, tmax, type = TREE_TYPE (var); enum ev_direction dir; + int_range<2> r; chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var)); @@ -1647,7 +1662,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, if (is_gimple_min_invariant (chrec)) { *min = *max = chrec; - goto fix_overflow; + fix_overflow (min, max); + return true; } if (TREE_CODE (chrec) != POLYNOMIAL_CHREC) @@ -1659,13 +1675,17 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, if (!init || !step) return false; + Value_Range rinit (TREE_TYPE (init)); + Value_Range rstep (TREE_TYPE (step)); /* If INIT is an SSA with a singleton range, set INIT to said singleton, otherwise leave INIT alone. */ - if (TREE_CODE (init) == SSA_NAME) - query->get_value_range (init, stmt)->singleton_p (&init); + if (TREE_CODE (init) == SSA_NAME + && query->range_of_expr (rinit, init, stmt)) + rinit.singleton_p (&init); /* Likewise for step. */ - if (TREE_CODE (step) == SSA_NAME) - query->get_value_range (step, stmt)->singleton_p (&step); + if (TREE_CODE (step) == SSA_NAME + && query->range_of_expr (rstep, step, stmt)) + rstep.singleton_p (&step); /* If STEP is symbolic, we can't know whether INIT will be the minimum or maximum value in the range. Also, unless INIT is @@ -1699,7 +1719,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, if (TREE_CODE (step) == INTEGER_CST && is_gimple_val (init) && (TREE_CODE (init) != SSA_NAME - || query->get_value_range (init, stmt)->kind () == VR_RANGE)) + || (query->range_of_expr (r, init, stmt) + && r.kind () == VR_RANGE))) { widest_int nit; @@ -1724,7 +1745,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, { value_range maxvr, vr0, vr1; if (TREE_CODE (init) == SSA_NAME) - vr0 = *(query->get_value_range (init, stmt)); + query->range_of_expr (vr0, init, stmt); else if (is_gimple_min_invariant (init)) vr0.set (init); else @@ -1737,10 +1758,10 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, /* Likewise if the addition did. */ if (maxvr.kind () == VR_RANGE) { - value_range initvr; + int_range<2> initvr; if (TREE_CODE (init) == SSA_NAME) - initvr = *(query->get_value_range (init, stmt)); + query->range_of_expr (initvr, init, stmt); else if (is_gimple_min_invariant (init)) initvr.set (init); else @@ -1770,16 +1791,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query, else *min = init; - fix_overflow: - /* Even for valid range info, sometimes overflow flag will leak in. - As GIMPLE IL should have no constants with TREE_OVERFLOW set, we - drop them. */ - if (TREE_OVERFLOW_P (*min)) - *min = drop_tree_overflow (*min); - if (TREE_OVERFLOW_P (*max)) - *max = drop_tree_overflow (*max); - - gcc_checking_assert (compare_values (*min, *max) != 1); + fix_overflow (min, max); return true; } @@ -2446,7 +2458,9 @@ simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p) fprintf (dump_file, "\t"); print_generic_expr (dump_file, use); fprintf (dump_file, ": "); - dump_value_range (dump_file, query->get_value_range (use, stmt)); + Value_Range r (TREE_TYPE (use)); + query->range_of_expr (r, use, stmt); + r.dump (dump_file); } fprintf (dump_file, "\n"); diff --git a/gcc/vr-values.h b/gcc/vr-values.h index 7a377ce..f018d0d 100644 --- a/gcc/vr-values.h +++ b/gcc/vr-values.h @@ -109,7 +109,7 @@ class vr_values : public range_query vr_values (void); ~vr_values (void); - virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) override; + virtual bool range_of_expr (vrange &r, tree expr, gimple *stmt) override; virtual tree value_of_expr (tree, gimple * = NULL) override; virtual tree value_on_edge (edge, tree) override; virtual tree value_of_stmt (gimple *, tree = NULL_TREE) override; |