diff options
author | Martin Liska <mliska@suse.cz> | 2022-08-08 09:05:36 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-08-08 09:05:36 +0200 |
commit | b3a187edd33b89acf19ba46f3b8070d7c977ac57 (patch) | |
tree | 43549f6851052eb2844ea76358af30a9fd302ec5 /gcc | |
parent | 89eca196c99645ee1abefcf8b4a9dd84edd87ad6 (diff) | |
parent | 2633c8d8f338f1e2b53d3757f3edf4179bfcc218 (diff) | |
download | gcc-b3a187edd33b89acf19ba46f3b8070d7c977ac57.zip gcc-b3a187edd33b89acf19ba46f3b8070d7c977ac57.tar.gz gcc-b3a187edd33b89acf19ba46f3b8070d7c977ac57.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
202 files changed, 5215 insertions, 1049 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 22cf563..2d41c22 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,355 @@ +2022-08-07 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386.md (*cmp<dwi>_doubleword): Change predicate + for x86_64_hilo_general_operand to general operand. Call + force_reg on parts that are not x86_64_immediate_operand. + +2022-08-05 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/105947 + * doc/invoke.texi: Add -Wanalyzer-jump-through-null. + +2022-08-05 Roger Sayle <roger@nextmovesoftware.com> + + * expmed.cc (emit_store_flag_1): Move code to expand double word + equality and inequality against zero or -1, using word operations, + to after trying to use the backend's cstore<mode>4 optab/expander. + +2022-08-05 Tamar Christina <tamar.christina@arm.com> + + PR middle-end/106534 + * tree-ssa-phiopt.cc (tree_ssa_phiopt_worker): Guard the + value_replacement and store_elim from diamonds. + +2022-08-05 Richard Biener <rguenther@suse.de> + + * tree-ssa-threadbackward.cc (back_threader::maybe_register_path): + Check whether the registry register_path rejected the path. + (back_threader_registry::register_path): Return whether + register_jump_thread succeeded. + +2022-08-05 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/106514 + * value-range.cc (unsupported_range::unsupported_range): Move... + * value-range.h (unsupported_range::unsupported_range): ...here. + (unsupported_range::set_undefined): New. + +2022-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106533 + * tree-loop-distribution.cc (loop_distribution::execute): Continue + analyzing the inner loops when find_seed_stmts_for_distribution + fails. + +2022-08-05 Andrew Pinski <apinski@marvell.com> + + * config/riscv/predicates.md (splittable_const_int_operand): + Remove the check for TARGET_64BIT for single bit const values. + +2022-08-04 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/106514 + * gimple-range-path.cc (path_range_query::compute_ranges_in_block): + Use EXECUTE_IF_AND_IN_BITMAP to loop over 2 bitmaps. + +2022-08-04 Tamar Christina <tamar.christina@arm.com> + + * match.pd: New bit_not rule. + +2022-08-04 Tamar Christina <tamar.christina@arm.com> + + PR middle-end/106519 + * tree-ssa-phiopt.cc (tree_ssa_phiopt_worker): Check final phi edge for + diamond shapes. + +2022-08-04 Sam Feifer <sfeifer@redhat.com> + + PR tree-optimization/106243 + * match.pd (-x & 1): New simplification. + +2022-08-04 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106521 + * gimple-loop-jam.cc (tree_loop_unroll_and_jam): Perform + CFG cleanup manually before rewriting into LC SSA. + +2022-08-04 Richard Biener <rguenther@suse.de> + + * tree-ssa-threadbackward.cc (populate_worklist): Remove. + (back_threader::resolve_phi): Likewise. + (back_threader::find_paths_to_names): Rewrite greedy search. + +2022-08-04 Ilya Leoshkevich <iii@linux.ibm.com> + + * config/s390/vector.md (V_HW_FT): New iterator. + * config/s390/vx-builtins.md (vsel<mode>): Use V_HW_FT instead + of V_HW. + +2022-08-03 Michael Meissner <meissner@linux.ibm.com> + + * config/rs6000/rs6000.cc (rs6000_option_override_internal): Remove code + setting -mblock-ops-vector-pair. + +2022-08-03 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/106514 + * value-relation.cc (path_oracle::killing_def) Do not walk the + equivalence set clearing bits. + +2022-08-03 Tamar Christina <tamar.christina@arm.com> + + * tree-ssa-phiopt.cc (minmax_replacement): Optionally search for the phi + sequence of a three-way conditional. + (replace_phi_edge_with_variable): Support diamonds. + (tree_ssa_phiopt_worker): Detect diamond phi structure for three-way + min/max. + (strip_bit_not, invert_minmax_code): New. + +2022-08-03 Richard Earnshaw <rearnsha@arm.com> + + PR rtl-optimization/106187 + * alias.h (mems_same_for_tbaa_p): Declare. + * alias.cc (mems_same_for_tbaa_p): New function. + * dse.cc (record_store): Use it instead of open-coding + alias check. + * cselib.h (cselib_redundant_set_p): Declare. + * cselib.cc: Include alias.h + (cselib_redundant_set_p): New function. + * cfgcleanup.cc: (mark_effect): Use cselib_redundant_set_p instead + of rtx_equal_for_cselib_p. + * postreload.cc (reload_cse_simplify): Use cselib_redundant_set_p. + (reload_cse_noop_set_p): Delete. + +2022-08-03 Martin Liska <mliska@suse.cz> + + * doc/gcov-dump.texi: Document the new option. + * gcov-dump.cc (main): Parse the new option. + (print_usage): Show the option. + (tag_counters): Sort key:value pairs of TOP N counter. + +2022-08-03 Martin Liska <mliska@suse.cz> + + * profile.cc (compute_branch_probabilities): Do not collect + stats unless TDF_DETAILS. + +2022-08-03 Roger Sayle <roger@nextmovesoftware.com> + Uroš Bizjak <ubizjak@gmail.com> + + PR target/47949 + * config/i386/i386.md (peephole2): New peephole2 to convert + SWI48 moves to/from %rax/%eax where the src is dead to xchg, + when optimizing for minimal size with -Oz. + +2022-08-03 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386.md (*cmp<dwi>_doubleword): Add a special case + to split comparisons against -1 using AND and CMP -1 instructions. + +2022-08-03 Roger Sayle <roger@nextmovesoftware.com> + + * config/i386/i386-features.cc (compute_convert_gain): Add gain + for converting suitable TImode shift to a V1TImode shift. + (timode_scalar_chain::convert_insn): Add support for converting + suitable ASHIFT and LSHIFTRT. + (timode_scalar_to_vector_candidate_p): Consider logical shifts + by integer constants that are multiples of 8 to be candidates. + +2022-08-03 Roger Sayle <roger@nextmovesoftware.com> + Segher Boessenkool <segher@kernel.crashing.org> + Richard Sandiford <richard.sandiford@arm.com> + + * simplify-rtx.cc (simplify_unary_operation_1) <ABS>: Add + optimizations for CLRSB, PARITY, POPCOUNT, SS_ABS and LSHIFTRT + that are all positive to complement the existing FFS and + idempotent ABS simplifications. + <SIGN_EXTEND>: Canonicalize SIGN_EXTEND to ZERO_EXTEND when + val_signbit_known_clear_p is true of the operand. + Simplify sign extensions of SUBREG truncations of operands + that are already suitably (zero) extended. + <ZERO_EXTEND>: Simplify zero extensions of SUBREG truncations + of operands that are already suitably zero extended. + +2022-08-02 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/106510 + * gimple-range-fold.cc (fur_source::register_outgoing_edges): + Check for unsupported statements early. + +2022-08-02 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/106474 + * gimple-range-cache.cc (ranger_cache::fill_block_cache): Query + range of equivalences that may contribute to the range. + +2022-08-02 Jose E. Marchesi <jose.marchesi@oracle.com> + + * btfout.cc (output_asm_btf_vlen_bytes): Do not use the CHAR + encoding bit in BTF. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-fold.cc (fold_using_range::range_of_phi): Remove + irange check. + (tree_lower_bound): New. + (tree_upper_bound): New. + (fold_using_range::range_of_ssa_name_with_loop_info): Convert to + vrange. + * gimple-range-fold.h (range_of_ssa_name_with_loop_info): Change + argument to vrange. + +2022-08-02 Richard Biener <rguenther@suse.de> + + * tree-ssa-threadbackward.cc + (back_threader_profitability::profitable_path_p): Apply + size constraints to all paths again. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * range-op-float.cc (finite_operands_p): New. + (frelop_early_resolve): New. + (default_frelop_fold_range): New. + (class foperator_equal): New. + (class foperator_not_equal): New. + (class foperator_lt): New. + (class foperator_le): New. + (class foperator_gt): New. + (class foperator_ge): New. + (class foperator_unordered): New. + (class foperator_ordered): New. + (class foperator_relop_unknown): New. + (floating_op_table::floating_op_table): Add above classes to + floating op table. + * value-range.h (frange::supports_p): Enable. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * tree-core.h (struct tree_ssa_name): Add frange_info and + reshuffle the rest. + * value-range-storage.cc (vrange_storage::alloc_slot): Add case + for frange. + (vrange_storage::set_vrange): Same. + (vrange_storage::get_vrange): Same. + (vrange_storage::fits_p): Same. + (frange_storage_slot::alloc_slot): New. + (frange_storage_slot::set_frange): New. + (frange_storage_slot::get_frange): New. + (frange_storage_slot::fits_p): New. + * value-range-storage.h (class frange_storage_slot): New. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * ipa-prop.cc (ipa_compute_jump_functions_for_edge): Limit ranger + query to integrals. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * value-range.cc (frange::set): Initialize m_props and cleanup. + +2022-08-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106497 + * tree-ssa-threadupdate.cc (fwd_jt_path_registry::update_cfg): + Also verify we can copy EDGE_COPY_SRC_JOINER_BLOCK. + +2022-08-02 Martin Liska <mliska@suse.cz> + + * profile.cc (compute_branch_probabilities): Dump details only + if TDF_DETAILS. + * symtab.cc (symtab_node::dump_base): Do not dump pointer unless + TDF_ADDRESS is used, it makes comparison harder. + +2022-08-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106498 + * omp-expand.cc (expand_omp_taskreg): Do not perform virtual + SSA update here. + (expand_omp_for): Or here. + (execute_expand_omp): Instead schedule it here together + with CFG cleanup via TODO. + +2022-08-02 Richard Biener <rguenther@suse.de> + + PR lto/106334 + * dwarf2out.cc (dwarf2out_register_external_die): Adjust + assert. + +2022-08-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106495 + * tree-ssa-threadbackward.cc + (back_threader_profitability::profitable_path_p): If known_edge + is probably never executed avoid threading. + +2022-08-01 David Malcolm <dmalcolm@redhat.com> + + * doc/invoke.texi (-Wanalyzer-putenv-of-auto-var): Fix copy&paste + error. + +2022-08-01 Roger Sayle <roger@nextmovesoftware.com> + Uroš Bizjak <ubizjak@gmail.com> + + PR target/106481 + * config/i386/i386-features.cc (timode_scalar_chain::convert_insn): + Convert a CONST_SCALAR_INT_P in a REG_EQUAL note into a V1TImode + CONST_VECTOR. + +2022-08-01 H.J. Lu <hjl.tools@gmail.com> + + PR target/83782 + * config/i386/i386.cc (ix86_ifunc_ref_local_ok): New. + (TARGET_IFUNC_REF_LOCAL_OK): Use it. + +2022-08-01 Jose E. Marchesi <jose.marchesi@oracle.com> + + PR debug/106263 + * ctfc.h (struct ctf_dtdef): Add field linkage. + * ctfc.cc (ctf_add_function): Set ctti_linkage. + * dwarf2ctf.cc (gen_ctf_function_type): Pass a linkage for + function types and subprograms. + * btfout.cc (btf_asm_func_type): Emit linkage information for the + function. + (btf_dtd_emit_preprocess_cb): Propagate the linkage information + for functions. + +2022-08-01 Andrew Stubbs <ams@codesourcery.com> + Jakub Jelinek <jakub@redhat.com> + + * omp-simd-clone.cc (simd_clone_adjust): Convert shift_cnt to match + the mask type. + +2022-08-01 Sam Feifer <sfeifer@redhat.com> + + PR tree-optimization/104992 + * match.pd (x / y * y == x): New simplification. + +2022-08-01 Aldy Hernandez <aldyh@redhat.com> + + * value-range.cc (tree_compare): New. + (frange::set): Make more general. + (frange::normalize_kind): Cleanup and return bool. + (frange::union_): Use normalize_kind return value. + (frange::intersect): Same. + (frange::verify_range): Remove unnecessary else. + * value-range.h (vrp_val_max): Move before frange class. + (vrp_val_min): Same. + (frange::frange): Remove set to m_type. + +2022-08-01 Aldy Hernandez <aldyh@redhat.com> + + * value-range.cc (vrange::supports_type_p): Use const_tree. + (irange::supports_type_p): Same. + (frange::supports_type_p): Same. + * value-range.h (Value_Range::supports_type_p): Same. + (irange::supports_p): Same. + +2022-08-01 Aldy Hernandez <aldyh@redhat.com> + + * gimple-range-fold.cc (fold_using_range::range_of_phi): Only + query SCEV for integers. + (fold_using_range::range_of_ssa_name_with_loop_info): Remove + irange check. + 2022-07-31 Roger Sayle <roger@nextmovesoftware.com> * config/i386/i386.md (define_expand <any_rotate>ti3): For diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index ed14e56..00f22f5 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220801 +20220808 diff --git a/gcc/alias.cc b/gcc/alias.cc index 8c08452..d54feb1 100644 --- a/gcc/alias.cc +++ b/gcc/alias.cc @@ -389,6 +389,20 @@ refs_same_for_tbaa_p (tree earlier, tree later) || alias_set_subset_of (later_base_set, earlier_base_set)); } +/* Similar to refs_same_for_tbaa_p() but for use on MEM rtxs. */ +bool +mems_same_for_tbaa_p (rtx earlier, rtx later) +{ + gcc_assert (MEM_P (earlier)); + gcc_assert (MEM_P (later)); + + return ((MEM_ALIAS_SET (earlier) == MEM_ALIAS_SET (later) + || alias_set_subset_of (MEM_ALIAS_SET (later), + MEM_ALIAS_SET (earlier))) + && (!MEM_EXPR (earlier) + || refs_same_for_tbaa_p (MEM_EXPR (earlier), MEM_EXPR (later)))); +} + /* Returns a pointer to the alias set entry for ALIAS_SET, if there is such an entry, or NULL otherwise. */ diff --git a/gcc/alias.h b/gcc/alias.h index b259651..ee3db46 100644 --- a/gcc/alias.h +++ b/gcc/alias.h @@ -40,6 +40,7 @@ tree reference_alias_ptr_type_1 (tree *); bool alias_ptr_types_compatible_p (tree, tree); int compare_base_decls (tree, tree); bool refs_same_for_tbaa_p (tree, tree); +bool mems_same_for_tbaa_p (rtx, rtx); /* This alias set can be used to force a memory to conflict with all other memories, creating a barrier across which no memory reference diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index d1cb3ad..0b93219 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,21 @@ +2022-08-05 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/105947 + * analyzer.opt (Wanalyzer-jump-through-null): New option. + * engine.cc (class jump_through_null): New. + (exploded_graph::process_node): Complain about jumps through NULL + function pointers. + +2022-08-02 Immad Mir <mirimmad@outlook.com> + + PR analyzer/106298 + * sm-fd.cc (fd_state_machine::on_open): Add + creat, dup, dup2 and dup3 functions. + (enum dup): New. + (fd_state_machine::valid_to_unchecked_state): New. + (fd_state_machine::on_creat): New. + (fd_state_machine::on_dup): New. + 2022-07-28 David Malcolm <dmalcolm@redhat.com> PR analyzer/105893 diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index 808ff36..c6d9c53 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -98,6 +98,10 @@ Wanalyzer-free-of-non-heap Common Var(warn_analyzer_free_of_non_heap) Init(1) Warning Warn about code paths in which a non-heap pointer is freed. +Wanalyzer-jump-through-null +Common Var(warn_analyzer_jump_through_null) Init(1) Warning +Warn about code paths in which a NULL function pointer is called. + Wanalyzer-malloc-leak Common Var(warn_analyzer_malloc_leak) Init(1) Warning Warn about code paths in which a heap-allocated pointer leaks. diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 85b7c5e..e8db00d 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -3705,6 +3705,46 @@ private: bool m_terminate_path; }; +/* A subclass of pending_diagnostic for complaining about jumps through NULL + function pointers. */ + +class jump_through_null : public pending_diagnostic_subclass<jump_through_null> +{ +public: + jump_through_null (const gcall *call) + : m_call (call) + {} + + const char *get_kind () const final override + { + return "jump_through_null"; + } + + bool operator== (const jump_through_null &other) const + { + return m_call == other.m_call; + } + + int get_controlling_option () const final override + { + return OPT_Wanalyzer_jump_through_null; + } + + bool emit (rich_location *rich_loc) final override + { + return warning_at (rich_loc, get_controlling_option (), + "jump through null pointer"); + } + + label_text describe_final_event (const evdesc::final_event &ev) final override + { + return ev.formatted_print ("jump through null pointer here"); + } + +private: + const gcall *m_call; +}; + /* The core of exploded_graph::process_worklist (the main analysis loop), handling one node in the worklist. @@ -4046,6 +4086,15 @@ exploded_graph::process_node (exploded_node *node) logger); if (!call_discovered) { + /* Check for jump through NULL. */ + if (tree fn_ptr = gimple_call_fn (call)) + { + const svalue *fn_ptr_sval + = model->get_rvalue (fn_ptr, &ctxt); + if (fn_ptr_sval->all_zeroes_p ()) + ctxt.warn (new jump_through_null (call)); + } + /* An unknown function or a special function was called at this point, in such case, don't terminate the analysis of the current function. diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index ed923ad..8bb76d7 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -69,6 +69,14 @@ enum access_directions DIRS_WRITE }; +/* An enum for distinguishing between dup, dup2 and dup3. */ +enum dup +{ + DUP_1, + DUP_2, + DUP_3 +}; + class fd_state_machine : public state_machine { public: @@ -114,7 +122,9 @@ public: bool is_readonly_fd_p (state_t s) const; bool is_writeonly_fd_p (state_t s) const; enum access_mode get_access_mode_from_flag (int flag) const; - + /* Function for one-to-one correspondence between valid + and unchecked states. */ + state_t valid_to_unchecked_state (state_t state) const; /* State for a constant file descriptor (>= 0) */ state_t m_constant_fd; @@ -147,6 +157,8 @@ public: private: void on_open (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, const gcall *call) const; + void on_creat (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, + const gcall *call) const; void on_close (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, const gcall *call) const; void on_read (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, @@ -170,6 +182,9 @@ private: const gimple *stmt, const gcall *call, const tree callee_fndecl, const char *attr_name, access_directions fd_attr_access_dir) const; + void check_for_dup (sm_context *sm_ctxt, const supernode *node, + const gimple *stmt, const gcall *call, const tree callee_fndecl, + enum dup kind) const; }; /* Base diagnostic class relative to fd_state_machine. */ @@ -723,6 +738,20 @@ fd_state_machine::is_constant_fd_p (state_t state) const return (state == m_constant_fd); } +fd_state_machine::state_t +fd_state_machine::valid_to_unchecked_state (state_t state) const +{ + if (state == m_valid_read_write) + return m_unchecked_read_write; + else if (state == m_valid_write_only) + return m_unchecked_write_only; + else if (state == m_valid_read_only) + return m_unchecked_read_only; + else + gcc_unreachable (); + return NULL; +} + bool fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node, const gimple *stmt) const @@ -736,6 +765,11 @@ fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node, return true; } // "open" + if (is_named_call_p (callee_fndecl, "creat", call, 2)) + { + on_creat (sm_ctxt, node, stmt, call); + } // "creat" + if (is_named_call_p (callee_fndecl, "close", call, 1)) { on_close (sm_ctxt, node, stmt, call); @@ -754,6 +788,23 @@ fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node, return true; } // "read" + if (is_named_call_p (callee_fndecl, "dup", call, 1)) + { + check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1); + return true; + } + + if (is_named_call_p (callee_fndecl, "dup2", call, 2)) + { + check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2); + return true; + } + + if (is_named_call_p (callee_fndecl, "dup3", call, 3)) + { + check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3); + return true; + } { // Handle __attribute__((fd_arg)) @@ -900,6 +951,78 @@ fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node, } void +fd_state_machine::on_creat (sm_context *sm_ctxt, const supernode *node, + const gimple *stmt, const gcall *call) const +{ + tree lhs = gimple_call_lhs (call); + if (lhs) + sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked_write_only); + else + sm_ctxt->warn (node, stmt, NULL_TREE, new fd_leak (*this, NULL_TREE)); +} + +void +fd_state_machine::check_for_dup (sm_context *sm_ctxt, const supernode *node, + const gimple *stmt, const gcall *call, + const tree callee_fndecl, enum dup kind) const +{ + tree lhs = gimple_call_lhs (call); + tree arg_1 = gimple_call_arg (call, 0); + state_t state_arg_1 = sm_ctxt->get_state (stmt, arg_1); + if (state_arg_1 == m_stop) + return; + if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1))) + { + check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, + DIRS_READ_WRITE); + if (kind == DUP_1) + return; + } + switch (kind) + { + case DUP_1: + if (lhs) + { + if (is_constant_fd_p (state_arg_1)) + sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write); + else + sm_ctxt->set_next_state (stmt, lhs, + valid_to_unchecked_state (state_arg_1)); + } + break; + + case DUP_2: + case DUP_3: + tree arg_2 = gimple_call_arg (call, 1); + state_t state_arg_2 = sm_ctxt->get_state (stmt, arg_2); + tree diag_arg_2 = sm_ctxt->get_diagnostic_tree (arg_2); + if (state_arg_2 == m_stop) + return; + /* Check if -1 was passed as second argument to dup2. */ + if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2))) + { + sm_ctxt->warn ( + node, stmt, arg_2, + new fd_use_without_check (*this, diag_arg_2, callee_fndecl)); + return; + } + /* dup2 returns value of its second argument on success.But, the + access mode of the returned file descriptor depends on the duplicated + file descriptor i.e the first argument. */ + if (lhs) + { + if (is_constant_fd_p (state_arg_1)) + sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write); + else + sm_ctxt->set_next_state (stmt, lhs, + valid_to_unchecked_state (state_arg_1)); + } + + break; + } +} + +void fd_state_machine::on_close (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, const gcall *call) const { @@ -964,6 +1087,8 @@ fd_state_machine::check_for_open_fd ( } switch (callee_fndecl_dir) { + case DIRS_READ_WRITE: + break; case DIRS_READ: if (is_writeonly_fd_p (state)) { @@ -984,8 +1109,6 @@ fd_state_machine::check_for_open_fd ( *this, diag_arg, DIRS_READ, callee_fndecl)); } break; - default: - gcc_unreachable (); } } } diff --git a/gcc/btfout.cc b/gcc/btfout.cc index 31af505..997a33f 100644 --- a/gcc/btfout.cc +++ b/gcc/btfout.cc @@ -463,6 +463,7 @@ btf_dtd_emit_preprocess_cb (ctf_container_ref ctfc, ctf_dtdef_ref dtd) ctf_dtdef_ref func_dtd = ggc_cleared_alloc<ctf_dtdef_t> (); func_dtd->dtd_data = dtd->dtd_data; func_dtd->dtd_data.ctti_type = dtd->dtd_type; + func_dtd->linkage = dtd->linkage; vec_safe_push (funcs, func_dtd); num_types_created++; @@ -740,7 +741,10 @@ static void btf_asm_func_type (ctf_dtdef_ref dtd) { dw2_asm_output_data (4, dtd->dtd_data.ctti_name, "btt_name"); - dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_FUNC, 0, 0), "btt_info"); + dw2_asm_output_data (4, BTF_TYPE_INFO (BTF_KIND_FUNC, 0, + dtd->linkage), + "btt_info: kind=%u, kflag=%u, linkage=%u", + BTF_KIND_FUNC, 0, dtd->linkage); dw2_asm_output_data (4, get_btf_id (dtd->dtd_data.ctti_type), "btt_type"); } @@ -914,6 +918,10 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref dtd) if (dtd->dtd_data.ctti_size < 1) break; + /* In BTF the CHAR `encoding' seems to not be used, so clear it + here. */ + dtd->dtd_u.dtu_enc.cte_format &= ~BTF_INT_CHAR; + encoding = BTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format, dtd->dtd_u.dtu_enc.cte_offset, dtd->dtd_u.dtu_enc.cte_bits); diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 3aa672b..cffb462 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,10 @@ +2022-08-01 David Malcolm <dmalcolm@redhat.com> + + * c-typeck.cc (build_c_cast): Quote names of address spaces in + diagnostics. + (convert_for_assignment): Add a note to address space mismatch + diagnostics, specifying the expected and actual types. + 2022-07-10 Lewis Hyatt <lhyatt@gmail.com> PR preprocessor/97498 diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index fd0a7f8..8514488 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -6032,18 +6032,18 @@ build_c_cast (location_t loc, tree type, tree expr) if (!addr_space_superset (as_to, as_from, &as_common)) { if (ADDR_SPACE_GENERIC_P (as_from)) - warning_at (loc, 0, "cast to %s address space pointer " + warning_at (loc, 0, "cast to %qs address space pointer " "from disjoint generic address space pointer", c_addr_space_name (as_to)); else if (ADDR_SPACE_GENERIC_P (as_to)) warning_at (loc, 0, "cast to generic address space pointer " - "from disjoint %s address space pointer", + "from disjoint %qs address space pointer", c_addr_space_name (as_from)); else - warning_at (loc, 0, "cast to %s address space pointer " - "from disjoint %s address space pointer", + warning_at (loc, 0, "cast to %qs address space pointer " + "from disjoint %qs address space pointer", c_addr_space_name (as_to), c_addr_space_name (as_from)); } @@ -7252,6 +7252,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, if (!null_pointer_constant_p (rhs) && asr != asl && !targetm.addr_space.subset_p (asr, asl)) { + auto_diagnostic_group d; + bool diagnosed = true; switch (errtype) { case ic_argpass: @@ -7259,7 +7261,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, const char msg[] = G_("passing argument %d of %qE from " "pointer to non-enclosed address space"); if (warnopt) - warning_at (expr_loc, warnopt, msg, parmnum, rname); + diagnosed + = warning_at (expr_loc, warnopt, msg, parmnum, rname); else error_at (expr_loc, msg, parmnum, rname); break; @@ -7269,7 +7272,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, const char msg[] = G_("assignment from pointer to " "non-enclosed address space"); if (warnopt) - warning_at (location, warnopt, msg); + diagnosed = warning_at (location, warnopt, msg); else error_at (location, msg); break; @@ -7280,7 +7283,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, const char msg[] = G_("initialization from pointer to " "non-enclosed address space"); if (warnopt) - warning_at (location, warnopt, msg); + diagnosed = warning_at (location, warnopt, msg); else error_at (location, msg); break; @@ -7290,7 +7293,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, const char msg[] = G_("return from pointer to " "non-enclosed address space"); if (warnopt) - warning_at (location, warnopt, msg); + diagnosed = warning_at (location, warnopt, msg); else error_at (location, msg); break; @@ -7298,6 +7301,14 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, default: gcc_unreachable (); } + if (diagnosed) + { + if (errtype == ic_argpass) + inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype); + else + inform (location, "expected %qT but pointer is of type %qT", + type, rhstype); + } return error_mark_node; } diff --git a/gcc/cfgcleanup.cc b/gcc/cfgcleanup.cc index 18047da..a8b0139 100644 --- a/gcc/cfgcleanup.cc +++ b/gcc/cfgcleanup.cc @@ -208,7 +208,7 @@ mark_effect (rtx exp, regset nonequal) return false; case SET: - if (rtx_equal_for_cselib_p (SET_DEST (exp), SET_SRC (exp))) + if (cselib_redundant_set_p (exp)) return false; dest = SET_DEST (exp); if (dest == pc_rtx) diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc index e4cc4a3..5e3a7ff 100644 --- a/gcc/config/i386/i386-features.cc +++ b/gcc/config/i386/i386-features.cc @@ -1221,6 +1221,13 @@ timode_scalar_chain::compute_convert_gain () igain = COSTS_N_INSNS (1); break; + case ASHIFT: + case LSHIFTRT: + /* For logical shifts by constant multiples of 8. */ + igain = optimize_insn_for_size_p () ? COSTS_N_BYTES (4) + : COSTS_N_INSNS (1); + break; + default: break; } @@ -1353,8 +1360,15 @@ timode_scalar_chain::convert_insn (rtx_insn *insn) if (GET_MODE (dst) == V1TImode) { tmp = find_reg_equal_equiv_note (insn); - if (tmp && GET_MODE (XEXP (tmp, 0)) == TImode) - PUT_MODE (XEXP (tmp, 0), V1TImode); + if (tmp) + { + if (GET_MODE (XEXP (tmp, 0)) == TImode) + PUT_MODE (XEXP (tmp, 0), V1TImode); + else if (CONST_SCALAR_INT_P (XEXP (tmp, 0))) + XEXP (tmp, 0) + = gen_rtx_CONST_VECTOR (V1TImode, + gen_rtvec (1, XEXP (tmp, 0))); + } } break; case MEM: @@ -1462,6 +1476,12 @@ timode_scalar_chain::convert_insn (rtx_insn *insn) src = convert_compare (XEXP (src, 0), XEXP (src, 1), insn); break; + case ASHIFT: + case LSHIFTRT: + convert_op (&XEXP (src, 0), insn); + PUT_MODE (src, V1TImode); + break; + default: gcc_unreachable (); } @@ -1796,6 +1816,14 @@ timode_scalar_to_vector_candidate_p (rtx_insn *insn) case NOT: return REG_P (XEXP (src, 0)) || timode_mem_p (XEXP (src, 0)); + case ASHIFT: + case LSHIFTRT: + /* Handle logical shifts by integer constants between 0 and 120 + that are multiples of 8. */ + return REG_P (XEXP (src, 0)) + && CONST_INT_P (XEXP (src, 1)) + && (INTVAL (XEXP (src, 1)) & ~0x78) == 0; + default: return false; } diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index e03f86d..5e30dc8 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -16070,6 +16070,19 @@ ix86_call_use_plt_p (rtx call_op) return true; } +/* Implement TARGET_IFUNC_REF_LOCAL_OK. If this hook returns true, + the PLT entry will be used as the function address for local IFUNC + functions. When the PIC register is needed for PLT call, indirect + call via the PLT entry will fail since the PIC register may not be + set up properly for indirect call. In this case, we should return + false. */ + +static bool +ix86_ifunc_ref_local_ok (void) +{ + return !flag_pic || (TARGET_64BIT && ix86_cmodel != CM_LARGE_PIC); +} + /* Return true if the function being called was marked with attribute "noplt" or using -fno-plt and we are compiling for non-PIC. We need to handle the non-PIC case in the backend because there is no easy @@ -24953,7 +24966,7 @@ ix86_libgcc_floating_mode_supported_p ix86_get_multilib_abi_name #undef TARGET_IFUNC_REF_LOCAL_OK -#define TARGET_IFUNC_REF_LOCAL_OK hook_bool_void_true +#define TARGET_IFUNC_REF_LOCAL_OK ix86_ifunc_ref_local_ok #if !TARGET_MACHO && !TARGET_DLLIMPORT_DECL_ATTRIBUTES # undef TARGET_ASM_RELOC_RW_MASK diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index f1158e1..fd30c57 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1510,7 +1510,7 @@ (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_hilo_general_operand")))] + (match_operand:<DWI> 1 "general_operand")))] "ix86_pre_reload_split ()" "#" "&& 1" @@ -1526,6 +1526,15 @@ operands[i] = force_reg (<MODE>mode, operands[i]); operands[4] = gen_reg_rtx (<MODE>mode); + + /* Special case comparisons against -1. */ + if (operands[1] == constm1_rtx && operands[3] == constm1_rtx) + { + emit_insn (gen_and<mode>3 (operands[4], operands[0], operands[2])); + emit_insn (gen_cmp_1 (<MODE>mode, operands[4], constm1_rtx)); + DONE; + } + if (operands[1] == const0_rtx) emit_move_insn (operands[4], operands[0]); else if (operands[0] == const0_rtx) @@ -1535,7 +1544,12 @@ 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 (CONST_SCALAR_INT_P (operands[1]) + && !x86_64_immediate_operand (operands[1], <MODE>mode)) + operands[1] = force_reg (<MODE>mode, operands[1]); + emit_insn (gen_xor<mode>3 (operands[4], operands[0], operands[1])); + } if (operands[3] == const0_rtx) operands[5] = operands[2]; @@ -1549,7 +1563,12 @@ 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])); + { + if (CONST_SCALAR_INT_P (operands[3]) + && !x86_64_immediate_operand (operands[3], <MODE>mode)) + operands[3] = force_reg (<MODE>mode, operands[3]); + emit_insn (gen_xor<mode>3 (operands[5], operands[2], operands[3])); + } } }) @@ -3018,6 +3037,18 @@ [(parallel [(set (match_dup 1) (match_dup 2)) (set (match_dup 2) (match_dup 1))])]) +;; Convert moves to/from AX_REG into xchg with -Oz. +(define_peephole2 + [(set (match_operand:SWI48 0 "general_reg_operand") + (match_operand:SWI48 1 "general_reg_operand"))] + "optimize_size > 1 + && (REGNO (operands[0]) == AX_REG + || REGNO (operands[1]) == AX_REG) + && optimize_insn_for_size_p () + && peep2_reg_dead_p (1, operands[1])" + [(parallel [(set (match_dup 0) (match_dup 1)) + (set (match_dup 1) (match_dup 0))])]) + (define_expand "movstrict<mode>" [(set (strict_low_part (match_operand:SWI12 0 "register_operand")) (match_operand:SWI12 1 "general_operand"))] diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index 90db5df..e98db2c 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -76,7 +76,7 @@ /* Check whether the constant can be loaded in a single instruction with zbs extensions. */ - if (TARGET_64BIT && TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (INTVAL (op))) + if (TARGET_ZBS && SINGLE_BIT_MASK_OPERAND (INTVAL (op))) return false; /* Otherwise check whether the constant can be loaded in a single diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 4b727d2..df491be 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -4094,17 +4094,6 @@ rs6000_option_override_internal (bool global_init_p) rs6000_isa_flags &= ~OPTION_MASK_BLOCK_OPS_UNALIGNED_VSX; } - if (!(rs6000_isa_flags_explicit & OPTION_MASK_BLOCK_OPS_VECTOR_PAIR)) - { - /* Do not generate lxvp and stxvp on power10 since there are some - performance issues. */ - if (TARGET_MMA && TARGET_EFFICIENT_UNALIGNED_VSX - && rs6000_tune != PROCESSOR_POWER10) - rs6000_isa_flags |= OPTION_MASK_BLOCK_OPS_VECTOR_PAIR; - else - rs6000_isa_flags &= ~OPTION_MASK_BLOCK_OPS_VECTOR_PAIR; - } - /* Use long double size to select the appropriate long double. We use TYPE_PRECISION to differentiate the 3 different long double types. We map 128 into the precision used for TFmode. */ diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md index a6c4b4e..6247298 100644 --- a/gcc/config/s390/vector.md +++ b/gcc/config/s390/vector.md @@ -63,6 +63,12 @@ V1DF V2DF (V1TF "TARGET_VXE") (TF "TARGET_VXE")]) +; All modes present in V_HW and VFT. +(define_mode_iterator V_HW_FT [V16QI V8HI V4SI V2DI (V1TI "TARGET_VXE") V1DF + V2DF (V1SF "TARGET_VXE") (V2SF "TARGET_VXE") + (V4SF "TARGET_VXE") (V1TF "TARGET_VXE") + (TF "TARGET_VXE")]) + ; FP vector modes directly supported by the HW. This does not include ; vector modes using only part of a vector register and should be used ; for instructions which might trigger IEEE exceptions. diff --git a/gcc/config/s390/vx-builtins.md b/gcc/config/s390/vx-builtins.md index d513079..98ee08b 100644 --- a/gcc/config/s390/vx-builtins.md +++ b/gcc/config/s390/vx-builtins.md @@ -517,12 +517,12 @@ ; swapped in s390-c.cc when we get here. (define_insn "vsel<mode>" - [(set (match_operand:V_HW 0 "register_operand" "=v") - (ior:V_HW - (and:V_HW (match_operand:V_HW 1 "register_operand" "v") - (match_operand:V_HW 3 "register_operand" "v")) - (and:V_HW (not:V_HW (match_dup 3)) - (match_operand:V_HW 2 "register_operand" "v"))))] + [(set (match_operand:V_HW_FT 0 "register_operand" "=v") + (ior:V_HW_FT + (and:V_HW_FT (match_operand:V_HW_FT 1 "register_operand" "v") + (match_operand:V_HW_FT 3 "register_operand" "v")) + (and:V_HW_FT (not:V_HW_FT (match_dup 3)) + (match_operand:V_HW_FT 2 "register_operand" "v"))))] "TARGET_VX" "vsel\t%v0,%1,%2,%3" [(set_attr "op_type" "VRR")]) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 4d7761c2..ed83b97 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2022-08-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/88174 + * constexpr.cc (cxx_eval_store_expression): Handle REALPART_EXPR + and IMAGPART_EXPR. Change ctors from releasing_vec to + auto_vec<tree *>, adjust all uses. For !preeval, update ctors + vector. + 2022-07-31 Lewis Hyatt <lhyatt@gmail.com> PR c++/66290 diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 5e0d339..c047fe4 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -5732,6 +5732,20 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, } break; + case REALPART_EXPR: + gcc_assert (probe == target); + vec_safe_push (refs, probe); + vec_safe_push (refs, TREE_TYPE (probe)); + probe = TREE_OPERAND (probe, 0); + break; + + case IMAGPART_EXPR: + gcc_assert (probe == target); + vec_safe_push (refs, probe); + vec_safe_push (refs, TREE_TYPE (probe)); + probe = TREE_OPERAND (probe, 0); + break; + default: if (evaluated) object = probe; @@ -5770,7 +5784,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, type = TREE_TYPE (object); bool no_zero_init = true; - releasing_vec ctors, indexes; + auto_vec<tree *> ctors; + releasing_vec indexes; auto_vec<int> index_pos_hints; bool activated_union_member_p = false; bool empty_base = false; @@ -5810,14 +5825,36 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, *valp = ary_ctor; } - /* If the value of object is already zero-initialized, any new ctors for - subobjects will also be zero-initialized. */ - no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp); - enum tree_code code = TREE_CODE (type); tree reftype = refs->pop(); tree index = refs->pop(); + if (code == COMPLEX_TYPE) + { + if (TREE_CODE (*valp) == COMPLEX_CST) + *valp = build2 (COMPLEX_EXPR, type, TREE_REALPART (*valp), + TREE_IMAGPART (*valp)); + else if (TREE_CODE (*valp) == CONSTRUCTOR + && CONSTRUCTOR_NELTS (*valp) == 0 + && CONSTRUCTOR_NO_CLEARING (*valp)) + { + tree r = build_constructor (reftype, NULL); + CONSTRUCTOR_NO_CLEARING (r) = 1; + *valp = build2 (COMPLEX_EXPR, type, r, r); + } + gcc_assert (TREE_CODE (*valp) == COMPLEX_EXPR); + ctors.safe_push (valp); + vec_safe_push (indexes, index); + valp = &TREE_OPERAND (*valp, TREE_CODE (index) == IMAGPART_EXPR); + gcc_checking_assert (refs->is_empty ()); + type = reftype; + break; + } + + /* If the value of object is already zero-initialized, any new ctors for + subobjects will also be zero-initialized. */ + no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp); + if (code == RECORD_TYPE && is_empty_field (index)) /* Don't build a sub-CONSTRUCTOR for an empty base or field, as they have no data and might have an offset lower than previously declared @@ -5860,7 +5897,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, no_zero_init = true; } - vec_safe_push (ctors, *valp); + ctors.safe_push (valp); vec_safe_push (indexes, index); constructor_elt *cep @@ -5922,11 +5959,11 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, semantics are not applied on an object under construction. They come into effect when the constructor for the most derived object ends." */ - for (tree elt : *ctors) + for (tree *elt : ctors) if (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (const_object_being_modified), TREE_TYPE (elt))) + (TREE_TYPE (const_object_being_modified), TREE_TYPE (*elt))) { - fail = TREE_READONLY (elt); + fail = TREE_READONLY (*elt); break; } } @@ -5967,6 +6004,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, valp = ctx->global->values.get (object); for (unsigned i = 0; i < vec_safe_length (indexes); i++) { + ctors[i] = valp; constructor_elt *cep = get_or_insert_ctor_field (*valp, indexes[i], index_pos_hints[i]); valp = &cep->value; @@ -6029,17 +6067,45 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTORs, if any. */ bool c = TREE_CONSTANT (init); bool s = TREE_SIDE_EFFECTS (init); + if (!indexes->is_empty ()) + { + tree last = indexes->last (); + if (TREE_CODE (last) == REALPART_EXPR + || TREE_CODE (last) == IMAGPART_EXPR) + { + /* And canonicalize COMPLEX_EXPR into COMPLEX_CST if + possible. */ + tree *cexpr = ctors.last (); + if (tree c = const_binop (COMPLEX_EXPR, TREE_TYPE (*cexpr), + TREE_OPERAND (*cexpr, 0), + TREE_OPERAND (*cexpr, 1))) + *cexpr = c; + else + { + TREE_CONSTANT (*cexpr) + = (TREE_CONSTANT (TREE_OPERAND (*cexpr, 0)) + & TREE_CONSTANT (TREE_OPERAND (*cexpr, 1))); + TREE_SIDE_EFFECTS (*cexpr) + = (TREE_SIDE_EFFECTS (TREE_OPERAND (*cexpr, 0)) + | TREE_SIDE_EFFECTS (TREE_OPERAND (*cexpr, 1))); + } + c = TREE_CONSTANT (*cexpr); + s = TREE_SIDE_EFFECTS (*cexpr); + } + } if (!c || s || activated_union_member_p) - for (tree elt : *ctors) + for (tree *elt : ctors) { + if (TREE_CODE (*elt) != CONSTRUCTOR) + continue; if (!c) - TREE_CONSTANT (elt) = false; + TREE_CONSTANT (*elt) = false; if (s) - TREE_SIDE_EFFECTS (elt) = true; + TREE_SIDE_EFFECTS (*elt) = true; /* Clear CONSTRUCTOR_NO_CLEARING since we've activated a member of this union. */ - if (TREE_CODE (TREE_TYPE (elt)) == UNION_TYPE) - CONSTRUCTOR_NO_CLEARING (elt) = false; + if (TREE_CODE (TREE_TYPE (*elt)) == UNION_TYPE) + CONSTRUCTOR_NO_CLEARING (*elt) = false; } if (lval) diff --git a/gcc/cselib.cc b/gcc/cselib.cc index 6769bee..6a56097 100644 --- a/gcc/cselib.cc +++ b/gcc/cselib.cc @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "cselib.h" #include "function-abi.h" +#include "alias.h" /* A list of cselib_val structures. */ struct elt_list @@ -1157,6 +1158,75 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, machine_mode memmode, int depth) return 1; } +/* Wrapper for rtx_equal_for_cselib_p to determine whether a SET is + truly redundant, taking into account aliasing information. */ +bool +cselib_redundant_set_p (rtx set) +{ + gcc_assert (GET_CODE (set) == SET); + rtx dest = SET_DEST (set); + if (cselib_reg_set_mode (dest) != GET_MODE (dest)) + return false; + + if (!rtx_equal_for_cselib_p (dest, SET_SRC (set))) + return false; + + while (GET_CODE (dest) == SUBREG + || GET_CODE (dest) == ZERO_EXTRACT + || GET_CODE (dest) == STRICT_LOW_PART) + dest = XEXP (dest, 0); + + if (!flag_strict_aliasing || !MEM_P (dest)) + return true; + + /* For a store we need to check that suppressing it will not change + the effective alias set. */ + rtx dest_addr = XEXP (dest, 0); + + /* Lookup the equivalents to the original dest (rather than just the + MEM). */ + cselib_val *src_val = cselib_lookup (SET_DEST (set), + GET_MODE (SET_DEST (set)), + 0, VOIDmode); + + if (src_val) + { + /* Walk the list of source equivalents to find the MEM accessing + the same location. */ + for (elt_loc_list *l = src_val->locs; l; l = l->next) + { + rtx src_equiv = l->loc; + while (GET_CODE (src_equiv) == SUBREG + || GET_CODE (src_equiv) == ZERO_EXTRACT + || GET_CODE (src_equiv) == STRICT_LOW_PART) + src_equiv = XEXP (src_equiv, 0); + + if (MEM_P (src_equiv)) + { + /* Match the MEMs by comparing the addresses. We can + only remove the later store if the earlier aliases at + least all the accesses of the later one. */ + if (rtx_equal_for_cselib_1 (dest_addr, XEXP (src_equiv, 0), + GET_MODE (dest), 0)) + return mems_same_for_tbaa_p (src_equiv, dest); + } + } + } + + /* We failed to find a recorded value in the cselib history, so try + the source of this set; this catches cases such as *p = *q when p + and q have the same value. */ + rtx src = SET_SRC (set); + while (GET_CODE (src) == SUBREG) + src = XEXP (src, 0); + + if (MEM_P (src) + && rtx_equal_for_cselib_1 (dest_addr, XEXP (src, 0), GET_MODE (dest), 0)) + return mems_same_for_tbaa_p (src, dest); + + return false; +} + /* Helper function for cselib_hash_rtx. Arguments like for cselib_hash_rtx, except that it hashes (plus:P x c). */ diff --git a/gcc/cselib.h b/gcc/cselib.h index 9ae65e6..b090505 100644 --- a/gcc/cselib.h +++ b/gcc/cselib.h @@ -83,6 +83,7 @@ extern void cselib_process_insn (rtx_insn *); extern bool fp_setter_insn (rtx_insn *); extern machine_mode cselib_reg_set_mode (const_rtx); extern int rtx_equal_for_cselib_1 (rtx, rtx, machine_mode, int); +extern bool cselib_redundant_set_p (rtx); extern int references_value_p (const_rtx, int); extern rtx cselib_expand_value_rtx (rtx, bitmap, int); typedef rtx (*cselib_expand_callback)(rtx, bitmap, int, void *); diff --git a/gcc/ctfc.cc b/gcc/ctfc.cc index f24e7bf..9773358 100644 --- a/gcc/ctfc.cc +++ b/gcc/ctfc.cc @@ -777,7 +777,7 @@ ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func, ctf_id_t ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name, const ctf_funcinfo_t * ctc, dw_die_ref die, - bool from_global_func) + bool from_global_func, int linkage) { ctf_dtdef_ref dtd; ctf_id_t type; @@ -791,6 +791,7 @@ ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name, type = ctf_add_generic (ctfc, flag, name, &dtd, die); dtd->from_global_func = from_global_func; + dtd->linkage = linkage; dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen); /* Caller must make sure CTF types for ctc->ctc_return are already added. */ dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return; @@ -161,6 +161,7 @@ struct GTY ((for_user)) ctf_dtdef ctf_itype_t dtd_data; /* Type node. */ bool from_global_func; /* Whether this type was added from a global function. */ + uint32_t linkage; /* Used in function types. 0=local, 1=global. */ union GTY ((desc ("ctf_dtu_d_union_selector (&%1)"))) { /* struct, union, or enum. */ @@ -423,7 +424,7 @@ extern ctf_id_t ctf_add_forward (ctf_container_ref, uint32_t, const char *, extern ctf_id_t ctf_add_typedef (ctf_container_ref, uint32_t, const char *, ctf_id_t, dw_die_ref); extern ctf_id_t ctf_add_function (ctf_container_ref, uint32_t, const char *, - const ctf_funcinfo_t *, dw_die_ref, bool); + const ctf_funcinfo_t *, dw_die_ref, bool, int); extern ctf_id_t ctf_add_sou (ctf_container_ref, uint32_t, const char *, uint32_t, size_t, dw_die_ref); diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index f1d1f00..41e2809 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,18 @@ +2022-08-03 Iain Buclaw <ibuclaw@gdcproject.org> + + * dmd/MERGE: Merge upstream dmd d7772a2369. + * dmd/VERSION: Bump version to v2.100.1. + * d-codegen.cc (get_frameinfo): Check whether decision to generate + closure changed since semantic finished. + * d-lang.cc (d_handle_option): Remove handling of -fdebug=level and + -fversion=level. + * decl.cc (DeclVisitor::visit (VarDeclaration *)): Generate evaluation + of noreturn variable initializers before throw. + * expr.cc (ExprVisitor::visit (AssignExp *)): Don't generate + assignment for noreturn types, only evaluate for side effects. + * lang.opt (fdebug=): Undocument -fdebug=level. + (fversion=): Undocument -fversion=level. + 2022-07-06 Iain Buclaw <ibuclaw@gdcproject.org> * dmd/MERGE: Merge upstream dmd 56589f0f4. diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2d90899..3fd4bee 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2826,8 +2826,15 @@ get_frameinfo (FuncDeclaration *fd) DECL_LANG_FRAMEINFO (fds) = ffi; + const bool requiresClosure = fd->requiresClosure; if (fd->needsClosure ()) { + /* This can shift due to templates being expanded that access alias + symbols, give it a decent error for now. */ + if (requiresClosure != fd->requiresClosure + && (fd->nrvo_var || global.params.betterC)) + fd->checkClosure (); + /* Set-up a closure frame, this will be allocated on the heap. */ FRAMEINFO_CREATES_FRAME (ffi) = 1; FRAMEINFO_IS_CLOSURE (ffi) = 1; diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 6e4350f..04147ed 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -456,16 +456,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fdebug_: - if (ISDIGIT (arg[0])) - { - int level = integral_argument (arg); - if (level != -1) - { - global.params.debuglevel = level; - break; - } - } - if (Identifier::isValidIdentifier (CONST_CAST (char *, arg))) { if (!global.params.debugids) @@ -713,16 +703,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fversion_: - if (ISDIGIT (arg[0])) - { - int level = integral_argument (arg); - if (level != -1) - { - global.params.versionlevel = level; - break; - } - } - if (Identifier::isValidIdentifier (CONST_CAST (char *, arg))) { if (!global.params.versionids) diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 3caa465..58cea4d 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -646,9 +646,12 @@ public: if (!d->isDataseg () && !d->isMember () && d->_init && !d->_init->isVoidInitializer ()) { + /* Evaluate RHS for side effects first. */ + Expression *ie = initializerToExpression (d->_init); + add_stmt (build_expr (ie)); + Expression *e = d->type->defaultInitLiteral (d->loc); - tree exp = build_expr (e); - add_stmt (exp); + add_stmt (build_expr (e)); } return; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 8324c1c..c358b69 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -56589f0f4d724c1c8022c57509a243f16a04228a +d7772a236983ec37b92d21b28bad3cd2de57b945 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 5ea2ba0..83a14f5 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.100.0 +v2.100.1 diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index 16cbe62..272e751 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -111,8 +111,8 @@ bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false) * evaluation order as the actual array operations have no * side-effect. * References: - * https://github.com/dlang/druntime/blob/master/src/object.d#L3944 - * https://github.com/dlang/druntime/blob/master/src/core/internal/array/operations.d + * https://github.com/dlang/dmd/blob/cdfadf8a18f474e6a1b8352af2541efe3e3467cc/druntime/src/object.d#L4694 + * https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/array/operations.d */ Expression arrayOp(BinExp e, Scope* sc) { diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index a3f3bc4..e118d70 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -62,7 +62,7 @@ import dmd.target; bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list) { //printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr); - size_t n, gnu_m_count; // index in args / number of Format.GNU_m + size_t n; // index in args for (size_t i = 0; i < format.length;) { if (format[i] != '%') @@ -79,6 +79,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre if (fmt == Format.percent) continue; // "%%", no arguments + if (fmt == Format.GNU_m) + continue; // "%m", no arguments if (isVa_list) { @@ -88,14 +90,11 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre continue; } - if (fmt == Format.GNU_m) - ++gnu_m_count; - Expression getNextArg(ref bool skip) { if (n == args.length) { - if (args.length < (n + 1) - gnu_m_count) + if (args.length < (n + 1)) deprecation(loc, "more format specifiers than %d arguments", cast(int)n); else skip = true; @@ -207,7 +206,6 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre errorMsg(null, e, "ptrdiff_t", t); break; - case Format.GNU_a: // Format.GNU_a is only for scanf case Format.lg: case Format.g: // double if (t.ty != Tfloat64 && t.ty != Timaginary64) @@ -289,8 +287,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre break; case Format.GNU_m: - break; // not assert(0) because it may go through it if there are extra arguments - + case Format.POSIX_ms: + case Format.POSIX_mls: case Format.percent: assert(0); } @@ -481,8 +479,6 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres errorMsg(null, e, "real*", t); break; - case Format.GNU_a: - case Format.GNU_m: case Format.c: case Format.s: // pointer to char string if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8))) @@ -500,10 +496,23 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres errorMsg(null, e, "void**", t); break; + case Format.POSIX_ms: // pointer to pointer to char string + Type tnext2 = tnext ? tnext.nextOf() : null; + if (!(t.ty == Tpointer && tnext.ty == Tpointer && (tnext2.ty == Tchar || tnext2.ty == Tint8 || tnext2.ty == Tuns8))) + errorMsg(null, e, "char**", t); + break; + + case Format.POSIX_mls: // pointer to pointer to wchar_t string + Type tnext2 = tnext ? tnext.nextOf() : null; + if (!(t.ty == Tpointer && tnext.ty == Tpointer && tnext2.ty.isSomeChar && tnext2.size() == target.c.wchar_tsize)) + errorMsg(null, e, "wchar_t**", t); + break; + case Format.error: deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr); break; + case Format.GNU_m: case Format.percent: assert(0); } @@ -567,35 +576,97 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx, return error(); } - /* Read the scanset - * A scanset can be anything, so we just check that it is paired + /* Read the specifier */ - if (format[i] == '[') + Format specifier; + Modifier flags = Modifier.none; + switch (format[i]) { - while (i < length) - { - if (format[i] == ']') - break; + case 'm': + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/scanf.html + // POSIX.1-2017 C Extension (CX) + flags = Modifier.m; ++i; - } + if (i == length) + return error(); + if (format[i] == 'l') + { + ++i; + if (i == length) + return error(); + flags = Modifier.ml; + } - // no `]` found - if (i == length) - return error(); + // Check valid conversion types for %m. + if (format[i] == 'c' || format[i] == 's') + specifier = flags == Modifier.ml ? Format.POSIX_mls : + Format.POSIX_ms; + else if (format[i] == 'C' || format[i] == 'S') + specifier = flags == Modifier.m ? Format.POSIX_mls : + Format.error; + else if (format[i] == '[') + goto case '['; + else + specifier = Format.error; + ++i; + break; - ++i; - // no specifier after `]` - // it could be mixed with the one above, but then idx won't have the right index - if (i == length) - return error(); - } + case 'l': + // Look for wchar_t scanset %l[..] + immutable j = i + 1; + if (j < length && format[j] == '[') + { + i = j; + flags = Modifier.l; + goto case '['; + } + goto default; - /* Read the specifier - */ - char genSpec; - Format specifier = parseGenericFormatSpecifier(format, i, genSpec); - if (specifier == Format.error) - return error(); + case '[': + // Read the scanset + i++; + if (i == length) + return error(); + // If the conversion specifier begins with `[]` or `[^]`, the right + // bracket character is not the terminator, but in the scanlist. + if (format[i] == '^') + { + i++; + if (i == length) + return error(); + } + if (format[i] == ']') + { + i++; + if (i == length) + return error(); + } + // A scanset can be anything, so we just check that it is paired + while (i < length) + { + if (format[i] == ']') + break; + ++i; + } + // no `]` found + if (i == length) + return error(); + + specifier = flags == Modifier.none ? Format.s : + flags == Modifier.l ? Format.ls : + flags == Modifier.m ? Format.POSIX_ms : + flags == Modifier.ml ? Format.POSIX_mls : + Format.error; + ++i; + break; + + default: + char genSpec; + specifier = parseGenericFormatSpecifier(format, i, genSpec); + if (specifier == Format.error) + return error(); + break; + } idx = i; return specifier; // success @@ -613,11 +684,13 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx, * even if `Format.error` is returned * widthStar = set if * for width * precisionStar = set if * for precision + * useGNUExts = true if parsing GNU format extensions * Returns: * Format */ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, - out bool widthStar, out bool precisionStar) nothrow pure @safe + out bool widthStar, out bool precisionStar, bool useGNUExts = + findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @safe { auto i = idx; assert(format[i] == '%'); @@ -730,14 +803,33 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, /* Read the specifier */ char genSpec; - Format specifier = parseGenericFormatSpecifier(format, i, genSpec); - if (specifier == Format.error) - return error(); + Format specifier; + switch (format[i]) + { + case 'm': + // https://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html + if (useGNUExts) + { + specifier = Format.GNU_m; + genSpec = format[i]; + ++i; + break; + } + goto default; + + default: + specifier = parseGenericFormatSpecifier(format, i, genSpec); + if (specifier == Format.error) + return error(); + break; + } switch (genSpec) { case 'c': case 's': + case 'C': + case 'S': if (hash || zero) return error(); break; @@ -748,6 +840,11 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, return error(); break; + case 'm': + if (hash || zero || flags) + return error(); + break; + case 'n': if (hash || zero || precision || width || flags) return error(); @@ -761,6 +858,22 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx, return specifier; // success } +/* Different kinds of conversion modifiers. */ +enum Modifier +{ + none, + h, // short + hh, // char + j, // intmax_t + l, // wint_t/wchar_t + ll, // long long int + L, // long double + m, // char** + ml, // wchar_t** + t, // ptrdiff_t + z // size_t +} + /* Different kinds of formatting specifications, variations we don't care about are merged. (Like we don't care about the difference between f, e, g, a, etc.) @@ -799,8 +912,9 @@ enum Format jn, // pointer to intmax_t zn, // pointer to size_t tn, // pointer to ptrdiff_t - GNU_a, // GNU ext. : address to a string with no maximum size (scanf) - GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf) + GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) + POSIX_ms, // POSIX ext. : dynamically allocated char string (scanf) + POSIX_mls, // POSIX ext. : dynamically allocated wchar_t string (scanf) percent, // %% (i.e. no argument) error, // invalid format specification } @@ -820,38 +934,48 @@ enum Format * Format */ Format parseGenericFormatSpecifier(scope const char[] format, - ref size_t idx, out char genSpecifier, bool useGNUExts = - findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @trusted + ref size_t idx, out char genSpecifier) nothrow pure @safe { const length = format.length; /* Read the `length modifier` */ const lm = format[idx]; - bool lm1; // if jztL - bool lm2; // if `hh` or `ll` - if (lm == 'j' || - lm == 'z' || - lm == 't' || - lm == 'L') + Modifier flags; + switch (lm) { - ++idx; - if (idx == length) - return Format.error; - lm1 = true; - } - else if (lm == 'h' || lm == 'l') - { - ++idx; - if (idx == length) - return Format.error; - lm2 = lm == format[idx]; - if (lm2) - { + case 'j': + case 'z': + case 't': + case 'L': + flags = lm == 'j' ? Modifier.j : + lm == 'z' ? Modifier.z : + lm == 't' ? Modifier.t : + Modifier.L; ++idx; if (idx == length) return Format.error; - } + break; + + case 'h': + case 'l': + ++idx; + if (idx == length) + return Format.error; + if (lm == format[idx]) + { + flags = lm == 'h' ? Modifier.hh : Modifier.ll; + ++idx; + if (idx == length) + return Format.error; + } + else + flags = lm == 'h' ? Modifier.h : Modifier.l; + break; + + default: + flags = Modifier.none; + break; } /* Read the `specifier` @@ -863,103 +987,88 @@ Format parseGenericFormatSpecifier(scope const char[] format, { case 'd': case 'i': - if (lm == 'L') - specifier = Format.error; - else - specifier = lm == 'h' && lm2 ? Format.hhd : - lm == 'h' ? Format.hd : - lm == 'l' && lm2 ? Format.lld : - lm == 'l' ? Format.ld : - lm == 'j' ? Format.jd : - lm == 'z' ? Format.zd : - lm == 't' ? Format.td : - Format.d; + specifier = flags == Modifier.none ? Format.d : + flags == Modifier.hh ? Format.hhd : + flags == Modifier.h ? Format.hd : + flags == Modifier.ll ? Format.lld : + flags == Modifier.l ? Format.ld : + flags == Modifier.j ? Format.jd : + flags == Modifier.z ? Format.zd : + flags == Modifier.t ? Format.td : + Format.error; break; case 'u': case 'o': case 'x': case 'X': - if (lm == 'L') - specifier = Format.error; - else - specifier = lm == 'h' && lm2 ? Format.hhu : - lm == 'h' ? Format.hu : - lm == 'l' && lm2 ? Format.llu : - lm == 'l' ? Format.lu : - lm == 'j' ? Format.ju : - lm == 'z' ? Format.zd : - lm == 't' ? Format.td : - Format.u; + specifier = flags == Modifier.none ? Format.u : + flags == Modifier.hh ? Format.hhu : + flags == Modifier.h ? Format.hu : + flags == Modifier.ll ? Format.llu : + flags == Modifier.l ? Format.lu : + flags == Modifier.j ? Format.ju : + flags == Modifier.z ? Format.zd : + flags == Modifier.t ? Format.td : + Format.error; break; - case 'a': - if (useGNUExts) - { - // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html - specifier = Format.GNU_a; - break; - } - goto case; - case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': + case 'a': case 'A': - if (lm == 'L') - specifier = Format.Lg; - else if (lm1 || lm2 || lm == 'h') - specifier = Format.error; - else - specifier = lm == 'l' ? Format.lg : Format.g; + specifier = flags == Modifier.none ? Format.g : + flags == Modifier.L ? Format.Lg : + flags == Modifier.l ? Format.lg : + Format.error; break; case 'c': - if (lm1 || lm2 || lm == 'h') - specifier = Format.error; - else - specifier = lm == 'l' ? Format.lc : Format.c; + specifier = flags == Modifier.none ? Format.c : + flags == Modifier.l ? Format.lc : + Format.error; break; case 's': - if (lm1 || lm2 || lm == 'h') - specifier = Format.error; - else - specifier = lm == 'l' ? Format.ls : Format.s; + specifier = flags == Modifier.none ? Format.s : + flags == Modifier.l ? Format.ls : + Format.error; break; case 'p': - if (lm1 || lm2 || lm == 'h' || lm == 'l') - specifier = Format.error; - else - specifier = Format.p; + specifier = flags == Modifier.none ? Format.p : + Format.error; break; case 'n': - if (lm == 'L') - specifier = Format.error; - else - specifier = lm == 'l' && lm2 ? Format.lln : - lm == 'l' ? Format.ln : - lm == 'h' && lm2 ? Format.hhn : - lm == 'h' ? Format.hn : - lm == 'j' ? Format.jn : - lm == 'z' ? Format.zn : - lm == 't' ? Format.tn : - Format.n; + specifier = flags == Modifier.none ? Format.n : + flags == Modifier.ll ? Format.lln : + flags == Modifier.l ? Format.ln : + flags == Modifier.hh ? Format.hhn : + flags == Modifier.h ? Format.hn : + flags == Modifier.j ? Format.jn : + flags == Modifier.z ? Format.zn : + flags == Modifier.t ? Format.tn : + Format.error; break; - case 'm': - if (useGNUExts) - { - // https://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html - specifier = Format.GNU_m; - break; - } - goto default; + case 'C': + // POSIX.1-2017 X/Open System Interfaces (XSI) + // %C format is equivalent to %lc + specifier = flags == Modifier.none ? Format.lc : + Format.error; + break; + + case 'S': + // POSIX.1-2017 X/Open System Interfaces (XSI) + // %S format is equivalent to %ls + specifier = flags == Modifier.none ? Format.ls : + Format.error; + break; default: specifier = Format.error; @@ -1126,11 +1235,14 @@ unittest assert(idx == 2); idx = 0; - Format g = parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar); - assert(g == Format.g || g == Format.GNU_a); + assert(parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar) == Format.g); assert(idx == 2); idx = 0; + assert(parsePrintfFormatSpecifier("%La", idx, widthStar, precisionStar) == Format.Lg); + assert(idx == 3); + + idx = 0; assert(parsePrintfFormatSpecifier("%A", idx, widthStar, precisionStar) == Format.g); assert(idx == 2); @@ -1296,8 +1408,7 @@ unittest assert(idx == 2); idx = 0; - g = parseScanfFormatSpecifier("%a", idx, asterisk); - assert(g == Format.g || g == Format.GNU_a); + assert(parseScanfFormatSpecifier("%a", idx, asterisk) == Format.g); assert(idx == 2); idx = 0; @@ -1322,15 +1433,25 @@ unittest // scansets idx = 0; - assert(parseScanfFormatSpecifier("%[a-zA-Z]s", idx, asterisk) == Format.s); - assert(idx == 10); + assert(parseScanfFormatSpecifier("%[a-zA-Z]", idx, asterisk) == Format.s); + assert(idx == 9); assert(!asterisk); idx = 0; - assert(parseScanfFormatSpecifier("%*25[a-z]hhd", idx, asterisk) == Format.hhd); - assert(idx == 12); + assert(parseScanfFormatSpecifier("%*25l[a-z]", idx, asterisk) == Format.ls); + assert(idx == 10); assert(asterisk); + idx = 0; + assert(parseScanfFormatSpecifier("%[]]", idx, asterisk) == Format.s); + assert(idx == 4); + assert(!asterisk); + + idx = 0; + assert(parseScanfFormatSpecifier("%[^]]", idx, asterisk) == Format.s); + assert(idx == 5); + assert(!asterisk); + // Too short formats foreach (s; ["%", "% ", "%#", "%0", "%*", "%1", "%19", "%j", "%z", "%t", "%l", "%h", "%ll", "%hh", "%K"]) @@ -1354,11 +1475,108 @@ unittest } // Invalid scansets - foreach (s; ["%[]", "%[s", "%[0-9lld", "%[", "%[a-z]"]) + foreach (s; ["%[]", "%[^", "%[^]", "%[s", "%[0-9lld", "%[", "%l[^]"]) + { + idx = 0; + assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); + assert(idx == s.length); + } + + // Posix extensions + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%m", "%ma", "%md", "%ml", "%mm", "%mlb", "%mlj", "%mlr", "%mlz", + "%LC", "%lC", "%llC", "%jC", "%tC", "%hC", "%hhC", "%zC", + "%LS", "%lS", "%llS", "%jS", "%tS", "%hS", "%hhS", "%zS"]) { idx = 0; assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error); assert(idx == s.length); } + idx = 0; + assert(parseScanfFormatSpecifier("%mc", idx, asterisk) == Format.POSIX_ms); + assert(idx == 3); + + idx = 0; + assert(parseScanfFormatSpecifier("%ms", idx, asterisk) == Format.POSIX_ms); + assert(idx == 3); + + idx = 0; + assert(parseScanfFormatSpecifier("%m[0-9]", idx, asterisk) == Format.POSIX_ms); + assert(idx == 7); + + idx = 0; + assert(parseScanfFormatSpecifier("%mlc", idx, asterisk) == Format.POSIX_mls); + assert(idx == 4); + + idx = 0; + assert(parseScanfFormatSpecifier("%mls", idx, asterisk) == Format.POSIX_mls); + assert(idx == 4); + + idx = 0; + assert(parseScanfFormatSpecifier("%ml[^0-9]", idx, asterisk) == Format.POSIX_mls); + assert(idx == 9); + + idx = 0; + assert(parseScanfFormatSpecifier("%mC", idx, asterisk) == Format.POSIX_mls); + assert(idx == 3); + + idx = 0; + assert(parseScanfFormatSpecifier("%mS", idx, asterisk) == Format.POSIX_mls); + assert(idx == 3); + + idx = 0; + assert(parsePrintfFormatSpecifier("%C", idx, widthStar, precisionStar) == Format.lc); + assert(idx == 2); + + idx = 0; + assert(parseScanfFormatSpecifier("%C", idx, asterisk) == Format.lc); + assert(idx == 2); + + idx = 0; + assert(parsePrintfFormatSpecifier("%S", idx, widthStar, precisionStar) == Format.ls); + assert(idx == 2); + + idx = 0; + assert(parseScanfFormatSpecifier("%S", idx, asterisk) == Format.ls); + assert(idx == 2); + + // GNU extensions: explicitly toggle ISO/GNU flag. + // ISO printf() + bool useGNUExts = false; + { + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%#m", "%+m", "%-m", "% m", "%0m"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); + assert(idx == s.length); + } + foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); + assert(idx == 2); + } + } + + // GNU printf() + useGNUExts = true; + { + foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm", + "%#m", "%+m", "%-m", "% m", "%0m"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error); + assert(idx == s.length); + } + + // valid cases, all parsed as `%m` + foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"]) + { + idx = 0; + assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.GNU_m); + assert(idx == 2); + } + } } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index cf4ccbb..1a26eaa 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -1121,6 +1121,10 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) if (!dtor) return null; + // Don't try to call `@disable`d dtors + if (dtor.storage_class & STC.disable) + return null; + // Generate shim only when ABI incompatible on target platform if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD) return dtor; diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index d90542f..f4e44e8 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -234,99 +234,9 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2) UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2) { - UnionExp ue = void; - if (type.isreal()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type); - } - else if (type.isimaginary()) - { - emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type); - } - else if (type.iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - auto c1 = complex_t(CTFloat.zero); - real_t r1 = CTFloat.zero; - real_t i1 = CTFloat.zero; - auto c2 = complex_t(CTFloat.zero); - real_t r2 = CTFloat.zero; - real_t i2 = CTFloat.zero; - auto v = complex_t(CTFloat.zero); - int x; - if (e1.type.isreal()) - { - r1 = e1.toReal(); - x = 0; - } - else if (e1.type.isimaginary()) - { - i1 = e1.toImaginary(); - x = 3; - } - else - { - c1 = e1.toComplex(); - x = 6; - } - if (e2.type.isreal()) - { - r2 = e2.toReal(); - } - else if (e2.type.isimaginary()) - { - i2 = e2.toImaginary(); - x += 1; - } - else - { - c2 = e2.toComplex(); - x += 2; - } - switch (x) - { - case 0 + 0: - v = complex_t(r1 - r2); - break; - case 0 + 1: - v = complex_t(r1, -i2); - break; - case 0 + 2: - v = complex_t(r1 - creall(c2), -cimagl(c2)); - break; - case 3 + 0: - v = complex_t(-r2, i1); - break; - case 3 + 1: - v = complex_t(CTFloat.zero, i1 - i2); - break; - case 3 + 2: - v = complex_t(-creall(c2), i1 - cimagl(c2)); - break; - case 6 + 0: - v = complex_t(creall(c1) - r2, cimagl(c1)); - break; - case 6 + 1: - v = complex_t(creall(c1), cimagl(c1) - i2); - break; - case 6 + 2: - v = c1 - c2; - break; - default: - assert(0); - } - emplaceExp!(ComplexExp)(&ue, loc, v, type); - } - else if (SymOffExp soe = e1.isSymOffExp()) - { - emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger()); - ue.exp().type = type; - } - else - { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type); - } + // Compute e1-e2 as e1+(-e2) + UnionExp neg = Neg(e2.type, e2); + UnionExp ue = Add(loc, type, e1, neg.exp()); return ue; } @@ -1213,6 +1123,10 @@ UnionExp ArrayLength(Type type, Expression e1) Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim; emplaceExp!(UnionExp)(&ue, e); } + else if (e1.isNullExp()) + { + emplaceExp!(IntegerExp)(&ue, loc, 0, type); + } else cantExp(ue); return ue; @@ -1505,17 +1419,11 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) Type t2 = e2.type.toBasetype(); //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars()); - if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral)) - { - e = e2; - t = t1; - goto L2; - } - else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_) + + /* e is the non-null operand, t is the type of the null operand + */ + UnionExp catNull(Expression e, Type t) { - e = e1; - t = t2; - L2: Type tn = e.type.toBasetype(); if (tn.ty.isSomeChar) { @@ -1545,6 +1453,15 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) assert(ue.exp().type); return ue; } + + if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral)) + { + return catNull(e2, t1); + } + else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_) + { + return catNull(e1, t2); + } else if (e1.op == EXP.null_ && e2.op == EXP.null_) { if (type == e1.type) diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index a3bebb7..2679a63 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1675,7 +1675,7 @@ final class CParser(AST) : Parser!AST auto stags = applySpecifier(stag, specifier); symbols.push(stags); - if (tt.tok == TOK.enum_) + if (0 && tt.tok == TOK.enum_) // C11 proscribes enums with no members, but we allow it { if (!tt.members) error(tt.loc, "`enum %s` has no members", stag.toChars()); diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 12051d9..afd19f3 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1106,9 +1106,14 @@ MATCH implicitConvTo(Expression e, Type t) MATCH visitCond(CondExp e) { - auto result = visit(e); - if (result != MATCH.nomatch) - return result; + e.econd = e.econd.optimize(WANTvalue); + const opt = e.econd.toBool(); + if (opt.isPresent()) + { + auto result = visit(e); + if (result != MATCH.nomatch) + return result; + } MATCH m1 = e.e1.implicitConvTo(t); MATCH m2 = e.e2.implicitConvTo(t); @@ -2942,6 +2947,9 @@ Lagain: t1 = Type.basic[ty1]; t2 = Type.basic[ty2]; + + if (!(t1 && t2)) + return null; e1 = e1.castTo(sc, t1); e2 = e2.castTo(sc, t2); return Lret(Type.basic[ty]); diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 2c7d381..c8f6c2a 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -684,6 +684,7 @@ public: const char *kind() const override; bool isUnique(); bool needsClosure(); + bool checkClosure(); bool hasNestedFrameRefs(); ParameterList getParameterList(); diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 5841a25..890c3b6 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -2352,6 +2352,7 @@ public: if (ExpInitializer ie = v._init.isExpInitializer()) { result = interpretRegion(ie.exp, istate, goal); + return; } else if (v._init.isVoidInitializer()) { @@ -2359,12 +2360,16 @@ public: // There is no AssignExp for void initializers, // so set it here. setValue(v, result); + return; } - else + else if (v._init.isArrayInitializer()) { - e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); - result = CTFEExp.cantexp; + result = v._init.initializerToExpression(v.type); + if (result !is null) + return; } + e.error("declaration `%s` is not yet implemented in CTFE", e.toChars()); + result = CTFEExp.cantexp; } else if (v.type.size() == 0) { diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 0be938f..5e802da 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -619,7 +619,7 @@ extern (C++) final class Module : Package else { // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module - bool isPackageMod = (strcmp(toChars(), "package") != 0) && (strcmp(srcfile.name(), package_d) == 0 || (strcmp(srcfile.name(), package_di) == 0)); + bool isPackageMod = (strcmp(toChars(), "package") != 0) && isPackageFileName(srcfile); if (isPackageMod) .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars()); else @@ -824,8 +824,7 @@ extern (C++) final class Module : Package const(char)* srcname = srcfile.toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); - isPackageFile = (strcmp(srcfile.name(), package_d) == 0 || - strcmp(srcfile.name(), package_di) == 0); + isPackageFile = isPackageFileName(srcfile); const(char)[] buf = cast(const(char)[]) this.src; bool needsReencoding = true; @@ -1032,8 +1031,7 @@ extern (C++) final class Module : Package } assert(dst); Module m = ppack ? ppack.isModule() : null; - if (m && (strcmp(m.srcfile.name(), package_d) != 0 && - strcmp(m.srcfile.name(), package_di) != 0)) + if (m && !isPackageFileName(m.srcfile)) { .error(md.loc, "package name '%s' conflicts with usage as a module name in file %s", ppack.toPrettyChars(), m.srcfile.toChars()); } diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 2b608f6..c940ff0 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -2441,6 +2441,15 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) auto sd = s.isScopeDsymbol(); // new declaration auto sd2 = s2.isScopeDsymbol(); // existing declaration + static if (log) void print(EnumDeclaration sd) + { + printf("members: %p\n", sd.members); + printf("symtab: %p\n", sd.symtab); + printf("endlinnum: %d\n", sd.endlinnum); + printf("type: %s\n", sd.type.toChars()); + printf("memtype: %s\n", sd.memtype.toChars()); + } + if (!sd2) { /* Look in tag table @@ -2473,6 +2482,23 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) { sd2.members = sd.members; // transfer definition to sd2 sd.members = null; + if (auto ed2 = sd2.isEnumDeclaration()) + { + auto ed = sd.isEnumDeclaration(); + if (ed.memtype != ed2.memtype) + return null; // conflict + + // transfer ed's members to sd2 + ed2.members.foreachDsymbol( (s) + { + if (auto em = s.isEnumMember()) + em.ed = ed2; + }); + + ed2.type = ed.type; + ed2.memtype = ed.memtype; + ed2.added = false; + } return sd2; } else diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 11a51f1..7f57cbe 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2023,7 +2023,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(EnumDeclaration ed) { //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); - //printf("EnumDeclaration::semantic() %p %s\n", this, ed.toChars()); + //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); if (ed.semanticRun >= PASS.semanticdone) return; // semantic() already completed if (ed.semanticRun == PASS.semantic) @@ -4442,7 +4442,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor invd.semanticRun < PASS.semantic && !ad.isUnionDeclaration() // users are on their own with union fields ) + { + invd.fixupInvariantIdent(ad.invs.length); ad.invs.push(invd); + } if (!invd.type) invd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, invd.storage_class); @@ -5713,6 +5716,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) { + //printf("addEnumMembers(ed: %p)\n", ed); if (ed.added) return; ed.added = true; @@ -5736,6 +5740,7 @@ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) em.ed = ed; if (isCEnum) { + //printf("adding EnumMember %s to %p\n", em.toChars(), ed); em.addMember(sc, ed); // add em to ed's symbol table em.addMember(sc, sds); // add em to symbol table that ed is in em.parent = ed; // restore it after previous addMember() changed it diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index c0a8e9f..02f12e4 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -7323,7 +7323,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol errors = true; } L1: - //printf("\tnested inside %s\n", enclosing.toChars()); + //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars()); nested |= 1; } } diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d index ef2fdef..c29d499 100644 --- a/gcc/d/dmd/entity.d +++ b/gcc/d/dmd/entity.d @@ -17,18 +17,27 @@ import core.stdc.ctype; nothrow: -public int HtmlNamedEntity(const(char)* p, size_t length) +/********************************** + * See if `name` is an HTML Named Entity + * Params: + * name = name of the entity + * Returns: + * code point corresponding to the named entity + * ~0 for not recognized as a named entity + */ +public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe { - int tableIndex = tolower(*p) - 'a'; - if (tableIndex >= 0 && tableIndex < 26) + const firstC = tolower(name[0]); + if (firstC >= 'a' && firstC <= 'z') { - foreach (entity; namesTable[tableIndex]) + // Linear search (use hash table instead?) + foreach (entity; namesTable[firstC - 'a']) { - if (entity.name == p[0 .. length]) + if (entity.name == name) return entity.value; } } - return -1; + return ~0; } private: diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 0646f57..fb5e092 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -351,7 +351,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC { unsafeAssign!"scope variable"(v); } - else if (v.storage_class & STC.variadic && p == sc.func) + else if (v.isTypesafeVariadicParameter && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -649,7 +649,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) Dsymbol p = v.toParent2(); if (va && !vaIsRef && !va.isScope() && !v.isScope() && - (va.storage_class & v.storage_class & (STC.maybescope | STC.variadic)) == STC.maybescope && + !v.isTypesafeVariadicParameter && !va.isTypesafeVariadicParameter && + (va.storage_class & v.storage_class & STC.maybescope) && p == fd) { /* Add v to va's list of dependencies @@ -663,7 +664,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) !(v.storage_class & STC.return_) && v.isParameter() && fd.flags & FUNCFLAG.returnInprocess && - p == fd) + p == fd && + !v.isTypesafeVariadicParameter) { if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars()); inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope` @@ -735,7 +737,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1); } - else if (v.storage_class & STC.variadic && p == fd) + else if (v.isTypesafeVariadicParameter && p == fd) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -1022,7 +1024,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) continue; } } - else if (v.storage_class & STC.variadic && p == sc.func) + else if (v.isTypesafeVariadicParameter && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -1194,7 +1196,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) v.isParameter() && !v.doNotInferReturn && sc.func.flags & FUNCFLAG.returnInprocess && - p == sc.func) + p == sc.func && + !v.isTypesafeVariadicParameter) { inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return' continue; @@ -1250,7 +1253,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } } } - else if (v.storage_class & STC.variadic && p == sc.func) + else if (v.isTypesafeVariadicParameter && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -1627,7 +1630,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re { if (tb.ty == Tsarray) return; - if (v.storage_class & STC.variadic) + if (v.isTypesafeVariadicParameter) { er.byvalue.push(v); return; @@ -1943,7 +1946,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR VarDeclaration v = ve.var.isVarDeclaration(); if (tb.ty == Tarray || tb.ty == Tsarray) { - if (v && v.storage_class & STC.variadic) + if (v && v.isTypesafeVariadicParameter) { er.pushRef(v, retRefTransition); return; @@ -2586,3 +2589,15 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g return sc.setUnsafeDIP1000(gag, e.loc, "cannot take address of `scope` variable `%s` since `scope` applies to first indirection only", v); } + +/**************************** + * Determine if `v` is a typesafe variadic parameter. + * Params: + * v = variable to check + * Returns: + * true if `v` is a variadic parameter + */ +bool isTypesafeVariadicParameter(VarDeclaration v) +{ + return !!(v.storage_class & STC.variadic); +} diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 35ba5fa..30baabd 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -3463,8 +3463,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.arguments && exp.newtype.isTypeSArray()) { auto ts = exp.newtype.isTypeSArray(); - edim = ts.dim; - exp.newtype = ts.next; + // check `new Value[Key]` + ts.dim = ts.dim.expressionSemantic(sc); + if (ts.dim.op == EXP.type) + { + exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type); + } + else + { + edim = ts.dim; + exp.newtype = ts.next; + } } ClassDeclaration cdthis = null; @@ -3518,18 +3527,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { return setError(); } - //https://issues.dlang.org/show_bug.cgi?id=20547 - //exp.arguments are the "parameters" to [], not to a real function - //so the errors that come from preFunctionParameters are misleading - if (originalNewtype.ty == Tsarray) - { - if (preFunctionParameters(sc, exp.arguments, false)) - { - exp.error("cannot create a `%s` with `new`", originalNewtype.toChars()); - return setError(); - } - } - else if (preFunctionParameters(sc, exp.arguments)) + if (preFunctionParameters(sc, exp.arguments)) { return setError(); } @@ -3885,6 +3883,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.type.pointerTo(); } + else if (tb.ty == Taarray) + { + // e.g. `new Alias(args)` + if (nargs) + { + exp.error("`new` cannot take arguments for an associative array"); + return setError(); + } + } else { exp.error("cannot create a `%s` with `new`", exp.type.toChars()); @@ -5019,7 +5026,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } - if (tf.trust <= TRUST.system && sc.setUnsafe()) + if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc, + "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1)) { exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); @@ -7588,11 +7596,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Check for unsafe casts - if (!isSafeCast(ex, t1b, tob) && - (!sc.func && sc.stc & STC.safe || sc.setUnsafe())) + if (!isSafeCast(ex, t1b, tob)) { - exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); - return setError(); + // This is an ad-hoc fix for https://issues.dlang.org/show_bug.cgi?id=19646 + // Should be replaced by a more general @system variables implementation + if (!sc.func && sc.stc & STC.safe) + { + exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); + return setError(); + } + + if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to)) + { + return setError(); + } } // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built @@ -8900,6 +8917,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) || e2x.checkSharedAccess(sc)) return setError(); + + if (e2x.type.isTypeNoreturn() && !e2x.isAssertExp() && !e2x.isThrowExp() && !e2x.isCallExp()) + { + auto msg = new StringExp(e2x.loc, "Accessed expression of type `noreturn`"); + msg.type = Type.tstring; + e2x = new AssertExp(e2x.loc, IntegerExp.literal!0, msg); + e2x.type = Type.tnoreturn; + return setResult(e2x); + } exp.e2 = e2x; } @@ -9896,9 +9922,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ae.e2.type.nextOf && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf); + /* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal, + * then we do want to make a temporary for it and call its destructor. + */ const isArraySetCtor = (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && - ae.e2.isLvalue && (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) && ae.e1.type.nextOf && ae.e1.type.nextOf.equivalent(ae.e2.type); @@ -10302,6 +10330,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // `__appendtmp*` will be destroyed together with the array `exp.e1`. auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); vd.storage_class |= STC.nodtor; + // Be more explicit that this "declaration" is local to the expression + vd.storage_class |= STC.exptemp; } auto ale = new ArrayLengthExp(exp.loc, value1); @@ -11870,6 +11900,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars()); + // https://issues.dlang.org/show_bug.cgi?id=22390 + // Equality comparison between array of noreturns simply lowers to length equality comparison + if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn()) + { + Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length); + Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length); + auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2); + result = e.expressionSemantic(sc); + return; + } + if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays")) return setError(); @@ -12638,7 +12679,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) e = new CommaExp(exp.loc, eleft, e); e.type = Type.tvoid; // ambiguous type? } - return e; + return e.expressionSemantic(sc); } if (auto o = s.isOverloadSet()) { @@ -13131,26 +13172,24 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) { //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars()); - if (v) + if (v is null) + return true; + + if (!v.canTakeAddressOf()) + { + exp.error("cannot take address of `%s`", exp.toChars()); + return false; + } + if (sc.func && !sc.intypeof && !v.isDataseg()) { - if (!v.canTakeAddressOf()) + v.storage_class &= ~STC.maybescope; + v.doNotInferScope = true; + if (global.params.useDIP1000 != FeatureState.enabled && + !(v.storage_class & STC.temp) && + sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func)) { - exp.error("cannot take address of `%s`", exp.toChars()); return false; } - if (sc.func && !sc.intypeof && !v.isDataseg()) - { - const(char)* p = v.isParameter() ? "parameter" : "local"; - v.storage_class &= ~STC.maybescope; - v.doNotInferScope = true; - if (global.params.useDIP1000 != FeatureState.enabled && - !(v.storage_class & STC.temp) && - sc.setUnsafe()) - { - exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); - return false; - } - } } return true; } diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index 9fe40bf..0ea7303 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -20,6 +20,12 @@ import dmd.identifier; enum package_d = "package." ~ mars_ext; enum package_di = "package." ~ hdr_ext; +/// Returns: whether a file with `name` is a special "package.d" module +bool isPackageFileName(scope FileName fileName) nothrow +{ + return FileName.equals(fileName.name, package_d) || FileName.equals(fileName.name, package_di); +} + final class FileManager { private StringTable!(const(ubyte)[]) files; diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 83bc2ea..7475cb4 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -867,6 +867,8 @@ extern (C++) class FuncDeclaration : Declaration auto f = s.isFuncDeclaration(); if (!f) return 0; + if (f.storage_class & STC.disable) + return 0; if (t.equals(f.type)) { fd = f; @@ -2048,9 +2050,11 @@ extern (C++) class FuncDeclaration : Declaration } if (!found) { - //printf("\tadding sibling %s\n", fdthis.toPrettyChars()); + //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars()); if (!sc.intypeof && !(sc.flags & SCOPE.compile)) + { siblingCallers.push(fdthis); + } } } @@ -2164,7 +2168,6 @@ extern (C++) class FuncDeclaration : Declaration return false; Lyes: - //printf("\tneeds closure\n"); return true; } @@ -2176,14 +2179,21 @@ extern (C++) class FuncDeclaration : Declaration * Returns: * true if any errors occur. */ - extern (D) final bool checkClosure() + extern (C++) final bool checkClosure() { + //printf("checkClosure() %s\n", toChars()); if (!needsClosure()) return false; if (setGC()) { - error("is `@nogc` yet allocates closures with the GC"); + error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars()); + if (global.gag) // need not report supplemental errors + return true; + } + else if (global.params.betterC) + { + error("is `-betterC` yet allocates closure for `%s()` with the GC", toChars()); if (global.gag) // need not report supplemental errors return true; } @@ -2216,7 +2226,7 @@ extern (C++) class FuncDeclaration : Declaration break LcheckAncestorsOfANestedRef; } a.push(f); - .errorSupplemental(f.loc, "%s closes over variable %s at %s", + .errorSupplemental(f.loc, "`%s` closes over variable `%s` at %s", f.toPrettyChars(), v.toChars(), v.loc.toChars()); break LcheckAncestorsOfANestedRef; } @@ -3293,7 +3303,8 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); - printCandidates(loc, td, sc.isDeprecated()); + if (!global.gag || global.params.showGaggedErrors) + printCandidates(loc, td, sc.isDeprecated()); return null; } /* This case used to happen when several ctors are mixed in an agregate. @@ -3331,7 +3342,8 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, { .error(loc, "none of the overloads of `%s` are callable using a %sobject", fd.ident.toChars(), thisBuf.peekChars()); - printCandidates(loc, fd, sc.isDeprecated()); + if (!global.gag || global.params.showGaggedErrors) + printCandidates(loc, fd, sc.isDeprecated()); return null; } @@ -3361,18 +3373,23 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, { .error(loc, "none of the overloads of `%s` are callable using argument types `%s`", fd.toChars(), fargsBuf.peekChars()); - printCandidates(loc, fd, sc.isDeprecated()); + if (!global.gag || global.params.showGaggedErrors) + printCandidates(loc, fd, sc.isDeprecated()); return null; } .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList), tf.modToChars(), fargsBuf.peekChars()); + // re-resolve to check for supplemental message - const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); - if (failMessage) - errorSupplemental(loc, failMessage); + if (!global.gag || global.params.showGaggedErrors) + { + const(char)* failMessage; + functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); + if (failMessage) + errorSupplemental(loc, failMessage); + } return null; } @@ -4220,6 +4237,7 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration { extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody) { + // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list. super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); this.fbody = fbody; } @@ -4256,6 +4274,15 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration { v.visit(this); } + + extern (D) void fixupInvariantIdent(size_t offset) + { + OutBuffer idBuf; + idBuf.writestring("__invariant"); + idBuf.print(offset); + + ident = Identifier.idPool(idBuf[]); + } } @@ -4447,12 +4474,15 @@ void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool depr errorFunc(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : ""); } - else if (FuncDeclaration fd2 = cast(FuncDeclaration) s.arg0) + else if (s.arg0.dyncast() == DYNCAST.dsymbol) { - if (maxDepth > 0) + if (FuncDeclaration fd2 = (cast(Dsymbol) s.arg0).isFuncDeclaration()) { - errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars()); - errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation); + if (maxDepth > 0) + { + errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars()); + errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation); + } } } } diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d index ab46f5e..832c331 100644 --- a/gcc/d/dmd/impcnvtab.d +++ b/gcc/d/dmd/impcnvtab.d @@ -64,6 +64,57 @@ enum ImpCnvTab impCnvTab = generateImpCnvTab(); ImpCnvTab generateImpCnvTab() { + TY[TMAX] typeTYs = + [ + Tarray, + Tsarray, + Taarray, + Tpointer, + Treference, + Tfunction, + Tident, + Tclass, + Tstruct, + Tenum, + Tdelegate, + Tnone, + Tvoid, + Tint8, + Tuns8, + Tint16, + Tuns16, + Tint32, + Tuns32, + Tint64, + Tuns64, + Tfloat32, + Tfloat64, + Tfloat80, + Timaginary32, + Timaginary64, + Timaginary80, + Tcomplex32, + Tcomplex64, + Tcomplex80, + Tbool, + Tchar, + Twchar, + Tdchar, + Terror, + Tinstance, + Ttypeof, + Ttuple, + Tslice, + Treturn, + Tnull, + Tvector, + Tint128, + Tuns128, + Ttraits, + Tmixin, + Tnoreturn, + Ttag, + ]; ImpCnvTab impCnvTab; // Set conversion tables @@ -375,5 +426,9 @@ ImpCnvTab generateImpCnvTab() X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80); + // "No type is implicitly convertible to noreturn, but noreturn is implicitly convertible to every other type" + foreach(convertToTy; typeTYs) + X(Tnoreturn, convertToTy, convertToTy, convertToTy, convertToTy); + return impCnvTab; } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index a1963da..a576712 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -567,18 +567,40 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = e.optimize(WANTvalue); } } + + // Look for the case of statically initializing an array with a single member. + // Recursively strip static array / enum layers until a compatible element is found, + // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found + // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]] + // int[2] = new Object => null + Expression sarrayRepeat(Type tb) { - // Look for the case of statically initializing an array - // with a single member. - auto tba = tb.isTypeSArray(); - if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next)) + auto tsa = tb.isTypeSArray(); + if (!tsa) + return null; + + // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars()); + Expression elem = null; + if (i.exp.implicitConvTo(tb.nextOf())) + elem = i.exp.implicitCastTo(sc, tb.nextOf()); + else if (auto ae = sarrayRepeat(tb.nextOf().toBasetype())) + elem = ae; + else + return null; + + auto arrayElements = new Expressions(cast(size_t) tsa.dim.toInteger()); + foreach (ref e; *arrayElements) + e = elem; + return new ArrayLiteralExp(i.exp.loc, tb, elem, arrayElements); + } + + if (auto sa = sarrayRepeat(tb)) { - /* If the variable is not actually used in compile time, array creation is - * redundant. So delay it until invocation of toExpression() or toDt(). - */ - t = tb.nextOf(); + // printf("sa = %s\n", sa.toChars()); + i.exp = sa; } + { auto tta = t.isTypeSArray(); if (i.exp.implicitConvTo(t)) { @@ -595,6 +617,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { + auto tba = tb.isTypeSArray(); // Look for mismatch of compile-time known length to emit // better diagnostic message, as same as AssignExp::semantic. if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch) diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index ef918e2..11afcdd 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -1326,7 +1326,7 @@ class Lexer switch (*p) { case ';': - c = HtmlNamedEntity(idstart, p - idstart); + c = HtmlNamedEntity(idstart[0 .. p - idstart]); if (c == ~0) { error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index 4eb4228..369d60e 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -98,7 +98,7 @@ void checkMustUseReserved(Dsymbol sym) */ private bool isAssignment(Expression e) { - if (e.isAssignExp || e.isBinAssignExp) + if (e.isAssignExp || e.isBinAssignExp || e.isConstructExp || e.isBlitExp) return true; if (auto ce = e.isCallExp()) { diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 2b7b9ac..be28d08 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -1120,7 +1120,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) e.e1 = ci; } } - if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray) + if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray || e.e1.op == EXP.null_) { ret = ArrayLength(e.type, e.e1).copy(); } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 4e3fd53..a2c364e 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2186,7 +2186,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) s = new AST.DebugSymbol(token.loc, token.ident); else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`debug = <integer>` is deprecated, use debug identifiers instead"); + s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue); + } else { error("identifier or integer expected, not `%s`", token.toChars()); @@ -2215,7 +2221,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) id = token.ident; else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`debug( <integer> )` is deprecated, use debug identifiers instead"); + level = cast(uint)token.unsvalue; + } else error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars()); loc = token.loc; @@ -2235,7 +2247,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) s = new AST.VersionSymbol(token.loc, token.ident); else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`version = <integer>` is deprecated, use version identifiers instead"); s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue); + } else { error("identifier or integer expected, not `%s`", token.toChars()); @@ -2269,7 +2286,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.identifier) id = token.ident; else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal) + { + // @@@DEPRECATED_2.111@@@ + // Deprecated in 2.101, remove in 2.111 + deprecation("`version( <integer> )` is deprecated, use version identifiers instead"); + level = cast(uint)token.unsvalue; + } else if (token.value == TOK.unittest_) id = Identifier.idPool(Token.toString(TOK.unittest_)); else if (token.value == TOK.assert_) @@ -9312,13 +9335,10 @@ LagainStc: { AST.TypeAArray taa = cast(AST.TypeAArray)t; AST.Type index = taa.index; + // `new Type[expr]` is a static array auto edim = AST.typeToExpression(index); - if (!edim) - { - error("cannot create a `%s` with `new`", t.toChars); - return new AST.NullExp(loc); - } - t = new AST.TypeSArray(taa.next, edim); + if (edim) + t = new AST.TypeSArray(taa.next, edim); } else if (token.value == TOK.leftParenthesis && t.ty != Tsarray) { diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index c5d7667..6f37770 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -470,14 +470,6 @@ private extern(C++) final class Semantic3Visitor : Visitor if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) { stc |= STC.variadic; - auto vtypeb = vtype.toBasetype(); - if (vtypeb.ty == Tarray || vtypeb.ty == Tclass) - { - /* Since it'll be pointing into the stack for the array - * contents, it needs to be `scope` - */ - stc |= STC.scope_; - } } if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_)) @@ -1379,7 +1371,7 @@ private extern(C++) final class Semantic3Visitor : Visitor funcdecl.flags &= ~FUNCFLAG.semantic3Errors; if (funcdecl.type.ty == Terror) funcdecl.errors = true; - //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars()); + //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars()); //fflush(stdout); } diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index f23b988..e5e5753 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -733,9 +733,26 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor { assert(oaggr.type); - fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars()); - if (isAggregate(fs.aggr.type)) - fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`"); + fs.error("invalid `%s` aggregate `%s` of type `%s`", + Token.toChars(fs.op), oaggr.toChars(), oaggr.type.toPrettyChars()); + + if (auto ad = isAggregate(fs.aggr.type)) + { + if (fs.op == TOK.foreach_reverse_) + { + fs.loc.errorSupplemental("`foreach_reverse` works with bidirectional ranges"~ + " (implementing `back` and `popBack`), aggregates implementing" ~ + " `opApplyReverse`, or the result of an aggregate's `.tupleof` property"); + fs.loc.errorSupplemental("https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange"); + } + else + { + fs.loc.errorSupplemental("`foreach` works with input ranges"~ + " (implementing `front` and `popFront`), aggregates implementing" ~ + " `opApply`, or the result of an aggregate's `.tupleof` property"); + fs.loc.errorSupplemental("https://dlang.org/phobos/std_range_primitives.html#isInputRange"); + } + } return setError(); } @@ -2828,10 +2845,20 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor rs.error("`return` statements cannot be in contracts"); errors = true; } - if (sc.os && sc.os.tok != TOK.onScopeFailure) + if (sc.os) { - rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); - errors = true; + // @@@DEPRECATED_2.112@@@ + // Deprecated in 2.100, transform into an error in 2.112 + if (sc.os.tok == TOK.onScopeFailure) + { + rs.deprecation("`return` statements cannot be in `scope(failure)` bodies."); + deprecationSupplemental(rs.loc, "Use try-catch blocks for this purpose"); + } + else + { + rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok)); + errors = true; + } } if (sc.tf) { @@ -2913,6 +2940,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor rs.exp.type = texp; } + // @@@DEPRECATED_2.111@@@ + const olderrors = global.startGagging(); + // uncomment to turn deprecation into an error when + // deprecation cycle is over + if (discardValue(rs.exp)) + { + //errors = true; + } + if (global.endGagging(olderrors)) + rs.exp.deprecation("`%s` has no effect", rs.exp.toChars()); + /* Replace: * return exp; * with: diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 25dee7f..5791a88 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -862,6 +862,12 @@ package mixin template ParseVisitMethods(AST) visitFuncBody(d); } + override void visit(AST.CtorDeclaration d) + { + //printf("Visiting CtorDeclaration\n"); + visitFuncBody(d); + } + override void visit(AST.StaticCtorDeclaration d) { //printf("Visiting StaticCtorDeclaration\n"); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 0469b92..b1f1b1f 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1272,6 +1272,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) errors = true; } + const bool isTypesafeVariadic = i + 1 == dim && + tf.parameterList.varargs == VarArg.typesafe && + (t.isTypeDArray() || t.isTypeClass()); + if (isTypesafeVariadic) + { + /* typesafe variadic arguments are constructed on the stack, so must be `scope` + */ + fparam.storageClass |= STC.scope_ | STC.scopeinferred; + } + if (fparam.storageClass & STC.return_) { if (fparam.isReference()) @@ -1300,8 +1310,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } } - if (i + 1 == dim && tf.parameterList.varargs == VarArg.typesafe && - (t.isTypeDArray() || t.isTypeClass())) + if (isTypesafeVariadic) { /* This is because they can be constructed on the stack * https://dlang.org/spec/function.html#typesafe_variadic_functions diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 1bb10a8..40c2689 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -873,6 +873,17 @@ public: gcc_unreachable (); } + /* Look for exp = noreturn; */ + if (e->e2->type->isTypeNoreturn ()) + { + /* If the RHS is a `noreturn' expression, there is no point generating + any code for the assignment, just evaluate side effects. */ + tree t1 = build_expr (e->e1); + tree t2 = build_expr (e->e2); + this->result_ = compound_expr (t1, t2); + return; + } + /* Look for array[] = n; */ if (e->e1->op == EXP::slice) { diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index bd9c61d..da65239 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -249,7 +249,7 @@ Compile in debug code. fdebug= D Joined RejectNegative --fdebug=<level|ident> Compile in debug code, code <= <level>, or code identified by <ident>. +-fdebug=<ident> Compile in debug code identified by <ident>. fdoc D @@ -466,7 +466,7 @@ Compile in unittest code. fversion= D Joined RejectNegative --fversion=<level|ident> Compile in version code >= <level> or identified by <ident>. +-fversion=<ident> Compile in version code identified by <ident>. fweak-templates D Var(flag_weak_templates) Init(1) diff --git a/gcc/doc/gcov-dump.texi b/gcc/doc/gcov-dump.texi index 2e82a18..34f2ef7 100644 --- a/gcc/doc/gcov-dump.texi +++ b/gcc/doc/gcov-dump.texi @@ -19,6 +19,7 @@ gcov-dump [@option{-l}|@option{--long}] [@option{-p}|@option{--positions}] [@option{-r}|@option{--raw}] + [@option{-s}|@option{--stable}] [@var{gcovfiles}] @subsubheading Options @@ -41,6 +42,10 @@ Dump positions of records. @itemx --raw Print content records in raw format. +@item -s +@itemx --stable +Print content in stable format usable for comparison. + @item -v @itemx --version Display the @command{gcov-dump} version number (on the standard output), diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 696ac2f..a48cca5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -416,6 +416,7 @@ Objective-C and Objective-C++ Dialects}. -Wno-analyzer-fd-use-without-check @gol -Wno-analyzer-file-leak @gol -Wno-analyzer-free-of-non-heap @gol +-Wno-analyzer-jump-through-null @gol -Wno-analyzer-malloc-leak @gol -Wno-analyzer-mismatching-deallocation @gol -Wno-analyzer-null-argument @gol @@ -9719,6 +9720,7 @@ Enabling this option effectively enables the following warnings: -Wanalyzer-fd-use-without-check @gol -Wanalyzer-file-leak @gol -Wanalyzer-free-of-non-heap @gol +-Wanalyzer-jump-through-null @gol -Wanalyzer-malloc-leak @gol -Wanalyzer-mismatching-deallocation @gol -Wanalyzer-null-argument @gol @@ -9905,6 +9907,16 @@ is called on a non-heap pointer (e.g. an on-stack buffer, or a global). See @uref{https://cwe.mitre.org/data/definitions/590.html, CWE-590: Free of Memory not on the Heap}. +@item -Wno-analyzer-jump-through-null +@opindex Wanalyzer-jump-through-null +@opindex Wno-analyzer-jump-through-null +This warning requires @option{-fanalyzer}, which enables it; use +@option{-Wno-analyzer-jump-through-null} +to disable it. + +This diagnostic warns for paths through the code in which a @code{NULL} +function pointer is called. + @item -Wno-analyzer-malloc-leak @opindex Wanalyzer-malloc-leak @opindex Wno-analyzer-malloc-leak @@ -9986,7 +9998,7 @@ See @uref{https://cwe.mitre.org/data/definitions/476.html, CWE-476: NULL Pointer @opindex Wanalyzer-putenv-of-auto-var @opindex Wno-analyzer-putenv-of-auto-var This warning requires @option{-fanalyzer}, which enables it; use -@option{-Wno-analyzer-possible-null-dereference} to disable it. +@option{-Wno-analyzer-putenv-of-auto-var} to disable it. This diagnostic warns for paths through the code in which a call to @code{putenv} is passed a pointer to an automatic variable @@ -1570,12 +1570,7 @@ record_store (rtx body, bb_info_t bb_info) width) /* We can only remove the later store if the earlier aliases at least all accesses the later one. */ - && ((MEM_ALIAS_SET (mem) == MEM_ALIAS_SET (s_info->mem) - || alias_set_subset_of (MEM_ALIAS_SET (mem), - MEM_ALIAS_SET (s_info->mem))) - && (!MEM_EXPR (s_info->mem) - || refs_same_for_tbaa_p (MEM_EXPR (s_info->mem), - MEM_EXPR (mem))))) + && mems_same_for_tbaa_p (s_info->mem, mem)) { if (GET_MODE (mem) == BLKmode) { diff --git a/gcc/dwarf2ctf.cc b/gcc/dwarf2ctf.cc index a6329ab..3971000 100644 --- a/gcc/dwarf2ctf.cc +++ b/gcc/dwarf2ctf.cc @@ -644,6 +644,7 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function, ctf_funcinfo_t func_info; uint32_t num_args = 0; + int linkage = get_AT_flag (function, DW_AT_external); ctf_id_t return_type_id; ctf_id_t function_type_id; @@ -687,7 +688,8 @@ gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function, function_name, (const ctf_funcinfo_t *)&func_info, function, - from_global_func); + from_global_func, + linkage); /* Second pass on formals: generate the CTF types corresponding to them and add them as CTF function args. */ diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 3ac39c1..cfea9cf 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -6069,11 +6069,12 @@ dwarf2out_register_external_die (tree decl, const char *sym, if (!external_die_map) external_die_map = hash_map<tree, sym_off_pair>::create_ggc (1000); - /* When we do tree merging during WPA we can end up re-using GC memory - as there's currently no way to unregister external DIEs. Ideally - we'd register them only after merging finished but allowing override - here is easiest. See PR106334. */ - gcc_checking_assert (flag_wpa || !external_die_map->get (decl)); + /* When we do tree merging during WPA or with -flto-partition=none we + can end up re-using GC memory as there's currently no way to unregister + external DIEs. Ideally we'd register them only after merging finished + but allowing override here is easiest. See PR106334. */ + gcc_checking_assert (!(in_lto_p && !flag_wpa) + || !external_die_map->get (decl)); sym_off_pair p = { IDENTIFIER_POINTER (get_identifier (sym)), off }; external_die_map->put (decl, p); } diff --git a/gcc/expmed.cc b/gcc/expmed.cc index 9b01b5a..8d7418b 100644 --- a/gcc/expmed.cc +++ b/gcc/expmed.cc @@ -5662,63 +5662,9 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1, break; } - /* If we are comparing a double-word integer with zero or -1, we can - convert the comparison into one involving a single word. */ - scalar_int_mode int_mode; - if (is_int_mode (mode, &int_mode) - && GET_MODE_BITSIZE (int_mode) == BITS_PER_WORD * 2 - && (!MEM_P (op0) || ! MEM_VOLATILE_P (op0))) - { - rtx tem; - if ((code == EQ || code == NE) - && (op1 == const0_rtx || op1 == constm1_rtx)) - { - rtx op00, op01; - - /* Do a logical OR or AND of the two words and compare the - result. */ - op00 = simplify_gen_subreg (word_mode, op0, int_mode, 0); - op01 = simplify_gen_subreg (word_mode, op0, int_mode, UNITS_PER_WORD); - tem = expand_binop (word_mode, - op1 == const0_rtx ? ior_optab : and_optab, - op00, op01, NULL_RTX, unsignedp, - OPTAB_DIRECT); - - if (tem != 0) - tem = emit_store_flag (NULL_RTX, code, tem, op1, word_mode, - unsignedp, normalizep); - } - else if ((code == LT || code == GE) && op1 == const0_rtx) - { - rtx op0h; - - /* If testing the sign bit, can just test on high word. */ - op0h = simplify_gen_subreg (word_mode, op0, int_mode, - subreg_highpart_offset (word_mode, - int_mode)); - tem = emit_store_flag (NULL_RTX, code, op0h, op1, word_mode, - unsignedp, normalizep); - } - else - tem = NULL_RTX; - - if (tem) - { - if (target_mode == VOIDmode || GET_MODE (tem) == target_mode) - return tem; - if (!target) - target = gen_reg_rtx (target_mode); - - convert_move (target, tem, - !val_signbit_known_set_p (word_mode, - (normalizep ? normalizep - : STORE_FLAG_VALUE))); - return target; - } - } - /* If this is A < 0 or A >= 0, we can do this by taking the ones complement of A (for GE) and shifting the sign bit to the low bit. */ + scalar_int_mode int_mode; if (op1 == const0_rtx && (code == LT || code == GE) && is_int_mode (mode, &int_mode) && (normalizep || STORE_FLAG_VALUE == 1 @@ -5764,6 +5710,7 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1, return op0; } + /* Next try expanding this via the backend's cstore<mode>4. */ mclass = GET_MODE_CLASS (mode); FOR_EACH_MODE_FROM (compare_mode, mode) { @@ -5788,6 +5735,60 @@ emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1, } } + /* If we are comparing a double-word integer with zero or -1, we can + convert the comparison into one involving a single word. */ + if (is_int_mode (mode, &int_mode) + && GET_MODE_BITSIZE (int_mode) == BITS_PER_WORD * 2 + && (!MEM_P (op0) || ! MEM_VOLATILE_P (op0))) + { + rtx tem; + if ((code == EQ || code == NE) + && (op1 == const0_rtx || op1 == constm1_rtx)) + { + rtx op00, op01; + + /* Do a logical OR or AND of the two words and compare the + result. */ + op00 = simplify_gen_subreg (word_mode, op0, int_mode, 0); + op01 = simplify_gen_subreg (word_mode, op0, int_mode, UNITS_PER_WORD); + tem = expand_binop (word_mode, + op1 == const0_rtx ? ior_optab : and_optab, + op00, op01, NULL_RTX, unsignedp, + OPTAB_DIRECT); + + if (tem != 0) + tem = emit_store_flag (NULL_RTX, code, tem, op1, word_mode, + unsignedp, normalizep); + } + else if ((code == LT || code == GE) && op1 == const0_rtx) + { + rtx op0h; + + /* If testing the sign bit, can just test on high word. */ + op0h = simplify_gen_subreg (word_mode, op0, int_mode, + subreg_highpart_offset (word_mode, + int_mode)); + tem = emit_store_flag (NULL_RTX, code, op0h, op1, word_mode, + unsignedp, normalizep); + } + else + tem = NULL_RTX; + + if (tem) + { + if (target_mode == VOIDmode || GET_MODE (tem) == target_mode) + return tem; + if (!target) + target = gen_reg_rtx (target_mode); + + convert_move (target, tem, + !val_signbit_known_set_p (word_mode, + (normalizep ? normalizep + : STORE_FLAG_VALUE))); + return target; + } + } + return 0; } diff --git a/gcc/gcov-dump.cc b/gcc/gcov-dump.cc index 0804c79..85b1be8 100644 --- a/gcc/gcov-dump.cc +++ b/gcc/gcov-dump.cc @@ -28,6 +28,10 @@ along with Gcov; see the file COPYING3. If not see #include "gcov-io.h" #include "gcov-io.cc" +#include <vector> + +using namespace std; + static void dump_gcov_file (const char *); static void print_prefix (const char *, unsigned, gcov_position_t); static void print_usage (void); @@ -50,6 +54,7 @@ typedef struct tag_format static int flag_dump_contents = 0; static int flag_dump_positions = 0; static int flag_dump_raw = 0; +static int flag_dump_stable = 0; static const struct option options[] = { @@ -57,7 +62,9 @@ static const struct option options[] = { "version", no_argument, NULL, 'v' }, { "long", no_argument, NULL, 'l' }, { "positions", no_argument, NULL, 'o' }, - { 0, 0, 0, 0 } + { "raw", no_argument, NULL, 'r' }, + { "stable", no_argument, NULL, 's' }, + {} }; #define VALUE_PADDING_PREFIX " " @@ -96,7 +103,7 @@ main (int argc ATTRIBUTE_UNUSED, char **argv) diagnostic_initialize (global_dc, 0); - while ((opt = getopt_long (argc, argv, "hlprvw", options, NULL)) != -1) + while ((opt = getopt_long (argc, argv, "hlprsvw", options, NULL)) != -1) { switch (opt) { @@ -115,6 +122,9 @@ main (int argc ATTRIBUTE_UNUSED, char **argv) case 'r': flag_dump_raw = 1; break; + case 's': + flag_dump_stable = 1; + break; default: fprintf (stderr, "unknown flag `%c'\n", opt); } @@ -134,6 +144,8 @@ print_usage (void) printf (" -l, --long Dump record contents too\n"); printf (" -p, --positions Dump record positions\n"); printf (" -r, --raw Print content records in raw format\n"); + printf (" -s, --stable Print content in stable " + "format usable for comparison\n"); printf (" -v, --version Print version number\n"); printf ("\nFor bug reporting instructions, please see:\n%s.\n", bug_report_url); @@ -439,16 +451,52 @@ tag_counters (const char *filename ATTRIBUTE_UNUSED, int n_counts = GCOV_TAG_COUNTER_NUM (length); bool has_zeros = n_counts < 0; n_counts = abs (n_counts); + unsigned counter_idx = GCOV_COUNTER_FOR_TAG (tag); printf (" %s %u counts%s", - counter_names[GCOV_COUNTER_FOR_TAG (tag)], n_counts, + counter_names[counter_idx], n_counts, has_zeros ? " (all zero)" : ""); if (flag_dump_contents) { + vector<gcov_type> counters; for (int ix = 0; ix != n_counts; ix++) + counters.push_back (has_zeros ? 0 : gcov_read_counter ()); + + /* Make stable sort for TOP N counters. */ + if (flag_dump_stable) + if (counter_idx == GCOV_COUNTER_V_INDIR + || counter_idx == GCOV_COUNTER_V_TOPN) + { + unsigned start = 0; + while (start < counters.size ()) + { + unsigned n = counters[start + 1]; + + /* Use bubble sort. */ + for (unsigned i = 1; i <= n; ++i) + for (unsigned j = i; j <= n; ++j) + { + gcov_type key1 = counters[start + 2 * i]; + gcov_type value1 = counters[start + 2 * i + 1]; + gcov_type key2 = counters[start + 2 * j]; + gcov_type value2 = counters[start + 2 * j + 1]; + + if (value1 < value2 || (value1 == value2 && key1 < key2)) + { + std::swap (counters[start + 2 * i], + counters[start + 2 * j]); + std::swap (counters[start + 2 * i + 1], + counters[start + 2 * j + 1]); + } + } + start += 2 * (n + 1); + } + if (start != counters.size ()) + abort (); + } + + for (unsigned ix = 0; ix < counters.size (); ++ix) { - gcov_type count; - if (flag_dump_raw) { if (ix == 0) @@ -461,8 +509,7 @@ tag_counters (const char *filename ATTRIBUTE_UNUSED, printf (VALUE_PADDING_PREFIX VALUE_PREFIX, ix); } - count = has_zeros ? 0 : gcov_read_counter (); - printf ("%" PRId64 " ", count); + printf ("%" PRId64 " ", counters[ix]); } } } diff --git a/gcc/gimple-loop-jam.cc b/gcc/gimple-loop-jam.cc index 8cde6c7..a8a57d3 100644 --- a/gcc/gimple-loop-jam.cc +++ b/gcc/gimple-loop-jam.cc @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-loop-ivopts.h" #include "tree-vectorizer.h" #include "tree-ssa-sccvn.h" +#include "tree-cfgcleanup.h" /* Unroll and Jam transformation @@ -609,9 +610,16 @@ tree_loop_unroll_and_jam (void) if (todo) { + free_dominance_info (CDI_DOMINATORS); + /* We need to cleanup the CFG first since otherwise SSA form can + be not up-to-date from the VN run. */ + if (todo & TODO_cleanup_cfg) + { + cleanup_tree_cfg (); + todo &= ~TODO_cleanup_cfg; + } rewrite_into_loop_closed_ssa (NULL, 0); scev_reset (); - free_dominance_info (CDI_DOMINATORS); } return todo; } diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index d9e160c..4782d47 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -1211,13 +1211,56 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb) // Check if a dominators can supply the range. if (range_from_dom (block_result, name, bb, RFD_FILL)) { - m_on_entry.set_bb_range (name, bb, block_result); if (DEBUG_RANGE_CACHE) { fprintf (dump_file, "Filled from dominator! : "); block_result.dump (dump_file); fprintf (dump_file, "\n"); } + // See if any equivalences can refine it. + if (m_oracle) + { + unsigned i; + bitmap_iterator bi; + // Query equivalences in read-only mode. + const_bitmap equiv = m_oracle->equiv_set (name, bb); + EXECUTE_IF_SET_IN_BITMAP (equiv, 0, i, bi) + { + if (i == SSA_NAME_VERSION (name)) + continue; + tree equiv_name = ssa_name (i); + basic_block equiv_bb = gimple_bb (SSA_NAME_DEF_STMT (equiv_name)); + + // Check if the equiv has any ranges calculated. + if (!m_gori.has_edge_range_p (equiv_name)) + continue; + + // Check if the equiv definition dominates this block + if (equiv_bb == bb || + (equiv_bb && !dominated_by_p (CDI_DOMINATORS, bb, equiv_bb))) + continue; + + Value_Range equiv_range (TREE_TYPE (equiv_name)); + if (range_from_dom (equiv_range, equiv_name, bb, RFD_READ_ONLY)) + { + if (block_result.intersect (equiv_range)) + { + if (DEBUG_RANGE_CACHE) + { + fprintf (dump_file, "Equivalence update! : "); + print_generic_expr (dump_file, equiv_name, TDF_SLIM); + fprintf (dump_file, "had range : "); + equiv_range.dump (dump_file); + fprintf (dump_file, " refining range to :"); + block_result.dump (dump_file); + fprintf (dump_file, "\n"); + } + } + } + } + } + + m_on_entry.set_bb_range (name, bb, block_result); gcc_checking_assert (m_workback.length () == 0); return; } diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index 6f907df..689d827 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -853,12 +853,13 @@ fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src) } // If SCEV is available, query if this PHI has any knonwn values. - if (scev_initialized_p () && !POINTER_TYPE_P (TREE_TYPE (phi_def))) + if (scev_initialized_p () + && !POINTER_TYPE_P (TREE_TYPE (phi_def))) { - value_range loop_range; class loop *l = loop_containing_stmt (phi); if (l && loop_outer (l)) { + Value_Range loop_range (type); range_of_ssa_name_with_loop_info (loop_range, phi_def, l, phi, src); if (!loop_range.varying_p ()) { @@ -1328,37 +1329,60 @@ fold_using_range::range_of_cond_expr (vrange &r, gassign *s, fur_source &src) return true; } +// Return the lower bound of R as a tree. + +static inline tree +tree_lower_bound (const vrange &r, tree type) +{ + if (is_a <irange> (r)) + return wide_int_to_tree (type, as_a <irange> (r).lower_bound ()); + // ?? Handle floats when they contain endpoints. + return NULL; +} + +// Return the upper bound of R as a tree. + +static inline tree +tree_upper_bound (const vrange &r, tree type) +{ + if (is_a <irange> (r)) + return wide_int_to_tree (type, as_a <irange> (r).upper_bound ()); + // ?? Handle floats when they contain endpoints. + return NULL; +} + // If SCEV has any information about phi node NAME, return it as a range in R. void -fold_using_range::range_of_ssa_name_with_loop_info (irange &r, tree name, +fold_using_range::range_of_ssa_name_with_loop_info (vrange &r, tree name, class loop *l, gphi *phi, fur_source &src) { gcc_checking_assert (TREE_CODE (name) == SSA_NAME); tree min, max, type = TREE_TYPE (name); - // FIXME: Remove the supports_p() once all this can handle floats, etc. - if (irange::supports_p (type) - && bounds_of_var_in_loop (&min, &max, src.query (), l, phi, name)) + if (bounds_of_var_in_loop (&min, &max, src.query (), l, phi, name)) { - if (TREE_CODE (min) != INTEGER_CST) + if (!is_gimple_constant (min)) { if (src.query ()->range_of_expr (r, min, phi) && !r.undefined_p ()) - min = wide_int_to_tree (type, r.lower_bound ()); + min = tree_lower_bound (r, type); else min = vrp_val_min (type); } - if (TREE_CODE (max) != INTEGER_CST) + if (!is_gimple_constant (max)) { if (src.query ()->range_of_expr (r, max, phi) && !r.undefined_p ()) - max = wide_int_to_tree (type, r.upper_bound ()); + max = tree_upper_bound (r, type); else max = vrp_val_max (type); } - r.set (min, max); + if (min && max) + { + r.set (min, max); + return; + } } - else - r.set_varying (type); + r.set_varying (type); } // ----------------------------------------------------------------------- @@ -1472,6 +1496,10 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge tree name; basic_block bb = gimple_bb (s); + range_op_handler handler (s); + if (!handler) + return; + if (e0) { // If this edge is never taken, ignore it. @@ -1500,8 +1528,6 @@ 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) { - range_op_handler handler (s); - gcc_checking_assert (handler); if (e0) { relation_kind relation = handler.op1_op2_relation (e0_range); diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index fbf6627..c2f381d 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -173,7 +173,7 @@ protected: void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code, 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 *, + void range_of_ssa_name_with_loop_info (vrange &, 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-path.cc b/gcc/gimple-range-path.cc index e1b9683..43e7526 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -479,32 +479,28 @@ path_range_query::compute_ranges_in_block (basic_block bb) p->set_root_oracle (nullptr); } - EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi) + gori_compute &g = m_ranger->gori (); + bitmap exports = g.exports (bb); + EXECUTE_IF_AND_IN_BITMAP (m_imports, exports, 0, i, bi) { tree name = ssa_name (i); - gori_compute &g = m_ranger->gori (); - bitmap exports = g.exports (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 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); + + set_cache (r, name); + if (DEBUG_SOLVER) { - Value_Range cached_range (TREE_TYPE (name)); - if (get_cache (cached_range, name)) - r.intersect (cached_range); - - set_cache (r, name); - if (DEBUG_SOLVER) - { - fprintf (dump_file, "outgoing_edge_range_p for "); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, " on edge %d->%d ", - e->src->index, e->dest->index); - fprintf (dump_file, "is "); - r.dump (dump_file); - fprintf (dump_file, "\n"); - } + fprintf (dump_file, "outgoing_edge_range_p for "); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " on edge %d->%d ", + e->src->index, e->dest->index); + fprintf (dump_file, "is "); + r.dump (dump_file); + fprintf (dump_file, "\n"); } } } diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc index fb8f973..ca5b9f3 100644 --- a/gcc/ipa-prop.cc +++ b/gcc/ipa-prop.cc @@ -2303,6 +2303,10 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi, { if (TREE_CODE (arg) == SSA_NAME && param_type + /* Limit the ranger query to integral types as the rest + of this file uses value_range's, which only hold + integers and pointers. */ + && irange::supports_p (TREE_TYPE (arg)) && get_range_query (cfun)->range_of_expr (vr, arg) && !vr.undefined_p ()) { diff --git a/gcc/match.pd b/gcc/match.pd index 330c1db..f82f94a 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1308,6 +1308,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (simplify (bit_not (plus:c (bit_not @0) @1)) (minus @0 @1)) +/* (~X - ~Y) -> Y - X. */ +(simplify + (minus (bit_not @0) (bit_not @1)) + (with { tree utype = unsigned_type_for (type); } + (convert (minus (convert:utype @1) (convert:utype @0))))) /* ~(X - Y) -> ~X + Y. */ (simplify @@ -3982,6 +3987,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (plus:c (mult:c (div @0 @1) @1) (mod @0 @1)) @0)) +/* x / y * y == x -> x % y == 0. */ +(simplify + (eq:c (mult:c (trunc_div:s @0 @1) @1) @0) + (if (TREE_CODE (TREE_TYPE (@0)) != COMPLEX_TYPE) + (eq (trunc_mod @0 @1) { build_zero_cst (TREE_TYPE (@0)); }))) + /* ((X /[ex] A) +- B) * A --> X +- A * B. */ (for op (plus minus) (simplify @@ -8055,3 +8066,8 @@ and, (if (TYPE_UNSIGNED (TREE_TYPE (@0))) (bit_and @0 @1) (cond (le @0 @1) @0 (bit_and @0 @1)))))) + +/* -x & 1 -> x & 1. */ +(simplify + (bit_and (negate @0) integer_onep@1) + (bit_and @0 @1)) diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc index 936adff..64e6308 100644 --- a/gcc/omp-expand.cc +++ b/gcc/omp-expand.cc @@ -1530,8 +1530,6 @@ expand_omp_taskreg (struct omp_region *region) expand_teams_call (new_bb, as_a <gomp_teams *> (entry_stmt)); else expand_task_call (region, new_bb, as_a <gomp_task *> (entry_stmt)); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_only_virtuals); } /* Information about members of an OpenACC collapsed loop nest. */ @@ -8191,9 +8189,6 @@ expand_omp_for (struct omp_region *region, gimple *inner_stmt) (enum built_in_function) next_ix, sched_arg, inner_stmt); } - - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_only_virtuals); } /* Expand code for an OpenMP sections directive. In pseudo code, we generate @@ -10591,13 +10586,10 @@ execute_expand_omp (void) expand_omp (root_omp_region); - if (flag_checking && !loops_state_satisfies_p (LOOPS_NEED_FIXUP)) - verify_loop_structure (); - cleanup_tree_cfg (); - omp_free_regions (); - return 0; + return (TODO_cleanup_cfg + | (gimple_in_ssa_p (cfun) ? TODO_update_ssa_only_virtuals : 0)); } /* OMP expansion -- the default pass, run before creation of SSA form. */ diff --git a/gcc/omp-simd-clone.cc b/gcc/omp-simd-clone.cc index 32649bc..58bd68b 100644 --- a/gcc/omp-simd-clone.cc +++ b/gcc/omp-simd-clone.cc @@ -1305,8 +1305,16 @@ simd_clone_adjust (struct cgraph_node *node) build_int_cst (TREE_TYPE (iter1), c)); gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); } + tree shift_cnt_conv = shift_cnt; + if (!useless_type_conversion_p (TREE_TYPE (mask), + TREE_TYPE (shift_cnt))) + { + shift_cnt_conv = make_ssa_name (TREE_TYPE (mask)); + g = gimple_build_assign (shift_cnt_conv, NOP_EXPR, shift_cnt); + gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); + } g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)), - RSHIFT_EXPR, mask, shift_cnt); + RSHIFT_EXPR, mask, shift_cnt_conv); gsi_insert_after (&gsi, g, GSI_CONTINUE_LINKING); mask = gimple_assign_lhs (g); g = gimple_build_assign (make_ssa_name (TREE_TYPE (mask)), diff --git a/gcc/postreload.cc b/gcc/postreload.cc index d1c99fe..41f61d3 100644 --- a/gcc/postreload.cc +++ b/gcc/postreload.cc @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see #include "function-abi.h" #include "rtl-iter.h" -static int reload_cse_noop_set_p (rtx); static bool reload_cse_simplify (rtx_insn *, rtx); static void reload_cse_regs_1 (void); static int reload_cse_simplify_set (rtx, rtx_insn *); @@ -74,16 +73,6 @@ reload_cse_regs (rtx_insn *first ATTRIBUTE_UNUSED) } } -/* See whether a single set SET is a noop. */ -static int -reload_cse_noop_set_p (rtx set) -{ - if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set))) - return 0; - - return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set)); -} - /* Try to simplify INSN. Return true if the CFG may have changed. */ static bool reload_cse_simplify (rtx_insn *insn, rtx testreg) @@ -118,7 +107,7 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg) this out, so it's safer to simplify before we delete. */ count += reload_cse_simplify_set (body, insn); - if (!count && reload_cse_noop_set_p (body)) + if (!count && cselib_redundant_set_p (body)) { if (check_for_inc_dec (insn)) delete_insn_and_edges (insn); @@ -157,7 +146,7 @@ reload_cse_simplify (rtx_insn *insn, rtx testreg) rtx part = XVECEXP (body, 0, i); if (GET_CODE (part) == SET) { - if (! reload_cse_noop_set_p (part)) + if (! cselib_redundant_set_p (part)) break; if (REG_P (SET_DEST (part)) && REG_FUNCTION_VALUE_P (SET_DEST (part))) diff --git a/gcc/profile.cc b/gcc/profile.cc index 08af512..96121d6 100644 --- a/gcc/profile.cc +++ b/gcc/profile.cc @@ -753,7 +753,8 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum) bb->count = profile_count::from_gcov_type (bb_gcov_count (bb)); else bb->count = profile_count::guessed_zero (); - if (dump_file && bb->index >= 0) + + if (dump_file && (dump_flags & TDF_DETAILS) && bb->index >= 0) { double freq1 = cnt.to_sreal_scale (old_entry_cnt).to_double (); double freq2 = bb->count.to_sreal_scale @@ -766,7 +767,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum) sum2 += freq2; } } - if (dump_file) + if (dump_file && (dump_flags & TDF_DETAILS)) { double nsum1 = 0, nsum2 = 0; stats.qsort (cmp_stats); @@ -776,8 +777,8 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum) nsum2 += stat.feedback; fprintf (dump_file, " Basic block %4i guessed freq: %12.3f" - " cummulative:%6.2f%% " - " feedback freq: %12.3f cummulative:%7.2f%%" + " cumulative:%6.2f%% " + " feedback freq: %12.3f cumulative:%7.2f%%" " cnt: 10%" PRId64 "\n", stat.bb->index, stat.guessed, nsum1 * 100 / sum1, diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 8e9d83e..4fbd96a 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -150,6 +150,50 @@ range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) cons return VREL_VARYING; } +// Return TRUE if OP1 and OP2 are known to be free of NANs. + +static inline bool +finite_operands_p (const frange &op1, const frange &op2) +{ + return (flag_finite_math_only + || (op1.get_nan ().no_p () + && op2.get_nan ().no_p ())); +} + +// Floating version of relop_early_resolve that takes into account NAN +// and -ffinite-math-only. + +inline bool +frelop_early_resolve (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel, relation_kind my_rel) +{ + // If either operand is undefined, return VARYING. + if (empty_range_varying (r, type, op1, op2)) + return true; + + // We can fold relations from the oracle when we know both operands + // are free of NANs, or when -ffinite-math-only. + return (finite_operands_p (op1, op2) + && relop_early_resolve (r, type, op1, op2, rel, my_rel)); +} + +// Default implementation of fold_range for relational operators. +// This amounts to passing on any known relations from the oracle, iff +// we know the operands are not NAN or -ffinite-math-only holds. + +static inline bool +default_frelop_fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel, relation_kind my_rel) +{ + if (frelop_early_resolve (r, type, op1, op2, rel, my_rel)) + return true; + + r.set_varying (type); + return true; +} + class foperator_identity : public range_operator_float { using range_operator_float::fold_range; @@ -172,6 +216,509 @@ class foperator_identity : public range_operator_float public: } fop_identity; +class foperator_equal : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + return default_frelop_fold_range (r, type, op1, op2, rel, VREL_EQ); + } + relation_kind op1_op2_relation (const irange &lhs) const final override + { + return equal_op1_op2_relation (lhs); + } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override + { + return op1_range (r, type, lhs, op1, rel); + } +} fop_equal; + +bool +foperator_equal::op1_range (frange &r, tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind rel) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 == op2 implies op1 is !NAN. + r.set_nan (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + // The FALSE side of op1 == op1 implies op1 is a NAN. + if (rel == VREL_EQ) + r.set_nan (fp_prop::YES); + break; + + default: + break; + } + return true; +} + +class foperator_not_equal : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + return default_frelop_fold_range (r, type, op1, op2, rel, VREL_NE); + } + relation_kind op1_op2_relation (const irange &lhs) const final override + { + return not_equal_op1_op2_relation (lhs); + } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; +} fop_not_equal; + +bool +foperator_not_equal::op1_range (frange &r, tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + break; + + case BRS_FALSE: + r.set_varying (type); + // The FALSE side of op1 != op2 implies op1 is !NAN. + r.set_nan (fp_prop::NO); + break; + + default: + break; + } + return true; +} + +class foperator_lt : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + return default_frelop_fold_range (r, type, op1, op2, rel, VREL_LT); + } + relation_kind op1_op2_relation (const irange &lhs) const final override + { + return lt_op1_op2_relation (lhs); + } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override; +} fop_lt; + +bool +foperator_lt::op1_range (frange &r, + tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 < op2 implies op1 is !NAN and !INF. + r.set_nan (fp_prop::NO); + r.set_inf (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + break; + + default: + break; + } + return true; +} + +bool +foperator_lt::op2_range (frange &r, + tree type, + const irange &lhs, + const frange &op1 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 < op2 implies op2 is !NAN and !NINF. + r.set_nan (fp_prop::NO); + r.set_ninf (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + break; + + default: + break; + } + return true; +} + +class foperator_le : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + return default_frelop_fold_range (r, type, op1, op2, rel, VREL_LE); + } + relation_kind op1_op2_relation (const irange &lhs) const final override + { + return le_op1_op2_relation (lhs); + } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override + { + return op1_range (r, type, lhs, op1, rel); + } +} fop_le; + +bool +foperator_le::op1_range (frange &r, + tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 <= op2 implies op1 is !NAN. + r.set_nan (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + break; + + default: + break; + } + return true; +} + +class foperator_gt : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + return default_frelop_fold_range (r, type, op1, op2, rel, VREL_GT); + } + relation_kind op1_op2_relation (const irange &lhs) const final override + { + return gt_op1_op2_relation (lhs); + } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override; +} fop_gt; + +bool +foperator_gt::op1_range (frange &r, + tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 > op2 implies op1 is !NAN and !NINF. + r.set_nan (fp_prop::NO); + r.set_ninf (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + break; + + default: + break; + } + return true; +} + +bool +foperator_gt::op2_range (frange &r, + tree type, + const irange &lhs, + const frange &op1 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 > op2 implies op2 is !NAN and !INF. + r.set_nan (fp_prop::NO); + r.set_inf (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + break; + + default: + break; + } + return true; +} + +class foperator_ge : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + return default_frelop_fold_range (r, type, op1, op2, rel, VREL_GE); + } + relation_kind op1_op2_relation (const irange &lhs) const final override + { + return ge_op1_op2_relation (lhs); + } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override + { + return op1_range (r, type, lhs, op1, rel); + } +} fop_ge; + +bool +foperator_ge::op1_range (frange &r, + tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 >= op2 implies op1 is !NAN. + r.set_nan (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + break; + + default: + break; + } + return true; +} + +// UNORDERED_EXPR comparison. + +class foperator_unordered : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + +public: + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override; + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override + { + return op1_range (r, type, lhs, op1, rel); + } +} fop_unordered; + +bool +foperator_unordered::fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind) const +{ + // UNORDERED is TRUE if either operand is a NAN. + if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ()) + r = range_true (type); + // UNORDERED is FALSE if neither operand is a NAN. + else if (op1.get_nan ().no_p () && op2.get_nan ().no_p ()) + r = range_false (type); + else + r = range_true_and_false (type); + return true; +} + +bool +foperator_unordered::op1_range (frange &r, tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // Since at least one operand must be NAN, if one of them is + // not, the other must be. + if (op2.get_nan ().no_p ()) + r.set_nan (fp_prop::YES); + break; + + case BRS_FALSE: + r.set_varying (type); + // A false UNORDERED means both operands are !NAN. + r.set_nan (fp_prop::NO); + break; + + default: + break; + } + return true; +} + +// ORDERED_EXPR comparison. + +class foperator_ordered : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; + +public: + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override; + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override + { + return op1_range (r, type, lhs, op1, rel); + } +} fop_ordered; + +bool +foperator_ordered::fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind) const +{ + // ORDERED is TRUE if neither operand is a NAN. + if (op1.get_nan ().no_p () && op2.get_nan ().no_p ()) + r = range_true (type); + // ORDERED is FALSE if either operand is a NAN. + else if (op1.get_nan ().yes_p () || op2.get_nan ().yes_p ()) + r = range_false (type); + else + r = range_true_and_false (type); + return true; +} + +bool +foperator_ordered::op1_range (frange &r, tree type, + const irange &lhs, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind rel) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + r.set_varying (type); + // The TRUE side of op1 ORDERED op2 implies op1 is !NAN. + r.set_nan (fp_prop::NO); + break; + + case BRS_FALSE: + r.set_varying (type); + // The FALSE side of op1 ORDERED op1 implies op1 is !NAN. + if (rel == VREL_EQ) + r.set_nan (fp_prop::NO); + break; + + default: + break; + } + return true; +} + +// Placeholder for unimplemented relational operators. + +class foperator_relop_unknown : public range_operator_float +{ + using range_operator_float::fold_range; + +public: + bool fold_range (irange &r, tree type, + const frange &, const frange &, + relation_kind) const final override + { + r.set_varying (type); + return true; + } +} fop_relop_unknown; + // Instantiate a range_op_table for floating point operations. static floating_op_table global_floating_table; @@ -185,6 +732,23 @@ floating_op_table::floating_op_table () set (PAREN_EXPR, fop_identity); set (OBJ_TYPE_REF, fop_identity); set (REAL_CST, fop_identity); + + // All the relational operators are expected to work, because the + // calculation of ranges on outgoing edges expect the handlers to be + // present. + set (EQ_EXPR, fop_equal); + set (NE_EXPR, fop_not_equal); + set (LT_EXPR, fop_lt); + set (LE_EXPR, fop_le); + set (GT_EXPR, fop_gt); + set (GE_EXPR, fop_ge); + set (UNLE_EXPR, fop_relop_unknown); + set (UNLT_EXPR, fop_relop_unknown); + set (UNGE_EXPR, fop_relop_unknown); + set (UNGT_EXPR, fop_relop_unknown); + set (UNEQ_EXPR, fop_relop_unknown); + set (ORDERED_EXPR, fop_ordered); + set (UNORDERED_EXPR, fop_unordered); } // Return a pointer to the range_operator_float instance, if there is diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index fa20665..7d09bf7 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -1366,11 +1366,35 @@ simplify_context::simplify_unary_operation_1 (rtx_code code, machine_mode mode, break; /* If operand is something known to be positive, ignore the ABS. */ - if (GET_CODE (op) == FFS || GET_CODE (op) == ABS - || val_signbit_known_clear_p (GET_MODE (op), - nonzero_bits (op, GET_MODE (op)))) + if (val_signbit_known_clear_p (GET_MODE (op), + nonzero_bits (op, GET_MODE (op)))) return op; + /* Using nonzero_bits doesn't (currently) work for modes wider than + HOST_WIDE_INT, so the following transformations help simplify + ABS for TImode and wider. */ + switch (GET_CODE (op)) + { + case ABS: + case CLRSB: + case FFS: + case PARITY: + case POPCOUNT: + case SS_ABS: + return op; + + case LSHIFTRT: + if (CONST_INT_P (XEXP (op, 1)) + && INTVAL (XEXP (op, 1)) > 0 + && is_a <scalar_int_mode> (mode, &int_mode) + && INTVAL (XEXP (op, 1)) < GET_MODE_PRECISION (int_mode)) + return op; + break; + + default: + break; + } + /* If operand is known to be only -1 or 0, convert ABS to NEG. */ if (is_a <scalar_int_mode> (mode, &int_mode) && (num_sign_bit_copies (op, int_mode) @@ -1615,6 +1639,24 @@ simplify_context::simplify_unary_operation_1 (rtx_code code, machine_mode mode, } } + /* We can canonicalize SIGN_EXTEND (op) as ZERO_EXTEND (op) when + we know the sign bit of OP must be clear. */ + if (val_signbit_known_clear_p (GET_MODE (op), + nonzero_bits (op, GET_MODE (op)))) + return simplify_gen_unary (ZERO_EXTEND, mode, op, GET_MODE (op)); + + /* (sign_extend:DI (subreg:SI (ctz:DI ...))) is (ctz:DI ...). */ + if (GET_CODE (op) == SUBREG + && subreg_lowpart_p (op) + && GET_MODE (SUBREG_REG (op)) == mode + && is_a <scalar_int_mode> (mode, &int_mode) + && is_a <scalar_int_mode> (GET_MODE (op), &op_mode) + && GET_MODE_PRECISION (int_mode) <= HOST_BITS_PER_WIDE_INT + && GET_MODE_PRECISION (op_mode) < GET_MODE_PRECISION (int_mode) + && (nonzero_bits (SUBREG_REG (op), mode) + & ~(GET_MODE_MASK (op_mode) >> 1)) == 0) + return SUBREG_REG (op); + #if defined(POINTERS_EXTEND_UNSIGNED) /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer @@ -1765,6 +1807,18 @@ simplify_context::simplify_unary_operation_1 (rtx_code code, machine_mode mode, op0_mode); } + /* (zero_extend:DI (subreg:SI (ctz:DI ...))) is (ctz:DI ...). */ + if (GET_CODE (op) == SUBREG + && subreg_lowpart_p (op) + && GET_MODE (SUBREG_REG (op)) == mode + && is_a <scalar_int_mode> (mode, &int_mode) + && is_a <scalar_int_mode> (GET_MODE (op), &op_mode) + && GET_MODE_PRECISION (int_mode) <= HOST_BITS_PER_WIDE_INT + && GET_MODE_PRECISION (op_mode) < GET_MODE_PRECISION (int_mode) + && (nonzero_bits (SUBREG_REG (op), mode) + & ~GET_MODE_MASK (op_mode)) == 0) + return SUBREG_REG (op); + #if defined(POINTERS_EXTEND_UNSIGNED) /* As we do not know which address space the pointer is referring to, we can do this only if the target does not support different pointer diff --git a/gcc/symtab.cc b/gcc/symtab.cc index 8670337..f2d96c0 100644 --- a/gcc/symtab.cc +++ b/gcc/symtab.cc @@ -894,7 +894,8 @@ symtab_node::dump_base (FILE *f) }; fprintf (f, "%s (%s)", dump_asm_name (), name ()); - dump_addr (f, " @", (void *)this); + if (dump_flags & TDF_ADDRESS) + dump_addr (f, " @", (void *)this); fprintf (f, "\n Type: %s", symtab_type_names[type]); if (definition) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 781bba7..fee24d2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,161 @@ +2022-08-07 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.target/i386/cmpti2.c: Add -mno-stv to dg-options. + +2022-08-07 Jakub Jelinek <jakub@redhat.com> + + PR c++/88174 + * g++.dg/cpp1y/constexpr-complex1.C: New test. + +2022-08-07 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.target/i386/cmpti1.c: New test case. + * gcc.target/i386/cmpti2.c: Likewise. + * gcc.target/i386/cmpti3.c: Likewise. + +2022-08-05 David Malcolm <dmalcolm@redhat.com> + + PR analyzer/105947 + * gcc.dg/analyzer/function-ptr-5.c: New test. + +2022-08-05 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106533 + * gcc.dg/tree-ssa/ldist-39.c: New testcase. + +2022-08-05 Haochen Gui <guihaoc@gcc.gnu.org> + + * lib/target-supports.exp (check_p9modulo_hw_available): Correct return + value. + +2022-08-04 Tamar Christina <tamar.christina@arm.com> + + * gcc.dg/subnot.c: New test. + +2022-08-04 Tamar Christina <tamar.christina@arm.com> + + PR middle-end/106519 + * gcc.dg/pr106519.c: New test. + +2022-08-04 Sam Feifer <sfeifer@redhat.com> + + PR tree-optimization/106243 + * gcc.dg/pr106243-1.c: New test. + * gcc.dg/pr106243.c: New test. + +2022-08-04 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106521 + * gcc.dg/torture/pr106521.c: New testcase. + +2022-08-03 Jose E. Marchesi <jose.marchesi@oracle.com> + + PR testsuite/106515 + * gcc.dg/debug/btf/btf-int-1.c: Fix regexps in + scan-assembler-times. + +2022-08-03 Tamar Christina <tamar.christina@arm.com> + + * gcc.dg/tree-ssa/split-path-1.c: Disable phi-opts so we don't optimize + code away. + * gcc.dg/tree-ssa/minmax-10.c: New test. + * gcc.dg/tree-ssa/minmax-11.c: New test. + * gcc.dg/tree-ssa/minmax-12.c: New test. + * gcc.dg/tree-ssa/minmax-13.c: New test. + * gcc.dg/tree-ssa/minmax-14.c: New test. + * gcc.dg/tree-ssa/minmax-15.c: New test. + * gcc.dg/tree-ssa/minmax-16.c: New test. + * gcc.dg/tree-ssa/minmax-3.c: New test. + * gcc.dg/tree-ssa/minmax-4.c: New test. + * gcc.dg/tree-ssa/minmax-5.c: New test. + * gcc.dg/tree-ssa/minmax-6.c: New test. + * gcc.dg/tree-ssa/minmax-7.c: New test. + * gcc.dg/tree-ssa/minmax-8.c: New test. + * gcc.dg/tree-ssa/minmax-9.c: New test. + +2022-08-03 Roger Sayle <roger@nextmovesoftware.com> + Uroš Bizjak <ubizjak@gmail.com> + + PR target/47949 + * gcc.target/i386/pr47949.c: New test case. + +2022-08-03 Roger Sayle <roger@nextmovesoftware.com> + + * gcc.target/i386/sse4_1-stv-7.c: New test case. + +2022-08-02 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/106510 + * gcc.dg/pr106510.c: New. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * gcc.dg/tree-ssa/vrp-float-1.c: Adjust test so it passes. + +2022-08-02 Andrew MacLeod <amacleod@redhat.com> + + PR tree-optimization/106474 + * g++.dg/pr106474.C: New. + +2022-08-02 Jose E. Marchesi <jose.marchesi@oracle.com> + + * gcc.dg/debug/btf/btf-int-1.c: Do not check for char bits in + bti_encoding and check for bool bits. + +2022-08-02 Immad Mir <mirimmad@outlook.com> + + PR analyzer/106298 + * gcc.dg/analyzer/fd-1.c: Add tests for 'creat'. + * gcc.dg/analyzer/fd-2.c: Likewise. + * gcc.dg/analyzer/fd-4.c: Likewise. + * gcc.dg/analyzer/fd-dup-1.c: New tests. + +2022-08-02 Aldy Hernandez <aldyh@redhat.com> + + * g++.dg/opt/pr94589-2.C: XFAIL. + * gcc.dg/tree-ssa/vrp-float-1.c: New test. + * gcc.dg/tree-ssa/vrp-float-11.c: New test. + * gcc.dg/tree-ssa/vrp-float-3.c: New test. + * gcc.dg/tree-ssa/vrp-float-4.c: New test. + * gcc.dg/tree-ssa/vrp-float-6.c: New test. + * gcc.dg/tree-ssa/vrp-float-7.c: New test. + * gcc.dg/tree-ssa/vrp-float-8.c: New test. + +2022-08-02 Richard Biener <rguenther@suse.de> + + PR tree-optimization/106497 + * gcc.dg/torture/pr106497.c: New testcase. + +2022-08-01 David Malcolm <dmalcolm@redhat.com> + + * gcc.target/i386/addr-space-typeck-1.c: New test. + * gcc.target/i386/addr-space-typeck-2.c: New test. + +2022-08-01 Roger Sayle <roger@nextmovesoftware.com> + Uroš Bizjak <ubizjak@gmail.com> + + PR target/106481 + * gcc.target/i386/pr106481.c: New test case. + +2022-08-01 H.J. Lu <hjl.tools@gmail.com> + + PR target/83782 + * gcc.target/i386/pr83782-1.c: Require non-ia32. + * gcc.target/i386/pr83782-2.c: Likewise. + * gcc.target/i386/pr83782-3.c: New test. + +2022-08-01 Jose E. Marchesi <jose.marchesi@oracle.com> + + PR debug/106263 + * gcc.dg/debug/btf/btf-function-4.c: New test. + * gcc.dg/debug/btf/btf-function-5.c: Likewise. + +2022-08-01 Sam Feifer <sfeifer@redhat.com> + + PR tree-optimization/104992 + * g++.dg/pr104992-1.C: New test. + * gcc.dg/pr104992.c: New test. + 2022-07-31 Roger Sayle <roger@nextmovesoftware.com> H.J. Lu <hjl.tools@gmail.com> diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C new file mode 100644 index 0000000..8bb24cb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C @@ -0,0 +1,24 @@ +// PR c++/88174 +// { dg-do compile { target c++14 } } + +constexpr bool +foo (double x, double y, double z, double w) +{ + __complex__ double a = 0; + __real__ a = x; + __imag__ a = y; +#if __cpp_constexpr >= 201907L + __complex__ double b; + __real__ b = z; +#else + __complex__ double b = z; +#endif + __imag__ b = w; + a += b; + a -= b; + a *= b; + a /= b; + return __real__ a == x && __imag__ a == y; +} + +static_assert (foo (1.0, 2.0, 3.0, 4.0), ""); diff --git a/gcc/testsuite/g++.dg/opt/pr94589-2.C b/gcc/testsuite/g++.dg/opt/pr94589-2.C index e9ef84b..370deea 100644 --- a/gcc/testsuite/g++.dg/opt/pr94589-2.C +++ b/gcc/testsuite/g++.dg/opt/pr94589-2.C @@ -1,7 +1,7 @@ // PR tree-optimization/94589 // { dg-do compile { target c++20 } } // { dg-options "-O2 -g0 -ffast-math -fdump-tree-optimized" } -// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 12 "optimized" } } +// { dg-final { scan-tree-dump-times "\[ij]_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) \[ij]_\[0-9]+\\(D\\)" 12 "optimized" { xfail *-*-* } } } // { dg-final { scan-tree-dump-times "i_\[0-9]+\\(D\\) (?:<|<=|==|!=|>|>=) 5\\.0" 12 "optimized" } } #include <compare> diff --git a/gcc/testsuite/g++.dg/pr104992-1.C b/gcc/testsuite/g++.dg/pr104992-1.C new file mode 100644 index 0000000..f5696b2 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr104992-1.C @@ -0,0 +1,30 @@ +/* PR tree-optimization/104992 */ +/* { dg-do run } */ +/* { dg-options "-O2"} */ + +#include "../gcc.dg/pr104992.c" + +int main () { + + /* Should be true. */ + if (!foo(6, 3) + || !bar(12, 2) + || !baz(34, 17) + || !qux(50, 10) + || !fred(16, 8) + || !baz(-9, 3) + || !baz(9, -3) + || !baz(-9, -3) + ) { + __builtin_abort(); + } + + /* Should be false. */ + if (foo(5, 30) + || bar(72, 27) + || baz(42, 15)) { + __builtin_abort(); + } + + return 0; +} diff --git a/gcc/testsuite/g++.dg/pr106474.C b/gcc/testsuite/g++.dg/pr106474.C new file mode 100644 index 0000000..6cd37a2 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr106474.C @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-evrp " } */ + +void foo(); +static void __attribute__ ((noinline)) DCEMarker0_() {foo ();} + +void f(bool s, bool c) { + if ((!c == !s) && !c) { + if (s) { + DCEMarker0_(); + } + } +} + +// With equivalences, vrp should be able to remove all IFs. +/* { dg-final { scan-tree-dump-not "goto" "evrp" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr93776.c b/gcc/testsuite/gcc.c-torture/compile/pr93776.c index c407a62..3852736 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr93776.c +++ b/gcc/testsuite/gcc.c-torture/compile/pr93776.c @@ -1,5 +1,5 @@ -/* { dg-do compile } */ -/* { dg-options "-O1" } */ +/* This used to ICE in SRA as SRA got + confused by the zero signed assigment. */ struct empty {}; struct s { int i; }; diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-1.c b/gcc/testsuite/gcc.dg/analyzer/fd-1.c index 8a72e63..5b85a33 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-1.c @@ -3,6 +3,13 @@ int open(const char *, int mode); #define O_WRONLY 1 #define O_RDWR 2 +typedef enum { + S_IRWXU + // etc +} mode_t; + +int creat (const char *, mode_t mode); + void test_1 (const char *path) { @@ -37,3 +44,17 @@ void test_4 (const char *path) /* { dg-message "\\(1\\) leaks here" "" { target *-*-* } .-1 } */ } +void +test_5 (const char *path, mode_t mode) +{ + creat (path, mode); /* { dg-warning "leak of file descriptor \\\[CWE-775\\\]" } */ +} + +void +test_6 (const char *path, mode_t mode) +{ + int fd = creat (path, mode); + return; /* { dg-warning "leak of file descriptor 'fd' \\\[CWE-775\\\]" } */ +} + + diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-2.c b/gcc/testsuite/gcc.dg/analyzer/fd-2.c index d794b46..10c9ecd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-2.c @@ -5,6 +5,13 @@ void close(int fd); #define O_RDWR 2 #define STDIN 0 +typedef enum { + S_IRWXU + // etc +} mode_t; + +int creat (const char *, mode_t mode); + void test_1 (const char *path) { @@ -46,4 +53,12 @@ test_4 () int fd = -1; close(fd); close(fd); +} + +void +test_5 (const char *path, mode_t mode) +{ + int fd = creat (path, mode); + close(fd); + close(fd); /* { dg-warning "double 'close' of file descriptor 'fd' \\\[CWE-1341\\\]" "warning" } */ }
\ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-4.c b/gcc/testsuite/gcc.dg/analyzer/fd-4.c index ecd787c..6b8fca5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-4.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-4.c @@ -9,6 +9,12 @@ int read (int fd, void *buf, int nbytes); #define O_WRONLY 1 #define O_RDWR 2 +typedef enum { + S_IRWXU + // etc +} mode_t; + +int creat (const char *, mode_t mode); void test_1 (const char *path, void *buf) @@ -69,4 +75,27 @@ test_5 (const char *path) int fd = open (path, O_RDWR); close(fd); printf("%d", fd); /* { dg-bogus "'printf' on a closed file descriptor 'fd'" } */ -}
\ No newline at end of file +} + + +void +test_6 (const char *path, mode_t mode, void *buf) +{ + int fd = creat (path, mode); + if (fd != -1) + { + read (fd, buf, 1); /* { dg-warning "'read' on write-only file descriptor 'fd'" } */ + close(fd); + } +} + +void +test_7 (const char *path, mode_t mode, void *buf) +{ + int fd = creat (path, mode); + if (fd != -1) + { + write (fd, buf, 1); + close(fd); + } +} diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c b/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c new file mode 100644 index 0000000..eba2570 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/fd-dup-1.c @@ -0,0 +1,223 @@ +int open(const char *, int mode); +void close(int fd); +int dup (int old_fd); +int dup2 (int old_fd, int new_fd); +int dup3 (int old_fd, int new_fd, int flags); +int write (int fd, void *buf, int nbytes); +int read (int fd, void *buf, int nbytes); +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 + +void test_1 (const char *path) +{ + int old_fd = open (path, O_RDWR); + int new_fd = dup (old_fd); /* { dg-warning "'dup' on possibly invalid file descriptor 'old_fd'" } */ + close(old_fd); + close(new_fd); +} + +void test_2 (const char *path) +{ + int old_fd = open (path, O_RDWR); + if (old_fd != -1) + { + int new_fd = dup (old_fd); + close(old_fd); + return; /* { dg-warning "leak of file descriptor 'new_fd' \\\[CWE-775\\\]" } */ + } +} + +void test_3 (const char *path, void *buf) +{ + int old_fd = open (path, O_RDWR); + if (old_fd != -1) + { + int new_fd = dup (old_fd); + write (new_fd, buf, 1); /* { dg-warning "'write' on possibly invalid file descriptor 'new_fd'" } */ + close (new_fd); + close(old_fd); + } +} + + +void test_5 (const char *path, void *buf) +{ + int old_fd = open (path, O_RDWR); + if (old_fd != -1) + { + int new_fd = dup (old_fd); + if (new_fd != -1) + { + write (new_fd, buf, 1); + close (new_fd); + + } + close(old_fd); + } +} + + +void test_7 (const char *path) +{ + int old_fd = open (path, O_RDWR); + dup2 (old_fd, 4); /* { dg-warning "'dup2' on possibly invalid file descriptor 'old_fd'" } */ + close(old_fd); +} + +void test_8 (const char *path) +{ + int old_fd = open (path, O_RDWR); + int new_fd = open (path, O_RDWR); + if (old_fd != -1) + { + dup2 (old_fd, new_fd); /* { dg-warning "'dup2' on possibly invalid file descriptor 'new_fd'" } */ + close (old_fd); + } + close (new_fd); +} + +void test_9 (const char *path, void *buf) +{ + int old_fd = open (path, O_RDWR); + + if (old_fd != -1) + { + int new_fd = open (path, O_RDWR); + if (new_fd != -1) + { + int lhs = dup2 (old_fd, new_fd); + write (lhs, buf, 1); /* { dg-warning "'write' on possibly invalid file descriptor 'lhs'" } */ + close(new_fd); + close(lhs); + } + close(old_fd); + } +} + +void test_10 (const char *path, int flags) +{ + int old_fd = open (path, O_RDWR); + int new_fd = open (path, O_RDWR); + if (old_fd != -1) + { + dup3 (old_fd, new_fd, flags); /* { dg-warning "'dup3' on possibly invalid file descriptor 'new_fd'" } */ + close(old_fd); + + } + close(new_fd); +} + +void test_11 (const char *path, int flags) +{ + int old_fd = open (path, O_RDWR); + int new_fd = open (path, O_RDWR); + if (new_fd != -1) + { + dup3 (old_fd, new_fd, flags); /* { dg-warning "'dup3' on possibly invalid file descriptor 'old_fd'" } */ + close(new_fd); + + } + close(old_fd); +} + +void test_12 (const char *path, void *buf) +{ + int old_fd = open (path, O_RDONLY); + if (old_fd != -1) + { + int new_fd = dup (old_fd); + if (new_fd != -1) + { + write (new_fd, buf, 1); /* { dg-warning "'write' on read-only file descriptor 'new_fd'" } */ + close(new_fd); + } + close(old_fd); + } +} + +void test_13 (const char *path, void *buf) +{ + int old_fd = open (path, O_WRONLY); + if (old_fd != -1) + { + int new_fd = dup (old_fd); + if (new_fd != -1) + { + read (new_fd, buf, 1); /* { dg-warning "'read' on write-only file descriptor 'new_fd'" } */ + close(new_fd); + } + close(old_fd); + } +} + +void test_14 (const char *path, void *buf) +{ + int old_fd = open (path, O_RDWR); + if (old_fd != -1) + { + int new_fd = dup (old_fd); + if (new_fd != -1) + { + write (new_fd, buf, 1); + read (new_fd, buf, 1); + close(new_fd); + } + close(old_fd); + } +} + +void test_15 (void *buf) +{ + int fd = dup(0); + read (fd, buf, 1); /* { dg-warning "'read' on possibly invalid file descriptor 'fd'" } */ + close(fd); +} + +void test_16 (void *buf) +{ + int fd = dup(1); + if (fd != -1) + { + write (fd, buf, 1); + close (fd); + } +} + +void test_17 (const char *path) +{ + int fd = open (path, O_RDWR); + close(fd); + dup (fd); /* { dg-warning "'dup' on closed file descriptor 'fd'" } */ + dup2 (fd, 4); /* { dg-warning "'dup2' on closed file descriptor 'fd'" } */ +} + +void +test_18 (const char *path, void *buf) +{ + int fd = open (path, O_RDWR); + if (fd != -1) + { + int fd2 = dup2 (fd, 3); + read (fd2, buf, 1); /* { dg-warning "'read' on possibly invalid file descriptor 'fd2'" } */ + close(fd); + close(fd2); + } +} + +void +test_19 (const char *path, void *buf) +{ + int fd = open (path, O_WRONLY); + if (fd != -1) + { + int fd2 = dup2 (fd, 4); + if (fd2 != -1) + { + read (fd2, buf, 1); /* { dg-warning "'read' on write-only file descriptor 'fd2'" } */ + close(fd2); + } + close (fd); + } + +}
\ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c b/gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c new file mode 100644 index 0000000..3c46f28 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c @@ -0,0 +1,42 @@ +#define NULL ((void *)0) + +void calling_null_fn_ptr_1 (void) +{ + void (*fn_ptr) (void) = NULL; + fn_ptr (); /* { dg-warning "jump through null pointer" } */ +} + +int calling_null_fn_ptr_2 (void) +{ + int (*fn_ptr) (void) = NULL; + return fn_ptr (); /* { dg-warning "jump through null pointer" } */ +} + +typedef void (*void_void_fn_ptr) (void); + +void calling_const_fn_ptr (void) +{ + void_void_fn_ptr fn_ptr = (void_void_fn_ptr)0xffd2; + return fn_ptr (); +} + +void skipping_init (int flag) +{ + void_void_fn_ptr fn_ptr = NULL; + if (flag) /* { dg-message "branch" } */ + fn_ptr = (void_void_fn_ptr)0xffd2; + fn_ptr (); /* { dg-warning "jump through null pointer" } */ +} + +struct callbacks +{ + void_void_fn_ptr on_redraw; + void_void_fn_ptr on_cleanup; +}; + +void test_callbacks (void) +{ + struct callbacks cb; + __builtin_memset (&cb, 0, sizeof (cb)); + cb.on_cleanup (); /* { dg-warning "jump through null pointer" } */ +} diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-function-4.c b/gcc/testsuite/gcc.dg/debug/btf/btf-function-4.c new file mode 100644 index 0000000..fd31244 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-function-4.c @@ -0,0 +1,14 @@ +/* Test BTF linkage for functions. + + We expect to see one BTF_KIND_FUNC type with static linkage encoded in the + BTF type's vlen field. */ + +/* { dg-do compile } */ +/* { dg-options "-O0 -gbtf -dA" } */ + +/* { dg-final { scan-assembler-times "btt_info: kind=12, kflag=0, linkage=0" 1 } } */ + +static int funfoo (void) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-function-5.c b/gcc/testsuite/gcc.dg/debug/btf/btf-function-5.c new file mode 100644 index 0000000..12ee97f --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-function-5.c @@ -0,0 +1,14 @@ +/* Test BTF linkage for functions. + + We expect to see one BTF_KIND_FUNC type with global linkage encoded in the + BTF type's vlen field. */ + +/* { dg-do compile } */ +/* { dg-options "-O0 -gbtf -dA" } */ + +/* { dg-final { scan-assembler-times "btt_info: kind=12, kflag=0, linkage=1" 1 } } */ + +int funfoo (void) +{ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-int-1.c b/gcc/testsuite/gcc.dg/debug/btf/btf-int-1.c index 2381dec..e1ed198 100644 --- a/gcc/testsuite/gcc.dg/debug/btf/btf-int-1.c +++ b/gcc/testsuite/gcc.dg/debug/btf/btf-int-1.c @@ -4,7 +4,8 @@ | 0 | encoding | offset | 00 | bits | encoding: signed 1 << 24 - char 2 << 24 + char 2 << 24 (not used) + bool 4 << 24 All offsets in this test should be 0. This test does _not_ check number of bits, as it may vary between targets. @@ -13,13 +14,14 @@ /* { dg-do compile } */ /* { dg-options "-O0 -gbtf -dA" } */ -/* Check for 8 BTF_KIND_INT types. */ -/* { dg-final { scan-assembler-times "\[\t \]0x1000000\[\t \]+\[^\n\]*btt_info" 8 } } */ +/* Check for 9 BTF_KIND_INT types. */ +/* { dg-final { scan-assembler-times "\[\t \]0x1000000\[\t \]+\[^\n\]*btt_info" 9 } } */ -/* Check the signed/char flags, but not bit size. */ -/* { dg-final { scan-assembler-times "\[\t \]0x10000..\[\t \]+\[^\n\]*bti_encoding" 3 } } */ -/* { dg-final { scan-assembler-times "\[\t \]0x20000..\[\t \]+\[^\n\]*bti_encoding" 1 } } */ -/* { dg-final { scan-assembler-times "\[\t \]0x30000..\[\t \]+\[^\n\]*bti_encoding" 1 } } */ +/* Check the signed flags, but not bit size. */ +/* { dg-final { scan-assembler-times "\[\t \]0x10000\[0-9a-zA-Z\]{2}\[\t \]+\[^\n\]*bti_encoding" 4 } } */ +/* { dg-final { scan-assembler-times "\[\t \]0x\[0-9a-zA-Z\]{2}\[\t \]+\[^\n\]*bti_encoding" 3 } } */ +/* { dg-final { scan-assembler-times "\[\t \]0x\[0-9a-zA-Z\]\[\t \]+\[^\n\]*bti_encoding" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]0x40000\[0-9a-zA-Z\]{2}\[\t \]+\[^\n\]*bti_encoding" 1 } } */ /* Check that there is a string entry for each type name. */ /* { dg-final { scan-assembler-times "ascii \"unsigned char.0\"\[\t \]+\[^\n\]*btf_string" 1 } } */ @@ -42,3 +44,5 @@ signed int f = -66; unsigned long int g = 77; signed long int h = 88; + +_Bool x = 1; diff --git a/gcc/testsuite/gcc.dg/pr104992.c b/gcc/testsuite/gcc.dg/pr104992.c new file mode 100644 index 0000000..b9d91a1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr104992.c @@ -0,0 +1,57 @@ +/* PR tree-optimization/104992 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +#define vector __attribute__((vector_size(4*sizeof(int)))) + +/* Form from PR. */ +__attribute__((noipa)) unsigned foo(unsigned x, unsigned y) +{ + return x / y * y == x; +} + +__attribute__((noipa)) unsigned bar(unsigned x, unsigned y) { + return x == x / y * y; +} + +/* Signed test case. */ +__attribute__((noipa)) unsigned baz (int x, int y) { + return x / y * y == x; +} + +/* Changed order. */ +__attribute__((noipa)) unsigned qux (unsigned x, unsigned y) { + return y * (x / y) == x; +} + +/* Test for forward propogation. */ +__attribute__((noipa)) unsigned corge(unsigned x, unsigned y) { + int z = x / y; + int q = z * y; + return q == x; +} + +/* Test vector case. */ +__attribute__((noipa)) vector int thud(vector int x, vector int y) { + return x / y * y == x; +} + +/* Complex type should not simplify because mod is different. */ +__attribute__((noipa)) int goo(_Complex int x, _Complex int y) +{ + _Complex int z = x / y; + _Complex int q = z * y; + return q == x; +} + +/* Wrong order. */ +__attribute__((noipa)) unsigned fred (unsigned x, unsigned y) { + return y * x / y == x; +} + +/* Wrong pattern. */ +__attribute__((noipa)) unsigned waldo (unsigned x, unsigned y, unsigned z) { + return x / y * z == x; +} + +/* { dg-final {scan-tree-dump-times " % " 9 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr106243-1.c b/gcc/testsuite/gcc.dg/pr106243-1.c new file mode 100644 index 0000000..b1dbe5c --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106243-1.c @@ -0,0 +1,18 @@ +/* PR tree-optimization/106243 */ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#include "pr106243.c" + +int main () { + + if (foo(3) != 1 + || bar(-6) != 0 + || baz(17) != 1 + || qux(-128) != 0 + || foo(127) != 1) { + __builtin_abort(); + } + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr106243.c b/gcc/testsuite/gcc.dg/pr106243.c new file mode 100644 index 0000000..ee2706f --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106243.c @@ -0,0 +1,43 @@ +/* PR tree-optimization/106243 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +#define vector __attribute__((vector_size(4*sizeof(int)))) + +/* Test from PR. */ +__attribute__((noipa)) int foo (int x) { + return -x & 1; +} + +/* Other test from PR. */ +__attribute__((noipa)) int bar (int x) { + return (0 - x) & 1; +} + +/* Forward propogation. */ +__attribute__((noipa)) int baz (int x) { + x = -x; + return x & 1; +} + +/* Commutative property. */ +__attribute__((noipa)) int qux (int x) { + return 1 & -x; +} + +/* Vector test case. */ +__attribute__((noipa)) vector int waldo (vector int x) { + return -x & 1; +} + +/* Should not simplify. */ +__attribute__((noipa)) int thud (int x) { + return -x & 2; +} + +/* Should not simplify. */ +__attribute__((noipa)) int corge (int x) { + return -x & -1; +} + +/* { dg-final {scan-tree-dump-times "-" 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/pr106510.c b/gcc/testsuite/gcc.dg/pr106510.c new file mode 100644 index 0000000..24e9112 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106510.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +void foo (); +void ine_ok() { + float y, x; + if (x < y || x > y || y) + foo (); +} + diff --git a/gcc/testsuite/gcc.dg/pr106519.c b/gcc/testsuite/gcc.dg/pr106519.c new file mode 100644 index 0000000..3d4662d --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr106519.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ + +int bytestart, bytemem_0_0, modlookup_l_p; + +void +modlookup_l() { + long j; + while (modlookup_l_p) + while (bytestart && j && bytemem_0_0) + j = j + 1; +} diff --git a/gcc/testsuite/gcc.dg/subnot.c b/gcc/testsuite/gcc.dg/subnot.c new file mode 100644 index 0000000..d621bac --- /dev/null +++ b/gcc/testsuite/gcc.dg/subnot.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +float g(float a, float b) +{ + return ~(int)a - ~(int)b; +} + +/* { dg-final { scan-tree-dump-not "~" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/torture/pr106497.c b/gcc/testsuite/gcc.dg/torture/pr106497.c new file mode 100644 index 0000000..601200d --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr106497.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fno-tree-dce" } */ + +int n; + +__attribute__ ((pure,returns_twice)) int +bar (void); + +int +foo (int x) +{ + n = 0; + + bar (); + + if (x && n) + return 0; + + foo (x); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr106521.c b/gcc/testsuite/gcc.dg/torture/pr106521.c new file mode 100644 index 0000000..05c8ce5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr106521.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-floop-unroll-and-jam --param unroll-jam-min-percent=0" } */ + +short a, b, e; +volatile long c; +long d; +int main() { + for (; d; d++) { + long g = a = 1; + for (; a; a++) { + g++; + c; + } + g && (b = e); + } + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-39.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-39.c new file mode 100644 index 0000000..3ef7286 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-39.c @@ -0,0 +1,16 @@ +/* PR/106533 */ +/* { dg-options "-O2 -fdump-tree-ldist-optimized" } */ + +void bar (int *a, int * __restrict b) +{ + for (int k = 0; k < 10; k++) + { + for (int j = 0; j < 100000; ++j) + a[j] = b[j]; + __builtin_printf ("Foo!"); + } +} + +/* The stmt with side-effects in the outer loop should not prevent + distribution of the inner loop of the loop nest. */ +/* { dg-final { scan-tree-dump "optimized: Loop . distributed: split to 0 loops and 1 library calls" "ldist" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-10.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-10.c new file mode 100644 index 0000000..5899536 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-10.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +#include <stdint.h> + +uint8_t three_max (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + xc=~xc; + xm=~xm; + xy=~xy; + if (xc > xm) { + xk = (uint8_t) (xc > xy ? xc : xy); + } else { + xk = (uint8_t) (xm > xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "= ~" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-11.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-11.c new file mode 100644 index 0000000..1c2ef01 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-11.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +#include <stdint.h> + +uint8_t three_minmax1 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + xc=~xc; + xm=~xm; + xy=~xy; + if (xc > xm) { + xk = (uint8_t) (xc < xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "= ~" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-12.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-12.c new file mode 100644 index 0000000..3d0c07d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-12.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_minmax3 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + xc=~xc; + xm=~xm; + xy=~xy; + if (xc > xm) { + xk = (uint8_t) (xy < xc ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-13.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-13.c new file mode 100644 index 0000000..c0d0f27 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-13.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_minmax2 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + xc=~xc; + xm=~xm; + xy=~xy; + if (xc > xm) { + xk = (uint8_t) (xc > xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-14.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-14.c new file mode 100644 index 0000000..9c0cadb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-14.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +#include <stdint.h> + +uint8_t three_minmax11 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + xc=~xc; + xm=~xm; + xy=~xy; + if (xc < xm) { + xk = (uint8_t) (xc > xy ? xc : xy); + } else { + xk = (uint8_t) (xm > xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "= ~" 1 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-15.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-15.c new file mode 100644 index 0000000..1d97a16 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-15.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> +#include <stdbool.h> + +uint8_t three_min (uint8_t xc, uint8_t xm, uint8_t xy, bool m) { + uint8_t xk; + if (xc) + { + if (xc < xm) { + xk = (uint8_t) (xc < xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + } + + return xk; +} +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-16.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-16.c new file mode 100644 index 0000000..89377a2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-16.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt -g" } */ + +#include <stdint.h> + +uint8_t three_min (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc < xm) { + xk = (uint8_t) (xc < xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-3.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-3.c new file mode 100644 index 0000000..de3b2e9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-3.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_min (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc < xm) { + xk = (uint8_t) (xc < xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 0 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-4.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-4.c new file mode 100644 index 0000000..0b6d667 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-4.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_max (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc > xm) { + xk = (uint8_t) (xc > xy ? xc : xy); + } else { + xk = (uint8_t) (xm > xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 0 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-5.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-5.c new file mode 100644 index 0000000..650601a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-5.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_minmax1 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc > xm) { + xk = (uint8_t) (xc < xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-6.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-6.c new file mode 100644 index 0000000..a628f6d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-6.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_minmax3 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc > xm) { + xk = (uint8_t) (xy < xc ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-7.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-7.c new file mode 100644 index 0000000..cb42412 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-7.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_minmax2 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc > xm) { + xk = (uint8_t) (xc > xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 1 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-8.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-8.c new file mode 100644 index 0000000..9cd050e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-8.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-phiopt" } */ + +#include <stdint.h> + +uint8_t three_minmax11 (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + if (xc < xm) { + xk = (uint8_t) (xc > xy ? xc : xy); + } else { + xk = (uint8_t) (xm > xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "phiopt1" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "phiopt1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-9.c b/gcc/testsuite/gcc.dg/tree-ssa/minmax-9.c new file mode 100644 index 0000000..24f5802 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-9.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +#include <stdint.h> + +uint8_t three_min (uint8_t xc, uint8_t xm, uint8_t xy) { + uint8_t xk; + xc=~xc; + xm=~xm; + xy=~xy; + if (xc < xm) { + xk = (uint8_t) (xc < xy ? xc : xy); + } else { + xk = (uint8_t) (xm < xy ? xm : xy); + } + return xk; +} + +/* { dg-final { scan-tree-dump-times "= ~" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/split-path-1.c b/gcc/testsuite/gcc.dg/tree-ssa/split-path-1.c index 8b23ef4..902dde4 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/split-path-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/split-path-1.c @@ -1,5 +1,5 @@ /* { dg-do run } */ -/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details --param max-jump-thread-duplication-stmts=20" } */ +/* { dg-options "-O2 -fsplit-paths -fdump-tree-split-paths-details --param max-jump-thread-duplication-stmts=20 -fno-ssa-phiopt" } */ #include <stdio.h> #include <stdlib.h> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c new file mode 100644 index 0000000..5be5426 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-1.c @@ -0,0 +1,19 @@ +// { dg-do compile } +// { dg-options "-O2 -fdisable-tree-ethread -fdisable-tree-fre1 -fdump-tree-evrp-details" } + +void bar (); +void george (); + +float +foo (float x, float y) +{ + if (x == x) + { + if (x > y) + bar(); + if (x == x) + george(); + } +} + +// { dg-final { scan-tree-dump-times "Folded into: if \\(1 != 0\\)" 1 "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c new file mode 100644 index 0000000..2f4dc87 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-11.c @@ -0,0 +1,26 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-thread-jumps -fdump-tree-evrp" } + +extern void link_error (); + +void fast_sqrt (float); + +float test (float x) +{ + float y = x*x; + if (y >= 0.f) + { + if (__builtin_isnan (y)) + link_error (); + else + fast_sqrt (y); + + if (!__builtin_isnan (y)) + fast_sqrt (y); + else + link_error (); + } +} + +// { dg-final { scan-tree-dump-times "fast_sqrt" 2 "evrp" } } +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c new file mode 100644 index 0000000..c659abb --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-3.c @@ -0,0 +1,18 @@ +// { dg-do compile } +// { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-evrp" } + +void link_error (); + +void +foo (double x, double y) +{ + if (x == y) + { + if (__builtin_isnan (x)) + link_error (); + if (__builtin_isnan (y)) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c new file mode 100644 index 0000000..8643674 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-4.c @@ -0,0 +1,16 @@ +// { dg-do compile } +// { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-evrp" } + +void link_error (); + +void +foo (double x, double y) +{ + if (x > y) + { + if (__builtin_isnan (x) || __builtin_isnan (y)) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c new file mode 100644 index 0000000..145d186 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-6.c @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-options "-O2 -fdisable-tree-ethread -fdump-tree-evrp" } + +void bar (); + +void +foo (double x, double y) +{ + if (x > y) + ; + else if (!__builtin_isnan (x) && !__builtin_isnan (y)) + { + // If x and y are not NAN, the x <= y relationship holds, and the + // following conditional can be folded away. + if (x <= y) + bar (); + } +} + +// { dg-final { scan-tree-dump-times "Folding predicate x_.* <= y_.* to 1" 1 "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c new file mode 100644 index 0000000..92af870 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-7.c @@ -0,0 +1,14 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-tree-forwprop -fno-tree-ccp -fno-tree-fre -fdump-tree-evrp" } + +extern void link_error (); + +void +foo () +{ + float z = 0.0; + if (__builtin_isnan (z)) + link_error (); +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c new file mode 100644 index 0000000..9170150 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-8.c @@ -0,0 +1,26 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-thread-jumps -fdump-tree-evrp" } + +extern void link_error (); + +void fast_sqrt (float); + +float test (float x) +{ + float y = x*x; + if (y >= 0.f) + { + if (__builtin_isnan (y)) + link_error (); + else + fast_sqrt (y); + + if (!__builtin_isnan (y)) + fast_sqrt (y); + else + link_error (); + } +} + +// { dg-final { scan-tree-dump-times "fast_sqrt" 2 "evrp" } } +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } diff --git a/gcc/testsuite/gcc.target/i386/addr-space-typeck-1.c b/gcc/testsuite/gcc.target/i386/addr-space-typeck-1.c new file mode 100644 index 0000000..84d27b0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/addr-space-typeck-1.c @@ -0,0 +1,22 @@ +/* { dg-options "-std=gnu90" } */ + +void * +test_gs_to_generic (void __seg_gs *p) +{ + return p; /* { dg-error "return from pointer to non-enclosed address space" "error" } */ + /* { dg-message "expected 'void \\*' but pointer is of type '__seg_gs void \\*'" "note" { target *-*-* } .-1 } */ +} + +void __seg_gs * +test_generic_to_gs (void *q) +{ + return q; /* { dg-error "return from pointer to non-enclosed address space" "error" } */ + /* { dg-message "expected '__seg_gs void \\*' but pointer is of type 'void \\*'" "note" { target *-*-* } .-1 } */ +} + +extern void use_double_deref (char __seg_gs **buffer); + +void test_double_deref (char __seg_gs *buf) +{ + use_double_deref (&buf); +} diff --git a/gcc/testsuite/gcc.target/i386/addr-space-typeck-2.c b/gcc/testsuite/gcc.target/i386/addr-space-typeck-2.c new file mode 100644 index 0000000..d9fb9a7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/addr-space-typeck-2.c @@ -0,0 +1,25 @@ +/* Tests of C frontend's address space type-checking. */ +/* { dg-options "-std=gnu90 -fdiagnostics-show-caret" } */ + +/* Verify that we emit helpful diagnostics at a mismatching address space + at a function call, and that the underlined locations are correct. */ + +extern void expects_seg_gs (int i, void __seg_gs *param, int j); /* { dg-line "decl_line" } */ + +void +test_bad_call (void *ptr) +{ + expects_seg_gs (0, ptr, 1); /* { dg-line "err_line" } */ +} + +/* { dg-error "passing argument 2 of 'expects_seg_gs' from pointer to non-enclosed address space" "" { target *-*-* } err_line } */ +/* { dg-begin-multiline-output "" } + expects_seg_gs (0, ptr, 1); + ^~~ + { dg-end-multiline-output "" } */ + +/* { dg-message "expected '__seg_gs void \\*' but argument is of type 'void \\*'" "" { target *-*-* } decl_line } */ +/* { dg-begin-multiline-output "" } + extern void expects_seg_gs (int i, void __seg_gs *param, int j); + ~~~~~~~~~~~~~~~^~~~~ + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.target/i386/cmpti1.c b/gcc/testsuite/gcc.target/i386/cmpti1.c new file mode 100644 index 0000000..1c5f121 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cmpti1.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ +int eq(__int128 x, __int128 y) { return x == y; } +int ne(__int128 x, __int128 y) { return x != y; } +/* { dg-final { scan-assembler-times "xorq" 4 } } */ +/* { dg-final { scan-assembler-times "setne" 1 } } */ +/* { dg-final { scan-assembler-times "sete" 1 } } */ + diff --git a/gcc/testsuite/gcc.target/i386/cmpti2.c b/gcc/testsuite/gcc.target/i386/cmpti2.c new file mode 100644 index 0000000..ba7dd72 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cmpti2.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2 -mno-stv" } */ + +__int128 x; +__int128 y; + +int eq() { return x == y; } +int ne() { return x != y; } + +/* { dg-final { scan-assembler-times "xorq" 4 } } */ +/* { dg-final { scan-assembler-times "setne" 1 } } */ +/* { dg-final { scan-assembler-times "sete" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/cmpti3.c b/gcc/testsuite/gcc.target/i386/cmpti3.c new file mode 100644 index 0000000..302efd2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cmpti3.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2" } */ + +__int128 x; +int foo() +{ + __int128 t = 0x1234567890abcdefLL; + return x == t; +} + +/* { dg-final { scan-assembler-times "movabsq" 1 } } */ +/* { dg-final { scan-assembler-times "xorq" 1 } } */ +/* { dg-final { scan-assembler-not "xorl" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr106481.c b/gcc/testsuite/gcc.target/i386/pr106481.c new file mode 100644 index 0000000..8cc7048 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr106481.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2 -fno-dce -fno-forward-propagate -fno-rerun-cse-after-loop -Wno-psabi" } */ + +typedef int V __attribute__((vector_size (64))); +typedef __int128 W __attribute__((vector_size (64))); + +W w; +V bar (void); + +void +foo (V v, W) +{ + foo ((V){4, ~0}, (W) v); + foo (v, w); + bar (); +} + diff --git a/gcc/testsuite/gcc.target/i386/pr47949.c b/gcc/testsuite/gcc.target/i386/pr47949.c new file mode 100644 index 0000000..a0524b1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr47949.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-Oz" } */ +/* { dg-additional-options "-mregparm=2" { target ia32 } } */ + +int foo(int x, int y) +{ + return y; +} + +long bar(long x, long y) +{ + return y; +} + +/* { dg-final { scan-assembler-times "xchg" 2 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr83782-1.c b/gcc/testsuite/gcc.target/i386/pr83782-1.c index ce97b12..8567434 100644 --- a/gcc/testsuite/gcc.target/i386/pr83782-1.c +++ b/gcc/testsuite/gcc.target/i386/pr83782-1.c @@ -1,4 +1,4 @@ -/* { dg-do compile } */ +/* { dg-do compile { target { ! ia32 } } } */ /* { dg-require-ifunc "" } */ /* { dg-options "-O2 -fpic" } */ @@ -20,7 +20,5 @@ bar(void) return foo; } -/* { dg-final { scan-assembler {leal[ \t]foo@GOTOFF\(%[^,]*\),[ \t]%eax} { target ia32 } } } */ -/* { dg-final { scan-assembler {lea(?:l|q)[ \t]foo\(%rip\),[ \t]%(?:e|r)ax} { target { ! ia32 } } } } */ -/* { dg-final { scan-assembler-not "foo@GOT\\\(" { target ia32 } } } */ -/* { dg-final { scan-assembler-not "foo@GOTPCREL\\\(" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler {lea(?:l|q)[ \t]foo\(%rip\),[ \t]%(?:e|r)ax} } } */ +/* { dg-final { scan-assembler-not "foo@GOTPCREL\\\(" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr83782-2.c b/gcc/testsuite/gcc.target/i386/pr83782-2.c index e25d258..a654ded 100644 --- a/gcc/testsuite/gcc.target/i386/pr83782-2.c +++ b/gcc/testsuite/gcc.target/i386/pr83782-2.c @@ -1,4 +1,4 @@ -/* { dg-do compile } */ +/* { dg-do compile { target { ! ia32 } } } */ /* { dg-require-ifunc "" } */ /* { dg-options "-O2 -fpic" } */ @@ -20,7 +20,5 @@ bar(void) return foo; } -/* { dg-final { scan-assembler {leal[ \t]foo@GOTOFF\(%[^,]*\),[ \t]%eax} { target ia32 } } } */ /* { dg-final { scan-assembler {lea(?:l|q)[ \t]foo\(%rip\),[ \t]%(?:e|r)ax} { target { ! ia32 } } } } */ -/* { dg-final { scan-assembler-not "foo@GOT\\\(" { target ia32 } } } */ /* { dg-final { scan-assembler-not "foo@GOTPCREL\\\(" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr83782-3.c b/gcc/testsuite/gcc.target/i386/pr83782-3.c new file mode 100644 index 0000000..1536481 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr83782-3.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ +/* { dg-require-ifunc "" } */ +/* { dg-require-effective-target pie } */ +/* { dg-options "-fpie -pie" } */ + +#include <stdio.h> + +static int __attribute__((noinline)) +implementation (void) +{ + printf ("'ere I am JH\n"); + return 0; +} + +static __typeof__ (implementation) *resolver (void) +{ + return (void *)implementation; +} + +extern int magic (void) __attribute__ ((ifunc ("resolver"))); + +__attribute__ ((weak)) +int +call_magic (int (*ptr) (void)) +{ + return ptr (); +} + +int main () +{ + return call_magic (magic); +} diff --git a/gcc/testsuite/gcc.target/i386/sse4_1-stv-7.c b/gcc/testsuite/gcc.target/i386/sse4_1-stv-7.c new file mode 100644 index 0000000..b0d5fce --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse4_1-stv-7.c @@ -0,0 +1,18 @@ +/* { dg-do compile { target int128 } } */ +/* { dg-options "-O2 -msse4.1 -mstv -mno-stackrealign" } */ + +unsigned __int128 a; +unsigned __int128 b; + +void foo() +{ + a = b << 16; +} + +void bar() +{ + a = b >> 16; +} + +/* { dg-final { scan-assembler "pslldq" } } */ +/* { dg-final { scan-assembler "psrldq" } } */ diff --git a/gcc/testsuite/gdc.test/compilable/backendfloatoptim.d b/gcc/testsuite/gdc.test/compilable/backendfloatoptim.d new file mode 100644 index 0000000..7ec9f61 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/backendfloatoptim.d @@ -0,0 +1,10 @@ +// REQUIRED_ARGS: -O -inline + +//https://issues.dlang.org/show_bug.cgi?id=20143 +real fun(int x) { return 0.0; } + +double bug() +{ + // value passed to fun is irrelevant + return 0.0 / fun(420); +} diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle3.d b/gcc/testsuite/gdc.test/compilable/cppmangle3.d index 93e49c7..82c68f7 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle3.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle3.d @@ -45,16 +45,12 @@ alias Alias(T) = T; static assert(is(Alias!(__traits(parent, Foo.bar)) == Foo)); extern(C++, "std"): -debug = 456; debug = def; -version = 456; version = def; extern(C++, "std") { - debug = 456; debug = def; - version = 456; version = def; } diff --git a/gcc/testsuite/gdc.test/compilable/must_use_initialize.d b/gcc/testsuite/gdc.test/compilable/must_use_initialize.d new file mode 100644 index 0000000..8caec43 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/must_use_initialize.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=23236 +// can't initialize a @mustuse member in constructor + +import core.attribute; + +@mustuse struct MyError { } + +struct S +{ + MyError lastError; + + this(int x) + { + this.lastError = MyError(); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/noreturn1.d b/gcc/testsuite/gdc.test/compilable/noreturn1.d index 5bba9ba..e648a56 100644 --- a/gcc/testsuite/gdc.test/compilable/noreturn1.d +++ b/gcc/testsuite/gdc.test/compilable/noreturn1.d @@ -122,3 +122,31 @@ noreturn testdg(noreturn delegate() dg) { dg(); } + +noreturn func() +{ + while(1) + { + } +} +alias AliasSeq(T...) = T; +alias Types = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, + long, ulong, char, wchar, dchar, float, double, + real); +void noreturnImplicit() +{ + /* + Testing both ways because, although the underlying table + is symmetrical the code that calls into it may be buggy. + */ + { + int x = 2 + func(); + int y = func() + 2; + } + foreach(T; Types) + { + T value; + auto x = value + throw new Exception("Hello"); + auto y = (throw new Exception("wow")) + value; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test20832.d b/gcc/testsuite/gdc.test/compilable/test20832.d new file mode 100644 index 0000000..25617a9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test20832.d @@ -0,0 +1,12 @@ +// PERMUTE_ARGS: -preview=dip1000 +// https://issues.dlang.org/show_bug.cgi?id=20823 + +void boo(T)( scope void delegate(T[] data) fun) {} +void goo(T)(/+scope+/ void delegate(T[] data) fun) {} + +void main() +{ + void Execute(int[] data) {} + goo(&Execute); + boo(&Execute); +} diff --git a/gcc/testsuite/gdc.test/compilable/test21177.d b/gcc/testsuite/gdc.test/compilable/test21177.d index b3b613b..b485304 100644 --- a/gcc/testsuite/gdc.test/compilable/test21177.d +++ b/gcc/testsuite/gdc.test/compilable/test21177.d @@ -4,15 +4,19 @@ DISABLED: win TEST_OUTPUT: --- compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(111): Deprecation: more format specifiers than 0 arguments compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments -compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments -compilable/test21177.d(203): Deprecation: format specifier `"%m"` is invalid -compilable/test21177.d(204): Deprecation: format specifier `"%m"` is invalid -compilable/test21177.d(205): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*` -compilable/test21177.d(206): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*` +compilable/test21177.d(154): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(155): Deprecation: more format specifiers than 0 arguments +compilable/test21177.d(202): Deprecation: format specifier `"%m"` is invalid +compilable/test21177.d(203): Deprecation: argument `d` for format specification `"%mc"` must be `char**`, not `int` +compilable/test21177.d(204): Deprecation: argument `c` for format specification `"%ms"` must be `char**`, not `char*` +compilable/test21177.d(205): Deprecation: format specifier `"%ml"` is invalid +compilable/test21177.d(206): Deprecation: argument `d` for format specification `"%mlc"` must be `wchar_t**`, not `int` +compilable/test21177.d(207): Deprecation: argument `c` for format specification `"%mls"` must be `wchar_t**`, not `char*` --- */ @@ -27,50 +31,45 @@ void main() #line 100 printf("%m this is a string in errno"); printf("%s %m", "str".ptr, 2); - printf("%a", 2.); + printf("%m %a", 2.); printf("%m %m %s"); + printf("%m"); printf("%*m"); - + pragma(msg, "compilable/test21177.d(111): Deprecation: more format specifiers than 0 arguments"); + } + else + { + pragma(msg, "compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments"); + printf("%m"); + } + { char* a, b; - sscanf("salut poilu", "%a %m", a, b); + sscanf("salut poilu", "%ms %m[^\n]", &a, &b); assert(!strcmp(a, b)); free(a); free(b); - char* t, p; - sscanf("Tomate Patate", "%ms %as", t, p); + char* t; wchar_t* p; + sscanf("Tomate Patate", "%mc %mlc", &t, &p); free(t); free(p); #line 150 sscanf("150", "%m"); sscanf("151", "%ms"); - sscanf("152", "%a"); - sscanf("153", "%as"); - - pragma(msg, "compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments"); - pragma(msg, "compilable/test21177.d(203): Deprecation: format specifier `\"%m\"` is invalid"); - pragma(msg, "compilable/test21177.d(204): Deprecation: format specifier `\"%m\"` is invalid"); - pragma(msg, "compilable/test21177.d(205): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`"); - pragma(msg, "compilable/test21177.d(206): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`"); - } - else - { - // fake it - pragma(msg, "compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments"); - pragma(msg, "compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments"); - pragma(msg, "compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments"); - pragma(msg, "compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments"); - pragma(msg, "compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments"); + sscanf("152", "%mc"); + sscanf("153", "%ml"); + sscanf("154", "%mls"); + sscanf("155", "%mlc"); #line 200 - printf("%m"); - char* c; + int d; sscanf("204", "%m", c); - sscanf("205", "%ms", c); - sscanf("206", "%a", c); - sscanf("207", "%as", c); - + sscanf("205", "%mc", d); + sscanf("206", "%ms", c); + sscanf("207", "%ml", d); + sscanf("208", "%mlc", d); + sscanf("209", "%mls", c); } } diff --git a/gcc/testsuite/gdc.test/compilable/test21432.d b/gcc/testsuite/gdc.test/compilable/test21432.d new file mode 100644 index 0000000..2c83e24 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21432.d @@ -0,0 +1,25 @@ +// https://issues.dlang.org/show_bug.cgi?id=21432 +auto issue21432() +{ + enum int[] a = []; + return a; +} + +enum test21432a = issue21432; + +/////////////////////// + +double issue21432b(double r) +{ + enum double[4] poly = [ + 0x1.ffffffffffdbdp-2, + 0x1.555555555543cp-3, + 0x1.55555cf172b91p-5, + 0x1.1111167a4d017p-7, + ]; + + immutable r2 = r * r; + return r + r2 * (poly[0] + r * poly[1]) + r2 * r2 * (poly[2] + r * poly[3]); +} + +enum test21432b = issue21432b(-0x1p-1); diff --git a/gcc/testsuite/gdc.test/compilable/test22390.d b/gcc/testsuite/gdc.test/compilable/test22390.d new file mode 100644 index 0000000..f045416c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test22390.d @@ -0,0 +1,8 @@ +// https://issues.dlang.org/show_bug.cgi?id=22390 + +int main() +{ + noreturn[] empty; + assert(empty == empty); + return 0; +} diff --git a/gcc/testsuite/gdc.test/compilable/test23082.d b/gcc/testsuite/gdc.test/compilable/test23082.d new file mode 100644 index 0000000..9df4e4e --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23082.d @@ -0,0 +1,17 @@ +// https://issues.dlang.org/show_bug.cgi?id=23082 + +/* +TEST_OUTPUT: +--- +bar +--- +*/ + +void foo()() {} +alias bar = foo; +void bar() { } + +void main() +{ + pragma(msg, __traits(parent, main).bar.stringof); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23166.d b/gcc/testsuite/gdc.test/compilable/test23166.d new file mode 100644 index 0000000..66da4cd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23166.d @@ -0,0 +1,22 @@ +// REQUIRED_ARGS: -inline + +// https://issues.dlang.org/show_bug.cgi?id=23166 + +// seg fault with -inline + +bool __equals(scope const char[] lhs, scope const char[] rhs) +{ + if (lhs.length != rhs.length) + return false; + + { + import core.stdc.string : memcmp; + return lhs.length == 0; + } + return true; +} + +int test(string type) +{ + return __equals(type, "as-is"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23172.d b/gcc/testsuite/gdc.test/compilable/test23172.d new file mode 100644 index 0000000..18b6d4c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23172.d @@ -0,0 +1,33 @@ +// https://issues.dlang.org/show_bug.cgi?id=23172 + +enum E : ubyte { // `ubyte` is needed to trigger the bug + A, + B, +} + +struct S { + E e; +} + +void compiles(bool b, S s) { + E e = b ? E.A : s.e; +} + +void errors(bool b, const ref S s) { + E e = b ? E.A : s.e; +} + +// from https://issues.dlang.org/show_bug.cgi?id=23188 + +enum Status : byte +{ + A, B, C +} + +Status foo() +{ + Status t = Status.A; + const Status s = t; + + return (s == Status.A) ? Status.B : s; // <-- here +} diff --git a/gcc/testsuite/gdc.test/compilable/test23235.d b/gcc/testsuite/gdc.test/compilable/test23235.d new file mode 100644 index 0000000..99772ad --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23235.d @@ -0,0 +1,20 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23235 + */ + +@safe: + +void awkk(string[] ppp...) +{ +} + +void bark(string[] foo...) { + awkk(foo); +} + +void cack(string[] bar...) { + bark(bar); +} + +void test() { + cack("abc", "def"); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23256.d b/gcc/testsuite/gdc.test/compilable/test23256.d new file mode 100644 index 0000000..1e57201 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23256.d @@ -0,0 +1,6 @@ +/* REQUIRED_ARGS: -os=windows + */ + +// https://issues.dlang.org/show_bug.cgi?id=23256 + +void test23256() { } diff --git a/gcc/testsuite/gdc.test/compilable/test23262.d b/gcc/testsuite/gdc.test/compilable/test23262.d new file mode 100644 index 0000000..96da272 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23262.d @@ -0,0 +1,17 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23262 + */ + +struct T() +{ + string[] tags; + + this(string[] tags...) + { + this.tags = tags; // don't infer `return` attribute for `tags` + } +} + +void test() +{ + T!() t; +} diff --git a/gcc/testsuite/gdc.test/compilable/testgotoskips.d b/gcc/testsuite/gdc.test/compilable/testgotoskips.d new file mode 100644 index 0000000..659b5f7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/testgotoskips.d @@ -0,0 +1,17 @@ +/* + Tests to defend against false positives from the goto skips over decl errors +*/ +// https://issues.dlang.org/show_bug.cgi?id=23271 +class A { + private static A[] active; + private void test() { + foreach(a; active) { + if(a is this) + goto label; + } + // used to say Error: `goto` skips declaration of variable `s.A.test.__appendtmp4` at s.d(...) + active ~= this; + label: + return; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d index 1fdf5a5..8360e1a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d @@ -1,12 +1,20 @@ /* TEST_OUTPUT: --- -fail_compilation/attributediagnostic.d(16): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1` -fail_compilation/attributediagnostic.d(18): which calls `attributediagnostic.layer0` -fail_compilation/attributediagnostic.d(20): which calls `attributediagnostic.system` -fail_compilation/attributediagnostic.d(22): which was inferred `@system` because of: -fail_compilation/attributediagnostic.d(22): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not -fail_compilation/attributediagnostic.d(17): `attributediagnostic.layer1` is declared here +fail_compilation/attributediagnostic.d(24): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1` +fail_compilation/attributediagnostic.d(26): which calls `attributediagnostic.layer0` +fail_compilation/attributediagnostic.d(28): which calls `attributediagnostic.system` +fail_compilation/attributediagnostic.d(30): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(30): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not +fail_compilation/attributediagnostic.d(25): `attributediagnostic.layer1` is declared here +fail_compilation/attributediagnostic.d(46): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system1` +fail_compilation/attributediagnostic.d(35): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(35): cast from `uint` to `int*` not allowed in safe code +fail_compilation/attributediagnostic.d(33): `attributediagnostic.system1` is declared here +fail_compilation/attributediagnostic.d(47): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system2` +fail_compilation/attributediagnostic.d(41): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(41): `@safe` function `system2` cannot call `@system` `fsys` +fail_compilation/attributediagnostic.d(39): `attributediagnostic.system2` is declared here --- */ @@ -19,5 +27,22 @@ auto layer0() { system(); } auto system() { - asm {} + asm {} +} + +auto system1() +{ + int* x = cast(int*) 0xDEADBEEF; +} + +auto fsys = function void() @system {}; +auto system2() +{ + fsys(); +} + +void main() @safe +{ + system1(); + system2(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/chkformat.d b/gcc/testsuite/gdc.test/fail_compilation/chkformat.d index e9ed241..fa8915e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/chkformat.d +++ b/gcc/testsuite/gdc.test/fail_compilation/chkformat.d @@ -169,3 +169,21 @@ void test409() { char* p; printf("%llu", p); } void test410() { char* p; printf("%lld", p); } void test411() { char* p; printf("%ju", p); } void test412() { char* p; printf("%jd", p); } + +/* https://issues.dlang.org/show_bug.cgi?id=23247 +TEST_OUTPUT: +--- +fail_compilation/chkformat.d(501): Deprecation: argument `p` for format specification `"%a"` must be `double`, not `char*` +fail_compilation/chkformat.d(502): Deprecation: argument `p` for format specification `"%La"` must be `real`, not `char*` +fail_compilation/chkformat.d(503): Deprecation: argument `p` for format specification `"%a"` must be `float*`, not `char*` +fail_compilation/chkformat.d(504): Deprecation: argument `p` for format specification `"%la"` must be `double*`, not `char*` +fail_compilation/chkformat.d(505): Deprecation: argument `p` for format specification `"%La"` must be `real*`, not `char*` +--- +*/ +#line 500 + +void test501() { char* p; printf("%a", p); } +void test502() { char* p; printf("%La", p); } +void test503() { char* p; scanf("%a", p); } +void test504() { char* p; scanf("%la", p); } +void test505() { char* p; scanf("%La", p); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d index 416d563..7b2eca7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d @@ -1,15 +1,17 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10319.d(27): Error: `pure` function `D main` cannot call impure function `diag10319.foo` -fail_compilation/diag10319.d(27): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` -fail_compilation/diag10319.d(16): `diag10319.foo` is declared here -fail_compilation/diag10319.d(28): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` -fail_compilation/diag10319.d(28): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` -fail_compilation/diag10319.d(18): `diag10319.bar!int.bar` is declared here -fail_compilation/diag10319.d(27): Error: function `diag10319.foo` is not `nothrow` -fail_compilation/diag10319.d(28): Error: function `diag10319.bar!int.bar` is not `nothrow` -fail_compilation/diag10319.d(25): Error: function `D main` may throw but is marked as `nothrow` +fail_compilation/diag10319.d(29): Error: `pure` function `D main` cannot call impure function `diag10319.foo` +fail_compilation/diag10319.d(29): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` +fail_compilation/diag10319.d(18): `diag10319.foo` is declared here +fail_compilation/diag10319.d(30): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` +fail_compilation/diag10319.d(30): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` +fail_compilation/diag10319.d(23): which was inferred `@system` because of: +fail_compilation/diag10319.d(23): cannot take address of local `x` in `@safe` function `bar` +fail_compilation/diag10319.d(20): `diag10319.bar!int.bar` is declared here +fail_compilation/diag10319.d(29): Error: function `diag10319.foo` is not `nothrow` +fail_compilation/diag10319.d(30): Error: function `diag10319.bar!int.bar` is not `nothrow` +fail_compilation/diag10319.d(27): Error: function `D main` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d index 279d62a..1be0f1e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d @@ -1,12 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11198.d(15): Error: version `blah` declaration must be at module level -fail_compilation/diag11198.d(16): Error: debug `blah` declaration must be at module level -fail_compilation/diag11198.d(17): Error: version `1` level declaration must be at module level -fail_compilation/diag11198.d(18): Error: debug `2` level declaration must be at module level -fail_compilation/diag11198.d(19): Error: identifier or integer expected, not `""` -fail_compilation/diag11198.d(20): Error: identifier or integer expected, not `""` +fail_compilation/diag11198.d(17): Error: version `blah` declaration must be at module level +fail_compilation/diag11198.d(18): Error: debug `blah` declaration must be at module level +fail_compilation/diag11198.d(19): Deprecation: `version = <integer>` is deprecated, use version identifiers instead +fail_compilation/diag11198.d(19): Error: version `1` level declaration must be at module level +fail_compilation/diag11198.d(20): Deprecation: `debug = <integer>` is deprecated, use debug identifiers instead +fail_compilation/diag11198.d(20): Error: debug `2` level declaration must be at module level +fail_compilation/diag11198.d(21): Error: identifier or integer expected, not `""` +fail_compilation/diag11198.d(22): Error: identifier or integer expected, not `""` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d index f6e764b..1d37a1e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/diag12829.d(12): Error: function `diag12829.test1` is `@nogc` yet allocates closures with the GC -fail_compilation/diag12829.d(15): diag12829.test1.__lambda2 closes over variable x at fail_compilation/diag12829.d(14) -fail_compilation/diag12829.d(19): diag12829.test1.bar closes over variable x at fail_compilation/diag12829.d(14) -fail_compilation/diag12829.d(26): Error: function `diag12829.test2` is `@nogc` yet allocates closures with the GC -fail_compilation/diag12829.d(31): diag12829.test2.S.foo closes over variable x at fail_compilation/diag12829.d(28) +fail_compilation/diag12829.d(12): Error: function `diag12829.test1` is `@nogc` yet allocates closure for `test1()` with the GC +fail_compilation/diag12829.d(15): `diag12829.test1.__lambda2` closes over variable `x` at fail_compilation/diag12829.d(14) +fail_compilation/diag12829.d(19): `diag12829.test1.bar` closes over variable `x` at fail_compilation/diag12829.d(14) +fail_compilation/diag12829.d(26): Error: function `diag12829.test2` is `@nogc` yet allocates closure for `test2()` with the GC +fail_compilation/diag12829.d(31): `diag12829.test2.S.foo` closes over variable `x` at fail_compilation/diag12829.d(28) --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail118.d b/gcc/testsuite/gdc.test/fail_compilation/fail118.d index 3df797d..a526b90 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail118.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail118.d @@ -1,15 +1,17 @@ /* TEST_OUTPUT: --- -fail_compilation/fail118.d(43): Error: invalid `foreach` aggregate `Iter` of type `Iter` -fail_compilation/fail118.d(43): maybe define `opApply()`, range primitives, or use `.tupleof` -fail_compilation/fail118.d(44): Error: invalid `foreach` aggregate `Iter` of type `Iter` -fail_compilation/fail118.d(44): maybe define `opApply()`, range primitives, or use `.tupleof` -fail_compilation/fail118.d(47): Error: invalid `foreach` aggregate `s` of type `S*` -fail_compilation/fail118.d(49): Error: undefined identifier `unknown` -fail_compilation/fail118.d(37): Error: undefined identifier `doesNotExist` -fail_compilation/fail118.d(51): Error: template instance `fail118.error!()` error instantiating -fail_compilation/fail118.d(51): Error: invalid `foreach` aggregate `error()` of type `void` +fail_compilation/fail118.d(45): Error: invalid `foreach` aggregate `Iter` of type `Iter` +fail_compilation/fail118.d(45): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/fail118.d(45): https://dlang.org/phobos/std_range_primitives.html#isInputRange +fail_compilation/fail118.d(46): Error: invalid `foreach` aggregate `Iter` of type `Iter` +fail_compilation/fail118.d(46): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/fail118.d(46): https://dlang.org/phobos/std_range_primitives.html#isInputRange +fail_compilation/fail118.d(49): Error: invalid `foreach` aggregate `s` of type `S*` +fail_compilation/fail118.d(51): Error: undefined identifier `unknown` +fail_compilation/fail118.d(39): Error: undefined identifier `doesNotExist` +fail_compilation/fail118.d(53): Error: template instance `fail118.error!()` error instantiating +fail_compilation/fail118.d(53): Error: invalid `foreach` aggregate `error()` of type `void` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20547.d b/gcc/testsuite/gdc.test/fail_compilation/fail20547.d deleted file mode 100644 index c14977d..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20547.d +++ /dev/null @@ -1,15 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail20547.d(12): Error: cannot create a `string[string]` with `new` -fail_compilation/fail20547.d(14): Error: cannot create a `string[string]` with `new` ---- -*/ - -void main() -{ - //https://issues.dlang.org/show_bug.cgi?id=11790 - string[string] crash = new string[string]; - //https://issues.dlang.org/show_bug.cgi?id=20547 - int[string] c = new typeof(crash); -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22134.d b/gcc/testsuite/gdc.test/fail_compilation/fail22134.d new file mode 100644 index 0000000..5a4933e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22134.d @@ -0,0 +1,17 @@ +// https://issues.dlang.org/show_bug.cgi?id=22134 +/* REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/fail22134.d(12): Deprecation: `this.arr[i]` has no effect +--- +*/ +struct StackBuffer +{ + auto opIndex(size_t i) + { + return arr[i]; + } + +private: + void[] arr; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23181.d b/gcc/testsuite/gdc.test/fail_compilation/fail23181.d new file mode 100644 index 0000000..519244c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23181.d @@ -0,0 +1,16 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23181 +TEST_OUTPUT: +--- +$p:druntime/import/core/lifetime.d$($n$): Error: struct `fail23181.fail23181.NoPostblit` is not copyable because it has a disabled postblit +$p:druntime/import/core/internal/array/construction.d$($n$): Error: template instance `core.lifetime.copyEmplace!(NoPostblit, NoPostblit)` error instantiating +fail_compilation/fail23181.d(15): instantiated from here: `_d_arraysetctor!(NoPostblit[], NoPostblit)` +--- +*/ +void fail23181() +{ + struct NoPostblit + { + @disable this(this); + } + NoPostblit[4] noblit23181 = NoPostblit(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail261.d b/gcc/testsuite/gdc.test/fail_compilation/fail261.d index 85da957..d807dc8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail261.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail261.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail261.d(19): Error: invalid `foreach` aggregate `range` of type `MyRange` -fail_compilation/fail261.d(19): maybe define `opApply()`, range primitives, or use `.tupleof` +fail_compilation/fail261.d(20): Error: invalid `foreach` aggregate `range` of type `MyRange` +fail_compilation/fail261.d(20): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/fail261.d(20): https://dlang.org/phobos/std_range_primitives.html#isInputRange --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail58.d b/gcc/testsuite/gdc.test/fail_compilation/fail58.d index 1557055..89b2351 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail58.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail58.d @@ -7,7 +7,7 @@ fail_compilation/fail58.d(30): Error: function `fail58.SomeFunc(dchar[] pText, o fail_compilation/fail58.d(30): cannot pass argument `""` of type `string` to parameter `dchar[] pText` --- */ -debug(1) import std.stdio; +debug import std.stdio; const int anything = -1000; // Line #2 dchar[] SomeFunc( dchar[] pText, out int pStopPosn) { @@ -15,7 +15,7 @@ dchar[] SomeFunc( dchar[] pText, out int pStopPosn) pStopPosn = 0; else pStopPosn = -1; - debug(1) writefln("DEBUG: using '%s' we get %d", pText, pStopPosn); + debug writefln("DEBUG: using '%s' we get %d", pText, pStopPosn); return pText.dup; } @@ -24,12 +24,12 @@ int main(char[][] pArgs) int sp; SomeFunc("123", sp); - debug(1) writefln("DEBUG: got %d", sp); + debug writefln("DEBUG: got %d", sp); assert(sp == -1); SomeFunc("", sp); // if (sp != 0){} // Line #22 - debug(1) writefln("DEBUG: got %d", sp); + debug writefln("DEBUG: got %d", sp); assert(sp == -1); return 0; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d index aa18977..ee84a84 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d @@ -55,7 +55,7 @@ L1: scope(failure) { L2: goto L1; } // OK goto L2; // NG - scope(failure) { return; } // OK + foreach (i; 0..1) { diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d index e8371c4..001c7d7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d @@ -9,12 +9,12 @@ fail_compilation/fail7848.d(21): `fail7848.func` is declared here fail_compilation/fail7848.d(27): Error: `@nogc` function `fail7848.C.__unittest_L25_C30` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(27): Error: function `fail7848.func` is not `nothrow` fail_compilation/fail7848.d(25): Error: function `fail7848.C.__unittest_L25_C30` may throw but is marked as `nothrow` -fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func` -fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func` +fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant0` cannot call impure function `fail7848.func` +fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant0` cannot call `@system` function `fail7848.func` fail_compilation/fail7848.d(21): `fail7848.func` is declared here -fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func` +fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant0` cannot call non-@nogc function `fail7848.func` fail_compilation/fail7848.d(32): Error: function `fail7848.func` is not `nothrow` -fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant1` may throw but is marked as `nothrow` +fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant0` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d index d2a1d1d..24e39da 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d @@ -1,8 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11856_1.d(13): Error: none of the overloads of template `ice11856_1.g` are callable using argument types `!()(A)` -fail_compilation/ice11856_1.d(11): Candidate is: `g(T)(T x)` +fail_compilation/ice11856_1.d(16): Error: none of the overloads of template `ice11856_1.g` are callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(14): Candidate is: `g(T)(T x)` + with `T = A` + must satisfy the following constraint: +` is(typeof(x.f()))` --- */ struct A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d index 22cf392..b50a616 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d @@ -10,7 +10,6 @@ fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)` fail_compilation/misc_parser_err_cov1.d(32): Error: `type identifier : specialization` expected following `is` fail_compilation/misc_parser_err_cov1.d(33): Error: semicolon expected following auto declaration, not `auto` fail_compilation/misc_parser_err_cov1.d(33): Error: found `+` when expecting `(` following `mixin` -fail_compilation/misc_parser_err_cov1.d(34): Error: cannot create a `char[float]` with `new` fail_compilation/misc_parser_err_cov1.d(35): Error: `key:value` expected for associative array literal fail_compilation/misc_parser_err_cov1.d(36): Error: basic type expected, not `;` fail_compilation/misc_parser_err_cov1.d(36): Error: `{ members }` expected for anonymous class @@ -44,7 +43,7 @@ void main() auto tt = __traits(<o<); auto b = is ; auto mx1 = mixin +); - auto aa1 = new char[float]; + aa += [key:value, key]; auto anon1 = new class; auto anon2 = new class {}; diff --git a/gcc/testsuite/gdc.test/fail_compilation/newaa.d b/gcc/testsuite/gdc.test/fail_compilation/newaa.d new file mode 100644 index 0000000..ebc23fb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/newaa.d @@ -0,0 +1,19 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/newaa.d(14): Error: cannot implicitly convert expression `new string[string]` of type `string[string]` to `int[string]` +fail_compilation/newaa.d(15): Error: function expected before `()`, not `new int[int]` of type `int[int]` +fail_compilation/newaa.d(17): Error: `new` cannot take arguments for an associative array +--- +*/ +#line 9 +void main() +{ + //https://issues.dlang.org/show_bug.cgi?id=11790 + string[string] crash = new string[string]; + //https://issues.dlang.org/show_bug.cgi?id=20547 + int[string] c = new typeof(crash); + auto d = new int[int](5); + alias AA = char[string]; + auto e = new AA(5); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc3.d b/gcc/testsuite/gdc.test/fail_compilation/nogc3.d index fdc3cde..3bd7167 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/nogc3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/nogc3.d @@ -43,10 +43,10 @@ fail_compilation/nogc3.d(35): Error: `@nogc` function `nogc3.testCall` cannot ca /* TEST_OUTPUT: --- -fail_compilation/nogc3.d(52): Error: function `nogc3.testClosure1` is `@nogc` yet allocates closures with the GC -fail_compilation/nogc3.d(55): nogc3.testClosure1.bar closes over variable x at fail_compilation/nogc3.d(54) -fail_compilation/nogc3.d(64): Error: function `nogc3.testClosure3` is `@nogc` yet allocates closures with the GC -fail_compilation/nogc3.d(67): nogc3.testClosure3.bar closes over variable x at fail_compilation/nogc3.d(66) +fail_compilation/nogc3.d(52): Error: function `nogc3.testClosure1` is `@nogc` yet allocates closure for `testClosure1()` with the GC +fail_compilation/nogc3.d(55): `nogc3.testClosure1.bar` closes over variable `x` at fail_compilation/nogc3.d(54) +fail_compilation/nogc3.d(64): Error: function `nogc3.testClosure3` is `@nogc` yet allocates closure for `testClosure3()` with the GC +fail_compilation/nogc3.d(67): `nogc3.testClosure3.bar` closes over variable `x` at fail_compilation/nogc3.d(66) --- */ @nogc auto testClosure1() diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d index 9394404..2a69fe0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d @@ -54,8 +54,8 @@ void test2(scope int* p, int[] a ...) @safe /* TEST_OUTPUT: --- -fail_compilation/retscope.d(75): Error: function `retscope.HTTP.Impl.onReceive` is `@nogc` yet allocates closures with the GC -fail_compilation/retscope.d(77): retscope.HTTP.Impl.onReceive.__lambda1 closes over variable this at fail_compilation/retscope.d(75) +fail_compilation/retscope.d(75): Error: function `retscope.HTTP.Impl.onReceive` is `@nogc` yet allocates closure for `onReceive()` with the GC +fail_compilation/retscope.d(77): `retscope.HTTP.Impl.onReceive.__lambda1` closes over variable `this` at fail_compilation/retscope.d(75) --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13786.d b/gcc/testsuite/gdc.test/fail_compilation/test13786.d index 3524875..73ec588 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test13786.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test13786.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/test13786.d(14): Error: debug `123` level declaration must be at module level -fail_compilation/test13786.d(15): Error: debug `abc` declaration must be at module level -fail_compilation/test13786.d(16): Error: version `123` level declaration must be at module level -fail_compilation/test13786.d(17): Error: version `abc` declaration must be at module level -fail_compilation/test13786.d(20): Error: template instance `test13786.T!()` error instantiating +fail_compilation/test13786.d(16): Deprecation: `debug = <integer>` is deprecated, use debug identifiers instead +fail_compilation/test13786.d(18): Deprecation: `version = <integer>` is deprecated, use version identifiers instead +fail_compilation/test13786.d(16): Error: debug `123` level declaration must be at module level +fail_compilation/test13786.d(17): Error: debug `abc` declaration must be at module level +fail_compilation/test13786.d(18): Error: version `123` level declaration must be at module level +fail_compilation/test13786.d(19): Error: version `abc` declaration must be at module level +fail_compilation/test13786.d(22): Error: template instance `test13786.T!()` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16193.d b/gcc/testsuite/gdc.test/fail_compilation/test16193.d index 053f583..6c80471 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16193.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16193.d @@ -2,8 +2,8 @@ REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test16193.d(38): Error: function `test16193.abc` is `@nogc` yet allocates closures with the GC -fail_compilation/test16193.d(40): test16193.abc.__foreachbody2 closes over variable x at fail_compilation/test16193.d(39) +fail_compilation/test16193.d(38): Error: function `test16193.abc` is `@nogc` yet allocates closure for `abc()` with the GC +fail_compilation/test16193.d(40): `test16193.abc.__foreachbody2` closes over variable `x` at fail_compilation/test16193.d(39) --- */ //fail_compilation/test16193.d(22): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21443.d b/gcc/testsuite/gdc.test/fail_compilation/test21443.d new file mode 100644 index 0000000..2d99524 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test21443.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=21443 +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/test21443.d(14): Deprecation: `return` statements cannot be in `scope(failure)` bodies. +fail_compilation/test21443.d(14): Use try-catch blocks for this purpose +--- +*/ + +ulong get () @safe nothrow +{ + scope (failure) return 10; + throw new Error(""); +} + +void main () @safe +{ + assert(get() == 10); // passes +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21912.d b/gcc/testsuite/gdc.test/fail_compilation/test21912.d index 925210b..9b07eba 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21912.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21912.d @@ -2,14 +2,14 @@ PERMUTE_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test21912.d(24): Error: function `test21912.escapeParam` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(26): test21912.escapeParam.__lambda2 closes over variable i at fail_compilation/test21912.d(24) -fail_compilation/test21912.d(29): Error: function `test21912.escapeAssign` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(31): test21912.escapeAssign.__lambda3 closes over variable i at fail_compilation/test21912.d(29) -fail_compilation/test21912.d(40): Error: function `test21912.escapeAssignRef` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(42): test21912.escapeAssignRef.__lambda3 closes over variable i at fail_compilation/test21912.d(40) -fail_compilation/test21912.d(51): Error: function `test21912.escapeParamInferred` is `@nogc` yet allocates closures with the GC -fail_compilation/test21912.d(53): test21912.escapeParamInferred.__lambda2 closes over variable i at fail_compilation/test21912.d(51) +fail_compilation/test21912.d(24): Error: function `test21912.escapeParam` is `@nogc` yet allocates closure for `escapeParam()` with the GC +fail_compilation/test21912.d(26): `test21912.escapeParam.__lambda2` closes over variable `i` at fail_compilation/test21912.d(24) +fail_compilation/test21912.d(29): Error: function `test21912.escapeAssign` is `@nogc` yet allocates closure for `escapeAssign()` with the GC +fail_compilation/test21912.d(31): `test21912.escapeAssign.__lambda3` closes over variable `i` at fail_compilation/test21912.d(29) +fail_compilation/test21912.d(40): Error: function `test21912.escapeAssignRef` is `@nogc` yet allocates closure for `escapeAssignRef()` with the GC +fail_compilation/test21912.d(42): `test21912.escapeAssignRef.__lambda3` closes over variable `i` at fail_compilation/test21912.d(40) +fail_compilation/test21912.d(51): Error: function `test21912.escapeParamInferred` is `@nogc` yet allocates closure for `escapeParamInferred()` with the GC +fail_compilation/test21912.d(53): `test21912.escapeParamInferred.__lambda2` closes over variable `i` at fail_compilation/test21912.d(51) --- */ @nogc: diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21939.d b/gcc/testsuite/gdc.test/fail_compilation/test21939.d index 8f30bac..e513dc2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21939.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21939.d @@ -2,8 +2,9 @@ /* TEST_OUTPUT: --- -fail_compilation/test21939.d(10): Error: invalid `foreach` aggregate `Object` of type `Object` -fail_compilation/test21939.d(10): maybe define `opApply()`, range primitives, or use `.tupleof` +fail_compilation/test21939.d(11): Error: invalid `foreach` aggregate `Object` of type `Object` +fail_compilation/test21939.d(11): `foreach` works with input ranges (implementing `front` and `popFront`), aggregates implementing `opApply`, or the result of an aggregate's `.tupleof` property +fail_compilation/test21939.d(11): https://dlang.org/phobos/std_range_primitives.html#isInputRange --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23022.d b/gcc/testsuite/gdc.test/fail_compilation/test23022.d new file mode 100644 index 0000000..8c4eca9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23022.d @@ -0,0 +1,15 @@ +/* +REQUIRED_ARGS: -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/test23022.d(14): Error: scope parameter `p` may not be returned +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23022 +// Typesafe variadic parameter should not infer return + +auto ir(string[] p...) +{ + return p; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23112.d b/gcc/testsuite/gdc.test/fail_compilation/test23112.d new file mode 100644 index 0000000..325d89b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23112.d @@ -0,0 +1,30 @@ +/* REQUIRED_ARGS: -betterC +TEST_OUTPUT: +--- +fail_compilation/test23112.d(106): Error: function `test23112.bar` is `@nogc` yet allocates closure for `bar()` with the GC +fail_compilation/test23112.d(108): `test23112.bar.f` closes over variable `a` at fail_compilation/test23112.d(106) +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23112 + +#line 100 + +struct Forward(alias F) +{ + auto call()() { return F(); } +} + +auto bar(int a) nothrow @safe +{ + auto f() + { + return a; + } + return Forward!f(); +} + +extern(C) void main() +{ + assert(bar(3).call() == 3); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23170.d b/gcc/testsuite/gdc.test/fail_compilation/test23170.d new file mode 100644 index 0000000..eb79cd8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23170.d @@ -0,0 +1,12 @@ +/*
+TEST_OUTPUT:
+---
+fail_compilation/test23170.d(10): Error: array literal in `@nogc` delegate `test23170.__lambda5` may cause a GC allocation
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=23170
+
+@nogc:
+enum lambda = () => badAlias([1, 2, 3]);
+alias badAlias = (int[] array) => id(array);
+int[] id(int[] array) { return array; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23216.d b/gcc/testsuite/gdc.test/fail_compilation/test23216.d new file mode 100644 index 0000000..d7c12ed --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23216.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test23216.d(23): Error: invalid `foreach_reverse` aggregate `r` of type `Range` +fail_compilation/test23216.d(23): `foreach_reverse` works with bidirectional ranges (implementing `back` and `popBack`), aggregates implementing `opApplyReverse`, or the result of an aggregate's `.tupleof` property +fail_compilation/test23216.d(23): https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23216 +// Better Error Message For foreach_reverse Without Bidirectional Range + +struct Range +{ + bool empty = true; + int front = 0; + void popFront() { } +} + +void main() +{ + Range r; + foreach_reverse (word; r) { } +} diff --git a/gcc/testsuite/gdc.test/runnable/closure.d b/gcc/testsuite/gdc.test/runnable/closure.d index af304c1..1382f2d 100644 --- a/gcc/testsuite/gdc.test/runnable/closure.d +++ b/gcc/testsuite/gdc.test/runnable/closure.d @@ -922,7 +922,10 @@ void test14730() // This is questionable case. Currently it works without any errors, // but not sure it's really intentional - +// It showed up again in https://issues.dlang.org/show_bug.cgi?id=23112 +// where it's an @safe issue so it's a bug. +static if (0) +{ struct S14730x(alias f) { auto foo()() { return f(0); } @@ -947,6 +950,7 @@ void test14730x() // *after* the semantic3 completion of makeS() function. assert(s.foo() == 10); } +} /************************************/ @@ -981,7 +985,7 @@ int main() test9685b(); test12406(); test14730(); - test14730x(); + //test14730x(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/evalorder.d b/gcc/testsuite/gdc.test/runnable/evalorder.d index 6805ee2..f93aef5 100644 --- a/gcc/testsuite/gdc.test/runnable/evalorder.d +++ b/gcc/testsuite/gdc.test/runnable/evalorder.d @@ -46,6 +46,12 @@ int mul11ret3(T)(ref T s) return 3; } +auto cat11ret3(T)(ref T s) +{ + s ~= 11; + return [3]; +} + void add() { static int test1(int val) { val += add8ret3(val); return val; } @@ -147,6 +153,25 @@ void shr() static assert(test(0x80) == 0x40); } +void cat() +{ + static auto test1(int[] val) { val ~= cat11ret3(val); return val; } + assert(test1([1]) == [1, 11, 3]); + static assert(test1([1]) == [1, 11, 3]); + + static auto test2(int[] val) { val = val ~ cat11ret3(val); return val; } + // FIXME: assert(test2([1]) == [1, 3]); + static assert(test2([1]) == [1, 3]); + + static auto test3(int[] val) { (val ~= 7) ~= cat11ret3(val); return val; } + assert(test3([2]) == [2, 7, 11, 3]); + static assert(test3([2]) == [2, 7, 11, 3]); + + static auto test4(int[] val) { (val ~= cat11ret3(val)) ~= 7; return val; } + assert(test4([2]) == [2, 11, 3, 7]); + static assert(test4([2]) == [2, 11, 3, 7]); +} + void ldc_github_1617() { add(); @@ -156,6 +181,7 @@ void ldc_github_1617() addptr(); lhsCast(); shr(); + cat(); } /******************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/lexer.d b/gcc/testsuite/gdc.test/runnable/lexer.d index ee2fef8..6e31c07 100644 --- a/gcc/testsuite/gdc.test/runnable/lexer.d +++ b/gcc/testsuite/gdc.test/runnable/lexer.d @@ -1,5 +1,11 @@ // REQUIRED_ARGS: - +/* +TEST_OUTPUT: +--- +runnable/lexer.d(81): Deprecation: `version( <integer> )` is deprecated, use version identifiers instead +runnable/lexer.d(82): Deprecation: `debug( <integer> )` is deprecated, use debug identifiers instead +--- +*/ /*********************************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/noreturn1.d b/gcc/testsuite/gdc.test/runnable/noreturn1.d index 7d15b54..5ed46c1 100644 --- a/gcc/testsuite/gdc.test/runnable/noreturn1.d +++ b/gcc/testsuite/gdc.test/runnable/noreturn1.d @@ -261,6 +261,37 @@ void testThrowDtor() /*****************************************/ +noreturn func() +{ + throw new Exception("B"); +} + +// https://issues.dlang.org/show_bug.cgi?id=23120 +void test23120() +{ + string a; + try + { + noreturn q = throw new Exception ("A"); + } + catch(Exception e) + { + a ~= e.msg; + } + + try + { + noreturn z = func(); + } + catch(Exception e) + { + a ~= e.msg; + } + + assert(a == "AB"); +} + +/*****************************************/ int main() { test1(); @@ -269,5 +300,6 @@ int main() testThrowExpression(); testThrowSideEffect(); testThrowDtor(); + test23120(); return 0; } diff --git a/gcc/testsuite/gdc.test/runnable/test11.d b/gcc/testsuite/gdc.test/runnable/test11.d index 6735a81..333b600 100644 --- a/gcc/testsuite/gdc.test/runnable/test11.d +++ b/gcc/testsuite/gdc.test/runnable/test11.d @@ -1193,41 +1193,6 @@ void test63() printf("%.*s\n", cast(int)s.length, s.ptr); } - -/**************************************/ - -debug = 3; - -void test64() -{ - debug(5) - { - assert(0); - } - debug(3) - { - int x = 3; - } - assert(x == 3); -} - -/**************************************/ - -version = 3; - -void test65() -{ - version(5) - { - assert(0); - } - version(3) - { - int x = 3; - } - assert(x == 3); -} - /**************************************/ // https://issues.dlang.org/show_bug.cgi?id=8809 @@ -1381,8 +1346,6 @@ int main(string[] argv) test61(); test62(); test63(); - test64(); - test65(); test8809(); test9734(); diff --git a/gcc/testsuite/gdc.test/runnable/test18973.d b/gcc/testsuite/gdc.test/runnable/test18973.d new file mode 100644 index 0000000..29fcfa7 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test18973.d @@ -0,0 +1,25 @@ +// This is a runnable test as we are testing a linker error + +// https://issues.dlang.org/show_bug.cgi?id=18973 +struct X { + @disable size_t toHash() const; + @disable string toString() const; + @disable bool opEquals(const ref X) const; + @disable int opCmp(const ref X) const; +} + +// https://issues.dlang.org/show_bug.cgi?id=9161 +public struct dummy +{ + static auto opCall(C)(in C[] name) + { + return name; + } + + @disable ~this(); //comment this out to avoid error +} + +void main() +{ + assert(dummy("ABCDE") == "ABCDE"); +} diff --git a/gcc/testsuite/gdc.test/runnable/test19.d b/gcc/testsuite/gdc.test/runnable/test19.d index 372d32f..eda6172 100644 --- a/gcc/testsuite/gdc.test/runnable/test19.d +++ b/gcc/testsuite/gdc.test/runnable/test19.d @@ -59,22 +59,7 @@ void test2() void test3() { debug printf("debug\n"); - debug(1) printf("debug(1)\n"); - debug(2) printf("debug(2)\n"); - debug(3) printf("debug(3)\n"); debug(bar) printf("debug(bar)\n"); - debug(10) assert(0); - - debug(1) - { - int d1 = 3; - - printf("debug(1) { }\n"); - } - debug(2) - { - printf("debug(2): d1 = %d\n", d1); - } } /* ================================ */ diff --git a/gcc/testsuite/gdc.test/runnable/test20734.d b/gcc/testsuite/gdc.test/runnable/test20734.d index 264602b..b3c5916 100644 --- a/gcc/testsuite/gdc.test/runnable/test20734.d +++ b/gcc/testsuite/gdc.test/runnable/test20734.d @@ -16,6 +16,7 @@ extern(C) int main() nothrow @nogc @safe { takeScopeSlice([ S(1), S(2) ]); // @nogc => no GC allocation (() @trusted { assert(numDtor == 2); })(); // stack-allocated array literal properly destructed + assert23100([]); return 0; } @@ -26,3 +27,9 @@ void test23098() @safe { f23098([10, 20]); } + +// https://issues.dlang.org/show_bug.cgi?id=23100 +void assert23100(scope int[] d) @safe nothrow @nogc +{ + assert(!d); +} diff --git a/gcc/testsuite/gdc.test/runnable/test23181.d b/gcc/testsuite/gdc.test/runnable/test23181.d new file mode 100644 index 0000000..b961690 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23181.d @@ -0,0 +1,27 @@ +// https://issues.dlang.org/show_bug.cgi?id=23181 +void main() +{ + int count; + struct HasDtor + { + ~this() { ++count; } + } + + // array[] = elem() + // -> creates temporary to construct array and calls destructor. + { + count = 0; + HasDtor[4] dtor1 = HasDtor(); + assert(count == 1); + } + assert(count == 5); + + // array[] = array[elem()] + // -> constructs array using direct emplacement. + { + count = 0; + HasDtor[2] dtor2 = [HasDtor(), HasDtor()]; + assert(count == 0); + } + assert(count == 2); +} diff --git a/gcc/testsuite/gdc.test/runnable/test8.d b/gcc/testsuite/gdc.test/runnable/test8.d index 7d66eb6..d65ba0e 100644 --- a/gcc/testsuite/gdc.test/runnable/test8.d +++ b/gcc/testsuite/gdc.test/runnable/test8.d @@ -592,6 +592,44 @@ void test34() } /***********************************/ +// https://issues.dlang.org/show_bug.cgi?id=19178 + +float[3][4] arr2f = 10; +Int3_4[1] arr3i = 20; +short[3][4][1][1] arr4s = 30; + +enum Int3 : int[3] { + a = [0, 1, 2], +} + +enum Int3_4 : Int3[4] { + b = Int3[4].init, +} + +struct S35 +{ + int[3][3] arr = [2, 1]; +} + +void test35() +{ + for (int i = 0; i < 4; i++) + { + for (int j = 0; j < 3; j++) + { + // printf("[%d %d]: %f %d %d\n", i, j, arr2f[i][j], arr3i[0][i][j], arr4s[0][0][i][j]); + assert(arr2f[i][j] == 10); + assert(arr3i[0][i][j] == 20); + assert(arr4s[0][0][i][j] == 30); + } + } + + S35 t = S35.init; + assert(t.arr[0] == [2, 2, 2]); + assert(t.arr[1] == [1, 1, 1]); + assert(t.arr[2] == [0, 0, 0]); +} +/***********************************/ string itoa(int i) { @@ -868,6 +906,7 @@ int main() test32(); test33(); test34(); + test35(); test36(); test37(); test38(); diff --git a/gcc/testsuite/gdc.test/runnable/version.d b/gcc/testsuite/gdc.test/runnable/version.d index 1186e4c..e225d5e 100644 --- a/gcc/testsuite/gdc.test/runnable/version.d +++ b/gcc/testsuite/gdc.test/runnable/version.d @@ -1,10 +1,9 @@ /* PERMUTE_ARGS: -REQUIRED_ARGS: -version=3 -version=foo +REQUIRED_ARGS: -version=foo RUN_OUTPUT: --- i = 2 -i = 2 --- */ @@ -15,20 +14,6 @@ extern(C) int printf(const char*, ...); void test1() { int i = 3; - - version(2) - { - i = 2; - } - else - { - i = 0; - } - printf("i = %d\n", i); - assert(i == 2); - - i = 3; - version(foo) { i = 2; @@ -47,10 +32,6 @@ version(foo) { version = bar; } -else -{ - version = 4; -} void test2() { @@ -59,8 +40,6 @@ void test2() } else assert(0); - - version(4) assert(0); } /*******************************************/ diff --git a/gcc/testsuite/gdc.test/runnable/warning1.d b/gcc/testsuite/gdc.test/runnable/warning1.d index 537088e..01ac20c0 100644 --- a/gcc/testsuite/gdc.test/runnable/warning1.d +++ b/gcc/testsuite/gdc.test/runnable/warning1.d @@ -133,15 +133,6 @@ void test6518() } } -/******************************************/ -// https://issues.dlang.org/show_bug.cgi?id=7232 - -bool test7232() -{ - scope(failure) return false; - return true; -} - /***************************************************/ struct S9332 diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 4ed7b25..04a2a8e 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -2288,7 +2288,7 @@ proc check_p9modulo_hw_available { } { { int i = 5, j = 3, r = -1; asm ("modsw %0,%1,%2" : "+r" (r) : "r" (i), "r" (j)); - return (r == 2); + return (r != 2); } } $options } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index ea9f281..86a07c2 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1589,17 +1589,17 @@ struct GTY(()) tree_ssa_name { /* Value range information. */ union ssa_name_info_type { + /* Ranges for integers. */ + struct GTY ((tag ("0"))) irange_storage_slot *irange_info; + /* Ranges for floating point numbers. */ + struct GTY ((tag ("1"))) frange_storage_slot *frange_info; /* Pointer attributes used for alias analysis. */ - struct GTY ((tag ("0"))) ptr_info_def *ptr_info; + struct GTY ((tag ("2"))) ptr_info_def *ptr_info; /* This holds any range info supported by ranger (except ptr_info above) and is managed by vrange_storage. */ void * GTY ((skip)) range_info; - /* GTY tag when the range in the range_info slot above satisfies - irange::supports_type_p. */ - struct GTY ((tag ("1"))) irange_storage_slot *irange_info; } GTY ((desc ("%1.typed.type ?" \ - "!POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) : 2"))) info; - + "(POINTER_TYPE_P (TREE_TYPE ((tree)&%1)) ? 2 : SCALAR_FLOAT_TYPE_P (TREE_TYPE ((tree)&%1))) : 3"))) info; /* Immediate uses list for this SSA_NAME. */ struct ssa_use_operand_t imm_uses; }; diff --git a/gcc/tree-loop-distribution.cc b/gcc/tree-loop-distribution.cc index 0ee441c..e1948fb 100644 --- a/gcc/tree-loop-distribution.cc +++ b/gcc/tree-loop-distribution.cc @@ -3829,7 +3829,7 @@ loop_distribution::execute (function *fun) { auto_vec<gimple *> work_list; if (!find_seed_stmts_for_distribution (loop, &work_list)) - break; + continue; const char *str = loop->inner ? " nest" : ""; dump_user_location_t loc = find_loop_location (loop); diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index 2f4bebe..0191b9c 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -63,8 +63,8 @@ static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, tree, gimple *); static int value_replacement (basic_block, basic_block, edge, edge, gphi *, tree, tree); -static bool minmax_replacement (basic_block, basic_block, - edge, edge, gphi *, tree, tree); +static bool minmax_replacement (basic_block, basic_block, basic_block, + edge, edge, gphi *, tree, tree, bool); static bool spaceship_replacement (basic_block, basic_block, edge, edge, gphi *, tree, tree); static bool cond_removal_in_builtin_zero_pattern (basic_block, basic_block, @@ -200,6 +200,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) basic_block bb1, bb2; edge e1, e2; tree arg0, arg1; + bool diamond_p = false; bb = bb_order[i]; @@ -266,6 +267,12 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) hoist_adjacent_loads (bb, bb1, bb2, bb3); continue; } + else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest + && !empty_block_p (bb1)) + { + diamond_p = true; + e2 = EDGE_SUCC (bb2, 0); + } else continue; @@ -276,7 +283,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) || (e1->flags & EDGE_FALLTHRU) == 0) continue; - if (do_store_elim) + if (do_store_elim && !diamond_p) { /* Also make sure that bb1 only have one predecessor and that it is bb. */ @@ -294,13 +301,16 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) } else { - gimple_seq phis = phi_nodes (bb2); gimple_stmt_iterator gsi; bool candorest = true; + /* Check that we're looking for nested phis. */ + basic_block merge = diamond_p ? EDGE_SUCC (bb2, 0)->dest : bb2; + gimple_seq phis = phi_nodes (merge); + /* Value replacement can work with more than one PHI so try that first. */ - if (!early_p) + if (!early_p && !diamond_p) for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi)) { phi = as_a <gphi *> (gsi_stmt (gsi)); @@ -330,6 +340,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) gphi *newphi; if (single_pred_p (bb1) + && !diamond_p && (newphi = factor_out_conditional_conversion (e1, e2, phi, arg0, arg1, cond_stmt))) @@ -344,20 +355,25 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) } /* Do the replacement of conditional if it can be done. */ - if (!early_p && two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) + if (!early_p + && !diamond_p + && two_value_replacement (bb, bb1, e2, phi, arg0, arg1)) cfgchanged = true; - else if (match_simplify_replacement (bb, bb1, e1, e2, phi, - arg0, arg1, - early_p)) + else if (!diamond_p + && match_simplify_replacement (bb, bb1, e1, e2, phi, + arg0, arg1, early_p)) cfgchanged = true; else if (!early_p + && !diamond_p && single_pred_p (bb1) && cond_removal_in_builtin_zero_pattern (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; - else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) + else if (minmax_replacement (bb, bb1, bb2, e1, e2, phi, arg0, arg1, + diamond_p)) cfgchanged = true; else if (single_pred_p (bb1) + && !diamond_p && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } @@ -422,12 +438,23 @@ replace_phi_edge_with_variable (basic_block cond_block, SET_USE (PHI_ARG_DEF_PTR (phi, e->dest_idx), new_tree); /* Remove the empty basic block. */ - edge edge_to_remove; + edge edge_to_remove = NULL, keep_edge = NULL; if (EDGE_SUCC (cond_block, 0)->dest == bb) - edge_to_remove = EDGE_SUCC (cond_block, 1); + { + edge_to_remove = EDGE_SUCC (cond_block, 1); + keep_edge = EDGE_SUCC (cond_block, 0); + } + else if (EDGE_SUCC (cond_block, 1)->dest == bb) + { + edge_to_remove = EDGE_SUCC (cond_block, 0); + keep_edge = EDGE_SUCC (cond_block, 1); + } + else if ((keep_edge = find_edge (cond_block, e->src))) + ; else - edge_to_remove = EDGE_SUCC (cond_block, 0); - if (EDGE_COUNT (edge_to_remove->dest->preds) == 1) + gcc_unreachable (); + + if (edge_to_remove && EDGE_COUNT (edge_to_remove->dest->preds) == 1) { e->flags |= EDGE_FALLTHRU; e->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); @@ -444,9 +471,9 @@ replace_phi_edge_with_variable (basic_block cond_block, CFG cleanup deal with the edge removal to avoid updating dominators here in a non-trivial way. */ gcond *cond = as_a <gcond *> (last_stmt (cond_block)); - if (edge_to_remove->flags & EDGE_TRUE_VALUE) + if (keep_edge->flags & EDGE_FALSE_VALUE) gimple_cond_make_false (cond); - else + else if (keep_edge->flags & EDGE_TRUE_VALUE) gimple_cond_make_true (cond); } @@ -1733,15 +1760,52 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, return 0; } +/* If VAR is an SSA_NAME that points to a BIT_NOT_EXPR then return the TREE for + the value being inverted. */ + +static tree +strip_bit_not (tree var) +{ + if (TREE_CODE (var) != SSA_NAME) + return NULL_TREE; + + gimple *assign = SSA_NAME_DEF_STMT (var); + if (gimple_code (assign) != GIMPLE_ASSIGN) + return NULL_TREE; + + if (gimple_assign_rhs_code (assign) != BIT_NOT_EXPR) + return NULL_TREE; + + return gimple_assign_rhs1 (assign); +} + +/* Invert a MIN to a MAX or a MAX to a MIN expression CODE. */ + +enum tree_code +invert_minmax_code (enum tree_code code) +{ + switch (code) { + case MIN_EXPR: + return MAX_EXPR; + case MAX_EXPR: + return MIN_EXPR; + default: + gcc_unreachable (); + } +} + /* The function minmax_replacement does the main work of doing the minmax replacement. Return true if the replacement is done. Otherwise return false. BB is the basic block where the replacement is going to be done on. ARG0 - is argument 0 from the PHI. Likewise for ARG1. */ + is argument 0 from the PHI. Likewise for ARG1. + + If THREEWAY_P then expect the BB to be laid out in diamond shape with each + BB containing only a MIN or MAX expression. */ static bool -minmax_replacement (basic_block cond_bb, basic_block middle_bb, - edge e0, edge e1, gphi *phi, tree arg0, tree arg1) +minmax_replacement (basic_block cond_bb, basic_block middle_bb, basic_block alt_middle_bb, + edge e0, edge e1, gphi *phi, tree arg0, tree arg1, bool threeway_p) { tree result; edge true_edge, false_edge; @@ -1896,16 +1960,20 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, if (false_edge->dest == middle_bb) false_edge = EDGE_SUCC (false_edge->dest, 0); + /* When THREEWAY_P then e1 will point to the edge of the final transition + from middle-bb to end. */ if (true_edge == e0) { - gcc_assert (false_edge == e1); + if (!threeway_p) + gcc_assert (false_edge == e1); arg_true = arg0; arg_false = arg1; } else { gcc_assert (false_edge == e0); - gcc_assert (true_edge == e1); + if (!threeway_p) + gcc_assert (true_edge == e1); arg_true = arg1; arg_false = arg0; } @@ -1937,6 +2005,165 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb, else return false; } + else if (middle_bb != alt_middle_bb && threeway_p) + { + /* Recognize the following case: + + if (smaller < larger) + a = MIN (smaller, c); + else + b = MIN (larger, c); + x = PHI <a, b> + + This is equivalent to + + a = MIN (smaller, c); + x = MIN (larger, a); */ + + gimple *assign = last_and_only_stmt (middle_bb); + tree lhs, op0, op1, bound; + tree alt_lhs, alt_op0, alt_op1; + bool invert = false; + + if (!single_pred_p (middle_bb) + || !single_pred_p (alt_middle_bb) + || !single_succ_p (middle_bb) + || !single_succ_p (alt_middle_bb)) + return false; + + /* When THREEWAY_P then e1 will point to the edge of the final transition + from middle-bb to end. */ + if (true_edge == e0) + gcc_assert (false_edge == EDGE_PRED (e1->src, 0)); + else + gcc_assert (true_edge == EDGE_PRED (e1->src, 0)); + + bool valid_minmax_p = false; + gimple_stmt_iterator it1 + = gsi_start_nondebug_after_labels_bb (middle_bb); + gimple_stmt_iterator it2 + = gsi_start_nondebug_after_labels_bb (alt_middle_bb); + if (gsi_one_nondebug_before_end_p (it1) + && gsi_one_nondebug_before_end_p (it2)) + { + gimple *stmt1 = gsi_stmt (it1); + gimple *stmt2 = gsi_stmt (it2); + if (is_gimple_assign (stmt1) && is_gimple_assign (stmt2)) + { + enum tree_code code1 = gimple_assign_rhs_code (stmt1); + enum tree_code code2 = gimple_assign_rhs_code (stmt2); + valid_minmax_p = (code1 == MIN_EXPR || code1 == MAX_EXPR) + && (code2 == MIN_EXPR || code2 == MAX_EXPR); + } + } + + if (!valid_minmax_p) + return false; + + if (!assign + || gimple_code (assign) != GIMPLE_ASSIGN) + return false; + + lhs = gimple_assign_lhs (assign); + ass_code = gimple_assign_rhs_code (assign); + if (ass_code != MAX_EXPR && ass_code != MIN_EXPR) + return false; + + op0 = gimple_assign_rhs1 (assign); + op1 = gimple_assign_rhs2 (assign); + + assign = last_and_only_stmt (alt_middle_bb); + if (!assign + || gimple_code (assign) != GIMPLE_ASSIGN) + return false; + + alt_lhs = gimple_assign_lhs (assign); + if (ass_code != gimple_assign_rhs_code (assign)) + return false; + + if (!operand_equal_for_phi_arg_p (lhs, arg_true) + || !operand_equal_for_phi_arg_p (alt_lhs, arg_false)) + return false; + + alt_op0 = gimple_assign_rhs1 (assign); + alt_op1 = gimple_assign_rhs2 (assign); + + if ((operand_equal_for_phi_arg_p (op0, smaller) + || (alt_smaller + && operand_equal_for_phi_arg_p (op0, alt_smaller))) + && (operand_equal_for_phi_arg_p (alt_op0, larger) + || (alt_larger + && operand_equal_for_phi_arg_p (alt_op0, alt_larger)))) + { + /* We got here if the condition is true, i.e., SMALLER < LARGER. */ + if (!operand_equal_for_phi_arg_p (op1, alt_op1)) + return false; + + if ((arg0 = strip_bit_not (op0)) != NULL + && (arg1 = strip_bit_not (alt_op0)) != NULL + && (bound = strip_bit_not (op1)) != NULL) + { + minmax = MAX_EXPR; + ass_code = invert_minmax_code (ass_code); + invert = true; + } + else + { + bound = op1; + minmax = MIN_EXPR; + arg0 = op0; + arg1 = alt_op0; + } + } + else if ((operand_equal_for_phi_arg_p (op0, larger) + || (alt_larger + && operand_equal_for_phi_arg_p (op0, alt_larger))) + && (operand_equal_for_phi_arg_p (alt_op0, smaller) + || (alt_smaller + && operand_equal_for_phi_arg_p (alt_op0, alt_smaller)))) + { + /* We got here if the condition is true, i.e., SMALLER > LARGER. */ + if (!operand_equal_for_phi_arg_p (op1, alt_op1)) + return false; + + if ((arg0 = strip_bit_not (op0)) != NULL + && (arg1 = strip_bit_not (alt_op0)) != NULL + && (bound = strip_bit_not (op1)) != NULL) + { + minmax = MIN_EXPR; + ass_code = invert_minmax_code (ass_code); + invert = true; + } + else + { + bound = op1; + minmax = MAX_EXPR; + arg0 = op0; + arg1 = alt_op0; + } + } + else + return false; + + /* Emit the statement to compute min/max. */ + location_t locus = gimple_location (last_stmt (cond_bb)); + gimple_seq stmts = NULL; + tree phi_result = PHI_RESULT (phi); + result = gimple_build (&stmts, locus, minmax, TREE_TYPE (phi_result), + arg0, bound); + result = gimple_build (&stmts, locus, ass_code, TREE_TYPE (phi_result), + result, arg1); + if (invert) + result = gimple_build (&stmts, locus, BIT_NOT_EXPR, TREE_TYPE (phi_result), + result); + + gsi = gsi_last_bb (cond_bb); + gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT); + + replace_phi_edge_with_variable (cond_bb, e1, phi, result); + + return true; + } else { /* Recognize the following case, assuming d <= u: diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc index 90f5331..332a1d2 100644 --- a/gcc/tree-ssa-threadbackward.cc +++ b/gcc/tree-ssa-threadbackward.cc @@ -91,7 +91,6 @@ private: edge maybe_register_path (); void maybe_register_path_dump (edge taken_edge); void find_paths_to_names (basic_block bb, bitmap imports); - void resolve_phi (gphi *phi, bitmap imports); edge find_taken_edge (const vec<basic_block> &path); edge find_taken_edge_cond (const vec<basic_block> &path, gcond *); edge find_taken_edge_switch (const vec<basic_block> &path, gswitch *); @@ -244,10 +243,9 @@ back_threader::maybe_register_path () bool irreducible = false; if (m_profit.profitable_path_p (m_path, m_name, taken_edge, &irreducible) - && debug_counter ()) + && debug_counter () + && m_registry.register_path (m_path, taken_edge)) { - m_registry.register_path (m_path, taken_edge); - if (irreducible) vect_free_loop_info_assumptions (m_path[0]->loop_father); } @@ -335,71 +333,6 @@ back_threader::find_taken_edge_cond (const vec<basic_block> &path, return NULL; } -// Populate a vector of trees from a bitmap. - -static inline void -populate_worklist (vec<tree> &worklist, bitmap bits) -{ - bitmap_iterator bi; - unsigned i; - - EXECUTE_IF_SET_IN_BITMAP (bits, 0, i, bi) - { - tree name = ssa_name (i); - worklist.quick_push (name); - } -} - -// Find jump threading paths that go through a PHI. - -void -back_threader::resolve_phi (gphi *phi, bitmap interesting) -{ - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi))) - return; - - for (size_t i = 0; i < gimple_phi_num_args (phi); ++i) - { - edge e = gimple_phi_arg_edge (phi, i); - - // This is like path_crosses_loops in profitable_path_p but more - // restrictive to avoid peeling off loop iterations (see - // tree-ssa/pr14341.c for an example). - bool profitable_p = m_path[0]->loop_father == e->src->loop_father; - if (!profitable_p) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, - " FAIL: path through PHI in bb%d (incoming bb:%d) crosses loop\n", - e->dest->index, e->src->index); - fprintf (dump_file, "path: %d->", e->src->index); - dump_path (dump_file, m_path); - fprintf (dump_file, "->xx REJECTED\n"); - } - continue; - } - - tree arg = gimple_phi_arg_def (phi, i); - unsigned v = 0; - - if (TREE_CODE (arg) == SSA_NAME - && !bitmap_bit_p (interesting, SSA_NAME_VERSION (arg))) - { - // Record that ARG is interesting when searching down this path. - v = SSA_NAME_VERSION (arg); - gcc_checking_assert (v != 0); - bitmap_set_bit (interesting, v); - bitmap_set_bit (m_imports, v); - } - - find_paths_to_names (e->src, interesting); - - if (v) - bitmap_clear_bit (interesting, v); - } -} - // Find jump threading paths to any of the SSA names in the // INTERESTING bitmap, and register any such paths. // @@ -417,51 +350,75 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) if (m_path.length () > 1 && (!m_profit.profitable_path_p (m_path, m_name, NULL) || maybe_register_path ())) - { - m_path.pop (); - m_visited_bbs.remove (bb); - return; - } + ; - auto_bitmap processed; - bool done = false; - // We use a worklist instead of iterating through the bitmap, - // because we may add new items in-flight. - auto_vec<tree> worklist (bitmap_count_bits (interesting)); - populate_worklist (worklist, interesting); - while (!worklist.is_empty ()) + // Continue looking for ways to extend the path + else { - tree name = worklist.pop (); - unsigned i = SSA_NAME_VERSION (name); - gimple *def_stmt = SSA_NAME_DEF_STMT (name); - basic_block def_bb = gimple_bb (def_stmt); - - // Process any PHIs defined in this block. - if (def_bb == bb - && bitmap_set_bit (processed, i) - && gimple_code (def_stmt) == GIMPLE_PHI) + // For further greedy searching we want to remove interesting + // names defined in BB but add ones on the PHI edges for the + // respective edges. We do this by starting with all names + // not defined in BB as interesting, collecting a list of + // interesting PHIs in BB on the fly. Then we iterate over + // predecessor edges, adding interesting PHI edge defs to + // the set of interesting names to consider when processing it. + auto_bitmap new_interesting; + auto_vec<gphi *, 4> interesting_phis; + bitmap_iterator bi; + unsigned i; + EXECUTE_IF_SET_IN_BITMAP (interesting, 0, i, bi) { - resolve_phi (as_a<gphi *> (def_stmt), interesting); - done = true; - break; + tree name = ssa_name (i); + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + if (gimple_bb (def_stmt) != bb) + bitmap_set_bit (new_interesting, i); + else if (gphi *phi = dyn_cast<gphi *> (def_stmt)) + { + tree res = gimple_phi_result (phi); + if (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (res)) + interesting_phis.safe_push (phi); + } } - } - // If there are interesting names not yet processed, keep looking. - if (!done) - { - bitmap_and_compl_into (interesting, processed); - if (!bitmap_empty_p (interesting)) + if (!bitmap_empty_p (new_interesting) + || !interesting_phis.is_empty ()) { + auto_vec<tree, 4> unwind (interesting_phis.length ()); edge_iterator iter; edge e; FOR_EACH_EDGE (e, iter, bb->preds) - if ((e->flags & EDGE_ABNORMAL) == 0) - find_paths_to_names (e->src, interesting); + { + if (e->flags & EDGE_ABNORMAL + // This is like path_crosses_loops in profitable_path_p but + // more restrictive to avoid peeling off loop iterations (see + // tree-ssa/pr14341.c for an example). + // ??? Note this restriction only applied when visiting an + // interesting PHI with the former resolve_phi. + || (!interesting_phis.is_empty () + && m_path[0]->loop_father != e->src->loop_father)) + continue; + for (gphi *phi : interesting_phis) + { + tree def = PHI_ARG_DEF_FROM_EDGE (phi, e); + if (TREE_CODE (def) == SSA_NAME) + if (bitmap_set_bit (new_interesting, + SSA_NAME_VERSION (def))) + { + bitmap_set_bit (m_imports, SSA_NAME_VERSION (def)); + unwind.quick_push (def); + } + } + find_paths_to_names (e->src, new_interesting); + // Restore new_interesting. We leave m_imports alone since + // we do not prune defs in BB from it and separately keeping + // track of which bits to unwind isn't worth the trouble. + for (tree def : unwind) + bitmap_clear_bit (new_interesting, SSA_NAME_VERSION (def)); + unwind.truncate (0); + } } } // Reset things to their original state. - bitmap_ior_into (interesting, processed); m_path.pop (); m_visited_bbs.remove (bb); } @@ -777,6 +734,13 @@ back_threader_profitability::profitable_path_p (const vec<basic_block> &m_path, "exceeds PARAM_MAX_FSM_THREAD_PATH_INSNS.\n"); return false; } + if (taken_edge && probably_never_executed_edge_p (cfun, taken_edge)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " FAIL: Jump-thread path not considered: " + "path leads to probably never executed edge.\n"); + return false; + } edge entry = find_edge (m_path[m_path.length () - 1], m_path[m_path.length () - 2]); if (probably_never_executed_edge_p (cfun, entry)) @@ -787,7 +751,7 @@ back_threader_profitability::profitable_path_p (const vec<basic_block> &m_path, return false; } } - else if (!m_speed_p && n_insns > 1) + else if (n_insns > 1) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " FAIL: Jump-thread path not considered: " @@ -893,8 +857,7 @@ back_threader_registry::register_path (const vec<basic_block> &m_path, } push_edge (jump_thread_path, taken_edge, EDGE_NO_COPY_SRC_BLOCK); - register_jump_thread (jump_thread_path); - return true; + return register_jump_thread (jump_thread_path); } // Thread all suitable paths in the current function. diff --git a/gcc/tree-ssa-threadupdate.cc b/gcc/tree-ssa-threadupdate.cc index 0f2b319..59c268a 100644 --- a/gcc/tree-ssa-threadupdate.cc +++ b/gcc/tree-ssa-threadupdate.cc @@ -2679,7 +2679,8 @@ fwd_jt_path_registry::update_cfg (bool may_peel_loop_headers) { edge e = (*path)[j]->e; if (m_removed_edges->find_slot (e, NO_INSERT) - || ((*path)[j]->type == EDGE_COPY_SRC_BLOCK + || (((*path)[j]->type == EDGE_COPY_SRC_BLOCK + || (*path)[j]->type == EDGE_COPY_SRC_JOINER_BLOCK) && !can_duplicate_block_p (e->src))) break; } diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index 8b5ab54..ea3b83c 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -40,7 +40,8 @@ vrange_storage::alloc_slot (const vrange &r) if (is_a <irange> (r)) return irange_storage_slot::alloc_slot (*m_alloc, as_a <irange> (r)); - + if (is_a <frange> (r)) + return frange_storage_slot::alloc_slot (*m_alloc, as_a <frange> (r)); return NULL; } @@ -55,6 +56,12 @@ vrange_storage::set_vrange (void *slot, const vrange &r) gcc_checking_assert (s->fits_p (as_a <irange> (r))); s->set_irange (as_a <irange> (r)); } + else if (is_a <frange> (r)) + { + frange_storage_slot *s = static_cast <frange_storage_slot *> (slot); + gcc_checking_assert (s->fits_p (as_a <frange> (r))); + s->set_frange (as_a <frange> (r)); + } else gcc_unreachable (); } @@ -70,6 +77,12 @@ vrange_storage::get_vrange (const void *slot, vrange &r, tree type) = static_cast <const irange_storage_slot *> (slot); s->get_irange (as_a <irange> (r), type); } + else if (is_a <frange> (r)) + { + const frange_storage_slot *s + = static_cast <const frange_storage_slot *> (slot); + s->get_frange (as_a <frange> (r), type); + } else gcc_unreachable (); } @@ -85,6 +98,12 @@ vrange_storage::fits_p (const void *slot, const vrange &r) = static_cast <const irange_storage_slot *> (slot); return s->fits_p (as_a <irange> (r)); } + if (is_a <frange> (r)) + { + const frange_storage_slot *s + = static_cast <const frange_storage_slot *> (slot); + return s->fits_p (as_a <frange> (r)); + } gcc_unreachable (); return false; } @@ -215,3 +234,43 @@ debug (const irange_storage_slot &storage) storage.dump (); fprintf (stderr, "\n"); } + +// Implementation of frange_storage_slot. + +frange_storage_slot * +frange_storage_slot::alloc_slot (vrange_allocator &allocator, const frange &r) +{ + size_t size = sizeof (frange_storage_slot); + frange_storage_slot *p + = static_cast <frange_storage_slot *> (allocator.alloc (size)); + new (p) frange_storage_slot (r); + return p; +} + +void +frange_storage_slot::set_frange (const frange &r) +{ + gcc_checking_assert (fits_p (r)); + gcc_checking_assert (!r.undefined_p ()); + + m_props = r.m_props; +} + +void +frange_storage_slot::get_frange (frange &r, tree type) const +{ + gcc_checking_assert (r.supports_type_p (type)); + + r.set_varying (type); + r.m_props = m_props; + r.normalize_kind (); + + if (flag_checking) + r.verify_range (); +} + +bool +frange_storage_slot::fits_p (const frange &) const +{ + return true; +} diff --git a/gcc/value-range-storage.h b/gcc/value-range-storage.h index 5a3336b..3fac5ea 100644 --- a/gcc/value-range-storage.h +++ b/gcc/value-range-storage.h @@ -100,6 +100,25 @@ private: trailing_wide_ints<MAX_INTS> m_ints; }; +// A chunk of memory to store an frange to long term memory. + +class GTY (()) frange_storage_slot +{ + public: + static frange_storage_slot *alloc_slot (vrange_allocator &, const frange &r); + void set_frange (const frange &r); + void get_frange (frange &r, tree type) const; + bool fits_p (const frange &) const; + private: + frange_storage_slot (const frange &r) { set_frange (r); } + DISABLE_COPY_AND_ASSIGN (frange_storage_slot); + + // We can get away with just storing the properties because the type + // can be gotten from the SSA, and UNDEFINED is unsupported, so it + // can only be a range. + frange_props m_props; +}; + class obstack_vrange_allocator : public vrange_allocator { public: diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 2923f4f..a2273f5 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -105,7 +105,7 @@ vrange::type () const } bool -vrange::supports_type_p (tree) const +vrange::supports_type_p (const_tree) const { return false; } @@ -229,7 +229,7 @@ vrange::dump (FILE *file) const } bool -irange::supports_type_p (tree type) const +irange::supports_type_p (const_tree type) const { return supports_p (type); } @@ -248,78 +248,108 @@ 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 frange::accept (const vrange_visitor &v) const { v.visit (*this); } -// Setter for franges. Currently only singletons are supported. +// Helper function to compare floats. Returns TRUE if op1 .CODE. op2 +// is nonzero. + +static inline bool +tree_compare (tree_code code, tree op1, tree op2) +{ + return !integer_zerop (fold_build2 (code, integer_type_node, op1, op2)); +} + +// Setter for franges. void frange::set (tree min, tree max, value_range_kind kind) { - gcc_checking_assert (kind == VR_RANGE); - gcc_checking_assert (operand_equal_p (min, max)); gcc_checking_assert (TREE_CODE (min) == REAL_CST); + gcc_checking_assert (TREE_CODE (max) == REAL_CST); + + if (kind == VR_UNDEFINED) + { + set_undefined (); + return; + } + + // Treat VR_ANTI_RANGE and VR_VARYING as varying. + if (kind != VR_RANGE) + { + set_varying (TREE_TYPE (min)); + return; + } m_kind = kind; m_type = TREE_TYPE (min); + m_props.set_varying (); - REAL_VALUE_TYPE *const cst = TREE_REAL_CST_PTR (min); - if (real_isnan (cst)) - m_props.nan_set_yes (); - else - m_props.nan_set_no (); + bool is_min = vrp_val_is_min (min); + bool is_max = vrp_val_is_max (max); + bool is_nan = (real_isnan (TREE_REAL_CST_PTR (min)) + || real_isnan (TREE_REAL_CST_PTR (max))); + + // Ranges with a NAN and a non-NAN endpoint are nonsensical. + gcc_checking_assert (!is_nan || operand_equal_p (min, max)); - if (real_isinf (cst)) + // The properties for singletons can be all set ahead of time. + if (operand_equal_p (min, max)) { - if (real_isneg (cst)) - { - m_props.inf_set_no (); - m_props.ninf_set_yes (); - } + // Set INF properties. + if (is_min) + m_props.ninf_set_yes (); else - { - m_props.inf_set_yes (); - m_props.ninf_set_no (); - } + m_props.ninf_set_no (); + if (is_max) + m_props.inf_set_yes (); + else + m_props.inf_set_no (); + // Set NAN property. + if (is_nan) + m_props.nan_set_yes (); + else + m_props.nan_set_no (); } else { - m_props.inf_set_no (); - m_props.ninf_set_no (); + // Mark when the endpoints can't be +-INF. + if (!is_min) + m_props.ninf_set_no (); + if (!is_max) + m_props.inf_set_no (); } + // Check for swapped ranges. + gcc_checking_assert (is_nan || tree_compare (LE_EXPR, min, max)); + + normalize_kind (); + if (flag_checking) verify_range (); } -// Normalize range to VARYING or UNDEFINED, or vice versa. +// Normalize range to VARYING or UNDEFINED, or vice versa. Return +// TRUE if anything changed. // // A range with no known properties can be dropped to VARYING. // Similarly, a VARYING with any properties should be dropped to a // VR_RANGE. Normalizing ranges upon changing them ensures there is // only one representation for a given range. -void +bool frange::normalize_kind () { if (m_kind == VR_RANGE) { // No FP properties set means varying. - if (m_props.nan_varying_p () - && m_props.inf_varying_p () - && m_props.ninf_varying_p ()) + if (m_props.varying_p ()) { set_varying (m_type); - return; + return true; } // Undefined is viral. if (m_props.nan_undefined_p () @@ -327,17 +357,19 @@ frange::normalize_kind () || m_props.ninf_undefined_p ()) { set_undefined (); - return; + return true; } } else if (m_kind == VR_VARYING) { // If a VARYING has any FP properties, it's no longer VARYING. - if (!m_props.nan_varying_p () - || !m_props.inf_varying_p () - || !m_props.ninf_varying_p ()) - m_kind = VR_RANGE; + if (!m_props.varying_p ()) + { + m_kind = VR_RANGE; + return true; + } } + return false; } bool @@ -354,7 +386,7 @@ frange::union_ (const vrange &v) } bool ret = m_props.union_ (r.m_props); - normalize_kind (); + ret |= normalize_kind (); if (flag_checking) verify_range (); @@ -380,7 +412,7 @@ frange::intersect (const vrange &v) } bool ret = m_props.intersect (r.m_props); - normalize_kind (); + ret |= normalize_kind (); if (flag_checking) verify_range (); @@ -416,7 +448,7 @@ frange::operator== (const frange &src) const } bool -frange::supports_type_p (tree type) const +frange::supports_type_p (const_tree type) const { return supports_p (type); } @@ -429,12 +461,11 @@ frange::verify_range () gcc_checking_assert (m_props.undefined_p ()); return; } - else if (varying_p ()) + if (varying_p ()) { gcc_checking_assert (m_props.varying_p ()); return; } - gcc_checking_assert (m_kind == VR_RANGE); gcc_checking_assert (!m_props.varying_p () && !m_props.undefined_p ()); } diff --git a/gcc/value-range.h b/gcc/value-range.h index e43fbe3..856947d 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -78,7 +78,7 @@ public: virtual void accept (const class vrange_visitor &v) const = 0; virtual void set (tree, tree, value_range_kind = VR_RANGE); virtual tree type () const; - virtual bool supports_type_p (tree type) const; + virtual bool supports_type_p (const_tree type) const; virtual void set_varying (tree type); virtual void set_undefined (); virtual bool union_ (const vrange &); @@ -122,8 +122,8 @@ public: virtual void set_undefined () override; // Range types. - static bool supports_p (tree type); - virtual bool supports_type_p (tree type) const override; + static bool supports_p (const_tree type); + virtual bool supports_type_p (const_tree type) const override; virtual tree type () const override; // Iteration over sub-ranges. @@ -250,7 +250,15 @@ private: class unsupported_range : public vrange { public: - unsupported_range (); + unsupported_range () + { + m_discriminator = VR_UNKNOWN; + set_undefined (); + } + virtual void set_undefined () final override + { + m_kind = VR_UNDEFINED; + } virtual void accept (const vrange_visitor &v) const override; }; @@ -336,10 +344,9 @@ class frange : public vrange public: frange (); frange (const frange &); - static bool supports_p (tree type) + static bool supports_p (const_tree type) { - // Disabled until floating point range-ops come live. - return 0 && SCALAR_FLOAT_TYPE_P (type); + return SCALAR_FLOAT_TYPE_P (type); } virtual tree type () const override; virtual void set (tree, tree, value_range_kind = VR_RANGE) override; @@ -347,7 +354,7 @@ public: virtual void set_undefined () override; virtual bool union_ (const vrange &) override; virtual bool intersect (const vrange &) override; - virtual bool supports_type_p (tree type) const override; + virtual bool supports_type_p (const_tree type) const override; virtual void accept (const vrange_visitor &v) const override; frange& operator= (const frange &); bool operator== (const frange &) const; @@ -359,7 +366,7 @@ public: FRANGE_PROP_ACCESSOR(ninf) private: void verify_range (); - void normalize_kind (); + bool normalize_kind (); frange_props m_props; tree m_type; @@ -457,7 +464,7 @@ public: operator vrange &(); operator const vrange &() const; void dump (FILE *) const; - static bool supports_type_p (tree type); + static bool supports_type_p (const_tree type); // Convenience methods for vrange compatability. void set (tree min, tree max, value_range_kind kind = VR_RANGE) @@ -588,7 +595,7 @@ Value_Range::operator const vrange &() const // Return TRUE if TYPE is supported by the vrange infrastructure. inline bool -Value_Range::supports_type_p (tree type) +Value_Range::supports_type_p (const_tree type) { return irange::supports_p (type) || frange::supports_p (type); } @@ -730,7 +737,7 @@ irange::nonzero_p () const } inline bool -irange::supports_p (tree type) +irange::supports_p (const_tree type) { return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); } @@ -1010,6 +1017,45 @@ irange::normalize_kind () } } +// Return the maximum value for TYPE. + +inline tree +vrp_val_max (const_tree type) +{ + if (INTEGRAL_TYPE_P (type)) + return TYPE_MAX_VALUE (type); + if (POINTER_TYPE_P (type)) + { + wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + return wide_int_to_tree (const_cast<tree> (type), max); + } + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE real; + real_inf (&real); + return build_real (const_cast <tree> (type), real); + } + return NULL_TREE; +} + +// Return the minimum value for TYPE. + +inline tree +vrp_val_min (const_tree type) +{ + if (INTEGRAL_TYPE_P (type)) + return TYPE_MIN_VALUE (type); + if (POINTER_TYPE_P (type)) + return build_zero_cst (const_cast<tree> (type)); + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE real, real_ninf; + real_inf (&real); + real_ninf = real_value_negate (&real); + return build_real (const_cast <tree> (type), real_ninf); + } + return NULL_TREE; +} // Supporting methods for frange. @@ -1039,7 +1085,6 @@ inline frange::frange () { m_discriminator = VR_FRANGE; - m_type = nullptr; set_undefined (); } @@ -1072,32 +1117,4 @@ frange::set_undefined () m_props.set_undefined (); } - -// Return the maximum value for TYPE. - -inline tree -vrp_val_max (const_tree type) -{ - if (INTEGRAL_TYPE_P (type)) - return TYPE_MAX_VALUE (type); - if (POINTER_TYPE_P (type)) - { - wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - return wide_int_to_tree (const_cast<tree> (type), max); - } - return NULL_TREE; -} - -// Return the minimum value for TYPE. - -inline tree -vrp_val_min (const_tree type) -{ - if (INTEGRAL_TYPE_P (type)) - return TYPE_MIN_VALUE (type); - if (POINTER_TYPE_P (type)) - return build_zero_cst (const_cast<tree> (type)); - return NULL_TREE; -} - #endif // GCC_VALUE_RANGE_H diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc index a447021..3f0957c 100644 --- a/gcc/value-relation.cc +++ b/gcc/value-relation.cc @@ -1400,16 +1400,7 @@ path_oracle::killing_def (tree ssa) unsigned v = SSA_NAME_VERSION (ssa); bitmap_set_bit (m_killed_defs, v); - - // Walk the equivalency list and remove SSA from any equivalencies. - if (bitmap_bit_p (m_equiv.m_names, v)) - { - for (equiv_chain *ptr = m_equiv.m_next; ptr; ptr = ptr->m_next) - if (bitmap_bit_p (ptr->m_names, v)) - bitmap_clear_bit (ptr->m_names, v); - } - else - bitmap_set_bit (m_equiv.m_names, v); + bitmap_set_bit (m_equiv.m_names, v); // Now add an equivalency with itself so we don't look to the root oracle. bitmap b = BITMAP_ALLOC (&m_bitmaps); |