diff options
author | Martin Liska <mliska@suse.cz> | 2022-10-28 10:02:34 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-10-28 10:02:34 +0200 |
commit | 1eb021edb27e26f95cda63df121f6bc951647599 (patch) | |
tree | 7f132fded85bd7d05d81cd4c1227da2fd0c3c2d5 /gcc | |
parent | 62e475bad0d668c432bb97113cbf73fa281b8b55 (diff) | |
parent | 0607307768b66a90e27c5bc91a247acc938f070e (diff) | |
download | gcc-1eb021edb27e26f95cda63df121f6bc951647599.zip gcc-1eb021edb27e26f95cda63df121f6bc951647599.tar.gz gcc-1eb021edb27e26f95cda63df121f6bc951647599.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc')
111 files changed, 3192 insertions, 489 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6b8ba1d..a318a22 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,234 @@ +2022-10-27 Eric Botcazou <ebotcazou@adacore.com> + + * config/aarch64/aarch64.h (DONT_USE_BUILTIN_SETJMP): Delete. + +2022-10-27 H.J. Lu <hjl.tools@gmail.com> + + PR target/107172 + * config/i386/i386.md (UNSPEC_CC_NE): New. + Replace ne:CCC/ne:CCO with UNSPEC_CC_NE in neg patterns. + +2022-10-27 Andrew Pinski <apinski@marvell.com> + + * tree-ssa-phiopt.cc: Include tree-ssa-dce.h + (replace_phi_edge_with_variable): + New argument, dce_ssa_names. Call simple_dce_from_worklist. + (match_simplify_replacement): If we inserted a sequence, + mark the lhs of the new sequence to be possible dce. + Always move the statement and mark the lhs (if it is a name) + as possible to remove. + +2022-10-27 Richard Sandiford <richard.sandiford@arm.com> + + * config/aarch64/aarch64-protos.h: Replace constexpr with + CONSTEXPR. + * config/aarch64/aarch64-sve-builtins-base.cc: Likewise. + * config/aarch64/aarch64-sve-builtins-functions.h: Likewise. + * config/aarch64/aarch64-sve-builtins-shapes.cc: Likewise. + * config/aarch64/aarch64-sve-builtins-sve2.cc: Likewise. + * config/aarch64/aarch64-sve-builtins.cc: Likewise. + * config/aarch64/aarch64.cc: Likewise. + * config/aarch64/driver-aarch64.cc: Likewise + +2022-10-27 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107394 + * value-range-storage.cc (frange_storage_slot::get_frange): Use + frange constructor. + +2022-10-27 Thomas Schwinge <thomas@codesourcery.com> + + * optc-save-gen.awk: Clarify 'Init' option property usage for + streaming optimization. + +2022-10-27 Torbjörn SVENSSON <torbjorn.svensson@foss.st.com> + Yvan ROUX <yvan.roux@foss.st.com> + + * ira.cc: Resize array after reg number increased. + +2022-10-27 Jiawei <jiawei@iscas.ac.cn> + Sinan Lin <sinan@isrc.iscas.ac.cn> + + * config/riscv/constraints.md (TARGET_ZFINX ? GR_REGS): Set GPRS + use while Zfinx is enable. + * config/riscv/riscv.cc (riscv_hard_regno_mode_ok): Limit odd + registers use when Zdinx enable in RV32 cases. + (riscv_option_override): New target enable MASK_FDIV. + (riscv_libgcc_floating_mode_supported_p): New error info when + use incompatible arch&abi. + (riscv_excess_precision): New target enable FLOAT16. + +2022-10-27 Jiawei <jiawei@iscas.ac.cn> + + * config/riscv/iterators.md (TARGET_ZFINX):New target. + (TARGET_ZDINX): Ditto. + (TARGET_ZHINX): Ditto. + * config/riscv/riscv-builtins.cc (AVAIL): Ditto. + (riscv_atomic_assign_expand_fenv): Ditto. + * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Ditto. + * config/riscv/riscv.md: Ditto. + +2022-10-27 Jiawei <jiawei@iscas.ac.cn> + Sinan Lin <sinan@isrc.iscas.ac.cn> + + * common/config/riscv/riscv-common.cc: New extensions. + * config/riscv/arch-canonicalize: New imply relations. + * config/riscv/riscv-opts.h (MASK_ZFINX): New mask. + (MASK_ZDINX): Ditto. + (MASK_ZHINX): Ditto. + (MASK_ZHINXMIN): Ditto. + (TARGET_ZFINX): New target. + (TARGET_ZDINX): Ditto. + (TARGET_ZHINX): Ditto. + (TARGET_ZHINXMIN): Ditto. + * config/riscv/riscv.opt: New target variable. + +2022-10-26 David Faust <david.faust@oracle.com> + + * config/bpf/bpf.cc: Support __builtin_preserve_field_info. + (enum bpf_builtins): Add new builtin. + (bpf_init_builtins): Likewise. + (bpf_core_field_info): New function. + (bpf_expand_builtin): Accomodate new builtin. Refactor adding new + relocation to... + (maybe_make_core_relo): ... here. New function. + (bpf_resolve_overloaded_builtin): Accomodate new builtin. + (bpf_core_newdecl): Likewise. + (bpf_core_walk): Likewise. + (bpf_core_is_maybe_aggregate_access): Improve logic. + (struct core_walk_data): New. + * config/bpf/coreout.cc (bpf_core_reloc_add): Allow adding different + relocation kinds. + * config/bpf/coreout.h: Analogous change. + * doc/extend.texi: Document BPF __builtin_preserve_field_info. + +2022-10-26 Marek Polacek <polacek@redhat.com> + + PR c++/106393 + * doc/invoke.texi: Document -Wdangling-reference. + +2022-10-26 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp> + + * config/xtensa/xtensa.md (movdi): + Copy operands[0...1] to ops[0...3] and then use the latter before + calling xtensa_split_DI_reg_imm() and emitting insns. + +2022-10-26 Alexander Monakov <amonakov@ispras.ru> + + PR other/107353 + * ipa-visibility.cc (function_and_variable_visibility): + Conditionally upgrade TLS model instead of asserting. + +2022-10-26 Andrew MacLeod <amacleod@redhat.com> + + * gimple-range-fold.cc (fold_using_range::fold_stmt): Check if + stmt is non-negative and adjust the range. + +2022-10-26 Martin Liska <mliska@suse.cz> + + * common/config/i386/cpuinfo.h (has_cpu_feature): Add comment. + (reset_cpu_feature): New. + (get_zhaoxin_cpu): Use reset_cpu_feature. + +2022-10-26 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv.cc (riscv_expand_epilogue): Fix statement. + +2022-10-26 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + PR target/107357 + * config/riscv/riscv-modes.def (VECTOR_BOOL_MODE): Set to minimum size. + (ADJUST_NUNITS): Adjust according to -march. + (ADJUST_BYTESIZE): Ditto. + * config/riscv/riscv-protos.h (riscv_v_ext_enabled_vector_mode_p): + Remove. + (riscv_v_ext_vector_mode_p): Change function implementation. + * config/riscv/riscv-vector-builtins.cc (rvv_switcher::rvv_switcher): + Change to riscv_v_ext_vector_mode_p. + (register_builtin_type): Ditto. + * config/riscv/riscv.cc (riscv_v_ext_vector_mode_p): Change to enabled + modes. + (ENTRY): Ditto. + (riscv_v_ext_enabled_vector_mode_p): Remove. + (riscv_v_adjust_nunits): New function. + (riscv_vector_mode_supported_p): Use riscv_v_ext_vector_mode_p instead. + * config/riscv/riscv.h (riscv_v_adjust_nunits): New function. + +2022-10-26 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * config.gcc (riscv*): Add riscv-v.o to extra_objs. + * config/riscv/constraints.md (vu): New constraint. + (vi): Ditto. + (Wc0): Ditto. + (Wc1): Ditto. + * config/riscv/predicates.md (vector_length_operand): New. + (reg_or_mem_operand): Ditto. + (vector_move_operand): Ditto. + (vector_mask_operand): Ditto. + (vector_merge_operand): Ditto. + * config/riscv/riscv-protos.h (riscv_regmode_natural_size) New. + (riscv_vector::const_vec_all_same_in_range_p): Ditto. + (riscv_vector::legitimize_move): Ditto. + (tail_policy): Ditto. + (mask_policy): Ditto. + * config/riscv/riscv-v.cc: New. + * config/riscv/riscv-vector-builtins-bases.cc + (vsetvl::expand): Refactor how LMUL encoding. + * config/riscv/riscv.cc (riscv_print_operand): Update how LMUL + print and mask operand print. + (riscv_regmode_natural_size): New. + * config/riscv/riscv.h (REGMODE_NATURAL_SIZE): New. + * config/riscv/riscv.md (mode): Add vector modes. + * config/riscv/t-riscv (riscv-v.o) New. + * config/riscv/vector-iterators.md: New. + * config/riscv/vector.md (vundefined<mode>): New. + (mov<mode>): New. + (*mov<mode>): New. + (@vsetvl<mode>_no_side_effects): New. + (@pred_mov<mode>): New. + +2022-10-26 Monk Chiang <monk.chiang@sifive.com> + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Add svinval and svnapot extension. + (riscv_ext_flag_table): Ditto. + * config/riscv/riscv-opts.h (MASK_SVINVAL): New. + (MASK_SVNAPOT): Ditto. + (TARGET_SVINVAL): Ditto. + (TARGET_SVNAPOT): Ditto. + * config/riscv/riscv.opt (riscv_sv_subext): New. + +2022-10-26 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * config/riscv/riscv-modes.def: Adjust table indentation in commnet. + +2022-10-26 Martin Liska <mliska@suse.cz> + + * configure: Regenerate. + +2022-10-26 Aldy Hernandez <aldyh@redhat.com> + + * value-range.cc (frange::set): Use HONOR_*. + (frange::verify_range): Same. + * value-range.h (frange_val_min): Same. + (frange_val_max): Same. + +2022-10-26 Jiufu Guo <guojiufu@linux.ibm.com> + + PR target/106460 + * config/rs6000/rs6000.cc (rs6000_cannot_force_const_mem): Return true + for HIGH code rtx. + +2022-10-26 Kito Cheng <kito.cheng@sifive.com> + + * common/config/riscv/riscv-common.cc (riscv_ext_version_table): + Add `h`. + (riscv_supported_std_ext): Ditto. + (multi_letter_subset_rank): Remove `h`. + (riscv_subset_list::parse_std_ext): Handle `h` as single letter + extension. + (riscv_subset_list::parse): Ditto. + 2022-10-25 Eugene Rozenfeld <erozen@microsoft.com> * auto-profile.cc (get_combined_location): Include discriminator in the diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 03e9228..7109ae3 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20221026 +20221028 diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 733580a..6e6b056 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,14 @@ +2022-10-26 David Malcolm <dmalcolm@redhat.com> + + * sm-fd.cc (fd_state_machine::on_open): Transition to "unchecked" + when the mode is symbolic, rather than just on integer constants. + (fd_state_machine::check_for_open_fd): Don't complain about + unchecked values in the start state. + +2022-10-26 David Malcolm <dmalcolm@redhat.com> + + * sm-fd.dot: New file. + 2022-10-24 David Malcolm <dmalcolm@redhat.com> PR analyzer/107349 diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index 8a4c208..ae846cd 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -940,25 +940,25 @@ fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node, if (lhs) { tree arg = gimple_call_arg (call, 1); + enum access_mode mode = READ_WRITE; if (TREE_CODE (arg) == INTEGER_CST) { int flag = TREE_INT_CST_LOW (arg); - enum access_mode mode = get_access_mode_from_flag (flag); - - switch (mode) - { - case READ_ONLY: - sm_ctxt->on_transition (node, stmt, lhs, m_start, - m_unchecked_read_only); - break; - case WRITE_ONLY: - sm_ctxt->on_transition (node, stmt, lhs, m_start, - m_unchecked_write_only); - break; - default: - sm_ctxt->on_transition (node, stmt, lhs, m_start, - m_unchecked_read_write); - } + mode = get_access_mode_from_flag (flag); + } + switch (mode) + { + case READ_ONLY: + sm_ctxt->on_transition (node, stmt, lhs, m_start, + m_unchecked_read_only); + break; + case WRITE_ONLY: + sm_ctxt->on_transition (node, stmt, lhs, m_start, + m_unchecked_write_only); + break; + default: + sm_ctxt->on_transition (node, stmt, lhs, m_start, + m_unchecked_read_write); } } else @@ -1096,7 +1096,7 @@ fd_state_machine::check_for_open_fd ( else { - if (!(is_valid_fd_p (state) || (state == m_stop))) + if (!(is_valid_fd_p (state) || state == m_start || state == m_stop)) { if (!is_constant_fd_p (state)) sm_ctxt->warn ( diff --git a/gcc/analyzer/sm-fd.dot b/gcc/analyzer/sm-fd.dot new file mode 100644 index 0000000..175daae --- /dev/null +++ b/gcc/analyzer/sm-fd.dot @@ -0,0 +1,109 @@ +/* An overview of the state machine from sm-fd.cc. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Keep this in-sync with sm-dot.cc */ + +digraph "fd" { + + /* STATES. */ + + /* Start state. */ + start; + + /* States representing a file descriptor that hasn't yet been + checked for validity after opening, for three different + access modes. */ + unchecked_read_write; + unchecked_read_only; + unchecked_write_only; + + /* States for representing a file descriptor that is known to be valid (>= + 0), for three different access modes. */ + valid_read_write; + valid_read_only; + valid_write_only; + + /* State for a file descriptor that is known to be invalid (< 0). */ + invalid; + + /* State for a file descriptor that has been closed. */ + closed; + + /* State for a file descriptor that we do not want to track anymore . */ + stop; + + /* TRANSITIONS. */ + + /* On "open". */ + start -> unchecked_read_only [label="on 'X = open(..., O_RDONLY);'"]; + start -> unchecked_write_only [label="on 'X = open(..., O_WRONLY);'"]; + start -> unchecked_read_write [label="on 'X = open(..., ...);'"]; + + /* On "creat". */ + start -> unchecked_write_only [label="on 'X = create(...);'"]; + + /* On "close". */ + start -> closed [label="on 'close(X);'"]; + unchecked_read_write -> closed [label="on 'close(X);'"]; + unchecked_read_only -> closed [label="on 'close(X);'"]; + unchecked_write_only -> closed [label="on 'close(X);'"]; + valid_read_write -> closed [label="on 'close(X);'"]; + valid_read_only -> closed [label="on 'close(X);'"]; + valid_write_only -> closed [label="on 'close(X);'"]; + constant_fd -> closed [label="on 'close(X);'"]; + closed -> stop [label="on 'close(X);':\nWarn('double close')"]; + + /* On "read". */ + closed -> closed [label="on 'read(X);':\nWarn('use after close')"]; + unchecked_read_write -> unchecked_read_write [label="on 'read(X);:\nWarn('use without check')'"]; + unchecked_read_only -> unchecked_read_only [label="on 'read(X);:\nWarn('use without check')'"]; + unchecked_write_only -> unchecked_write_only [label="on 'read(X);:\nWarn('use without check')'"]; + valid_write_only -> valid_write_only [label="on 'read(X);:\nWarn('access mode mismatch')'"]; + + /* On "write". */ + closed -> closed [label="on 'write(X);':\nWarn('use after close')"]; + unchecked_read_write -> unchecked_read_write [label="on 'write(X);:\nWarn('use without check')'"]; + unchecked_read_only -> unchecked_read_only [label="on 'write(X);:\nWarn('use without check')'"]; + unchecked_write_only -> unchecked_write_only [label="on 'write(X);:\nWarn('use without check')'"]; + valid_read_only -> valid_read_only [label="on 'write(X);:\nWarn('access mode mismatch')'"]; + + /* On "dup". */ + closed -> closed [label="on 'dup(X);':\nWarn('use after close')"]; + /* plus stuff for the new fd. */ + + /* On "pipe". */ + start -> valid_read_write [label="when 'pipe()' succeeds"]; + + /* on_condition. */ + unchecked_read_write -> valid_read_write [label="on 'X >= 0'"]; + unchecked_read_only -> valid_read_only [label="on 'X >= 0'"]; + unchecked_write_only -> valid_write_only [label="on 'X >= 0'"]; + unchecked_read_write -> invalid [label="on 'X < 0'"]; + unchecked_read_only -> invalid [label="on 'X < 0'"]; + unchecked_write_only -> invalid [label="on 'X < 0'"]; + + /* Leaks. */ + unchecked_read_write -> stop [label="on leak:\nWarn('leak')"]; + unchecked_read_only -> stop [label="on leak:\nWarn('leak')"]; + unchecked_write_only -> stop [label="on leak:\nWarn('leak')"]; + valid_read_write -> stop [label="on leak:\nWarn('leak')"]; + valid_read_only -> stop [label="on leak:\nWarn('leak')"]; + valid_write_only -> stop [label="on leak:\nWarn('leak')"]; +} diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index bb85e78..ee7b511 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2022-10-26 Marek Polacek <polacek@redhat.com> + + PR c++/106393 + * c.opt (Wdangling-reference): New. + 2022-10-19 Joseph Myers <joseph@codesourcery.com> * c-format.h (enum format_lengths): Add FMT_LEN_w8, FMT_LEN_w16, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 62ab4ba..f9d0d29 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1004,6 +1004,30 @@ extern void c_parse_final_cleanups (void); /* True iff TYPE is cv decltype(nullptr). */ #define NULLPTR_TYPE_P(TYPE) (TREE_CODE (TYPE) == NULLPTR_TYPE) +/* Returns the underlying type of the given enumeration type. The + underlying type is determined in different ways, depending on the + properties of the enum: + + - In C++0x or C2x, the underlying type can be explicitly specified, e.g., + + enum E1 : char { ... } // underlying type is char + + - In a C++0x scoped enumeration, the underlying type is int + unless otherwises specified: + + enum class E2 { ... } // underlying type is int + + - Otherwise, the underlying type is determined based on the + values of the enumerators. In this case, the + ENUM_UNDERLYING_TYPE will not be set until after the definition + of the enumeration is completed by finish_enum. */ +#define ENUM_UNDERLYING_TYPE(TYPE) \ + TREE_TYPE (ENUMERAL_TYPE_CHECK (TYPE)) + +/* Determines whether an ENUMERAL_TYPE has an explicit + underlying type. */ +#define ENUM_FIXED_UNDERLYING_TYPE_P(NODE) (TYPE_LANG_FLAG_5 (NODE)) + extern tree do_case (location_t, tree, tree, tree); extern tree build_stmt (location_t, enum tree_code, ...); extern tree build_real_imag_expr (location_t, enum tree_code, tree); diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc index 6742f44..cd59c3c 100644 --- a/gcc/c-family/c-warn.cc +++ b/gcc/c-family/c-warn.cc @@ -1415,7 +1415,8 @@ warnings_for_convert_and_check (location_t loc, tree type, tree expr, if (TREE_CODE (expr) == INTEGER_CST && (TREE_CODE (type) == INTEGER_TYPE - || TREE_CODE (type) == ENUMERAL_TYPE) + || (TREE_CODE (type) == ENUMERAL_TYPE + && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) != BOOLEAN_TYPE)) && !int_fits_type_p (expr, type)) { /* Do not diagnose overflow in a constant expression merely diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 01d4807..070f85c 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -555,6 +555,10 @@ Wdangling-pointer= C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_dangling_pointer) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall, 2, 0) IntegerRange(0, 2) Warn for uses of pointers to auto variables whose lifetime has ended. +Wdangling-reference +C++ ObjC++ Var(warn_dangling_reference) Warning LangEnabledBy(C++ ObjC++, Wall) +Warn when a reference is bound to a temporary whose lifetime has ended. + Wdate-time C ObjC C++ ObjC++ CPP(warn_date_time) CppReason(CPP_W_DATE_TIME) Var(cpp_warn_date_time) Init(0) Warning Warn about __TIME__, __DATE__ and __TIMESTAMP__ usage. diff --git a/gcc/c/c-convert.cc b/gcc/c/c-convert.cc index 6e74913..8a43e5f 100644 --- a/gcc/c/c-convert.cc +++ b/gcc/c/c-convert.cc @@ -110,8 +110,13 @@ c_convert (tree type, tree expr, bool init_const) case VOID_TYPE: return fold_convert_loc (loc, type, e); - case INTEGER_TYPE: case ENUMERAL_TYPE: + if (ENUM_UNDERLYING_TYPE (type) != NULL_TREE + && TREE_CODE (ENUM_UNDERLYING_TYPE (type)) == BOOLEAN_TYPE) + goto convert_to_boolean; + gcc_fallthrough (); + + case INTEGER_TYPE: if (sanitize_flags_p (SANITIZE_FLOAT_CAST) && current_function_decl != NULL_TREE && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE @@ -129,6 +134,7 @@ c_convert (tree type, tree expr, bool init_const) goto maybe_fold; case BOOLEAN_TYPE: + convert_to_boolean: return fold_convert_loc (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 4746e31..2b83900 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -4817,7 +4817,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) else if (declspecs->typespec_kind != ctsk_tagdef && declspecs->typespec_kind != ctsk_tagfirstref && declspecs->typespec_kind != ctsk_tagfirstref_attrs - && code == ENUMERAL_TYPE) + && code == ENUMERAL_TYPE + && !declspecs->enum_type_specifier_ref_p) { bool warned_enum = false; if (warned != 1) @@ -4883,6 +4884,38 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) warned = 1; } + if (declspecs->enum_type_specifier_ref_p && !warned) + { + if (declspecs->storage_class != csc_none) + { + error ("storage class specifier in empty declaration with %<enum%> " + "underlying type"); + warned = 1; + } + else if (declspecs->thread_p) + { + error ("%qs in empty declaration with %<enum%> underlying type", + declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); + warned = 1; + } + else if (declspecs->const_p + || declspecs->volatile_p + || declspecs->atomic_p + || declspecs->restrict_p + || declspecs->address_space) + { + error ("type qualifier in empty declaration with %<enum%> " + "underlying type"); + warned = 1; + } + else if (declspecs->alignas_p) + { + error ("%<alignas%> in empty declaration with %<enum%> " + "underlying type"); + warned = 1; + } + } + if (!warned && !in_system_header_at (input_location) && declspecs->storage_class != csc_none) { @@ -6496,6 +6529,16 @@ grokdeclarator (const struct c_declarator *declarator, } } + /* An enum type specifier (": specifier-qualifier-list") may only be + specified when the enum is being defined or in an empty + declaration of the form "enum identifier enum-type-specifier;". + Except for the case of an empty declaration that has additional + declaration specifiers, all invalid contexts (declarations that + aren't empty, type names, parameter declarations, member + declarations) pass through grokdeclarator. */ + if (declspecs->enum_type_specifier_ref_p) + error_at (loc, "%<enum%> underlying type may not be specified here"); + /* A function definition's declarator must have the form of a function declarator. */ @@ -8285,12 +8328,15 @@ get_parm_info (bool ellipsis, tree expr) Define the tag as a forward-reference with location LOC if it is not defined. HAVE_STD_ATTRS says whether any standard attributes were present after the struct, union or enum keyword; ATTRS are the - standard attributes present there. Return a c_typespec structure - for the type specifier. */ + standard attributes present there. HAS_ENUM_TYPE_SPECIFIER says + whether an enum type specifier (": specifier-qualifier-list") is + present; if so, this is called before that specifier is parsed, so + that the tag is in scope for that specifier. Return a c_typespec + structure for the type specifier. */ struct c_typespec parser_xref_tag (location_t loc, enum tree_code code, tree name, - bool have_std_attrs, tree attrs) + bool have_std_attrs, tree attrs, bool has_enum_type_specifier) { struct c_typespec ret; tree ref; @@ -8298,11 +8344,13 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = has_enum_type_specifier; - /* If a cross reference is requested, look up the type - already defined for this tag and return it. */ + /* If a cross reference is requested, look up the type already + defined for this tag and return it. If an enum type specifier is + present, only a definition in the current scope is relevant. */ - ref = lookup_tag (code, name, false, &refloc); + ref = lookup_tag (code, name, has_enum_type_specifier, &refloc); /* If this is the right type of tag, return what we found. (This reference will be shadowed by shadow_tag later if appropriate.) If this is the wrong type of tag, do not return it. If it was the @@ -8371,6 +8419,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); TYPE_MIN_VALUE (ref) = TYPE_MIN_VALUE (unsigned_type_node); TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node); + ENUM_FIXED_UNDERLYING_TYPE_P (ref) = has_enum_type_specifier; } pushtag (loc, name, ref); @@ -8387,7 +8436,8 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name, tree xref_tag (enum tree_code code, tree name) { - return parser_xref_tag (input_location, code, name, false, NULL_TREE).spec; + return parser_xref_tag (input_location, code, name, false, NULL_TREE, + false).spec; } /* Make sure that the tag NAME is defined *in the current scope* @@ -9288,12 +9338,15 @@ layout_array_type (tree t) /* Begin compiling the definition of an enumeration type. NAME is its name (or null if anonymous). LOC is the enum's location. + FIXED_UNDERLYING_TYPE is the (C2x) underlying type specified in the + definition. Returns the type object, as yet incomplete. Also records info about it so that build_enumerator may be used to declare the individual values as they are read. */ tree -start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) +start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, + tree fixed_underlying_type) { tree enumtype = NULL_TREE; location_t enumloc = UNKNOWN_LOCATION; @@ -9309,6 +9362,23 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) { enumtype = make_node (ENUMERAL_TYPE); pushtag (loc, name, enumtype); + if (fixed_underlying_type != NULL_TREE) + { + /* For an enum definition with a fixed underlying type, the + type is complete during the definition and the + enumeration constants have that type. If there was a + tag, the type was completed in c_parser_enum_specifier. + If not, it must be completed here. */ + ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) = true; + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (fixed_underlying_type); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (fixed_underlying_type); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (fixed_underlying_type); + SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (fixed_underlying_type)); + TYPE_SIZE (enumtype) = NULL_TREE; + TYPE_PRECISION (enumtype) = TYPE_PRECISION (fixed_underlying_type); + ENUM_UNDERLYING_TYPE (enumtype) = fixed_underlying_type; + layout_type (enumtype); + } } /* Update type location to the one of the definition, instead of e.g. a forward declaration. */ @@ -9336,10 +9406,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name) TYPE_VALUES (enumtype) = NULL_TREE; } + if (ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) + && fixed_underlying_type == NULL_TREE) + error_at (loc, "%<enum%> declared with but defined without " + "fixed underlying type"); + the_enum->enum_next_value = integer_zero_node; + the_enum->enum_type = enumtype; the_enum->enum_overflow = 0; - if (flag_short_enums) + if (flag_short_enums && !ENUM_FIXED_UNDERLYING_TYPE_P (enumtype)) for (tree v = TYPE_MAIN_VARIANT (enumtype); v; v = TYPE_NEXT_VARIANT (v)) TYPE_PACKED (v) = 1; @@ -9403,54 +9479,61 @@ finish_enum (tree enumtype, tree values, tree attributes) (tree_int_cst_lt (minnode, TYPE_MIN_VALUE (integer_type_node)) || tree_int_cst_lt (TYPE_MAX_VALUE (integer_type_node), maxnode)); - /* If the precision of the type was specified with an attribute and it - was too small, give an error. Otherwise, use it. */ - if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) + + if (!ENUM_FIXED_UNDERLYING_TYPE_P (enumtype)) { - if (precision > TYPE_PRECISION (enumtype)) + /* If the precision of the type was specified with an attribute and it + was too small, give an error. Otherwise, use it. */ + if (TYPE_PRECISION (enumtype) && lookup_attribute ("mode", attributes)) { - TYPE_PRECISION (enumtype) = 0; - error ("specified mode too small for enumerated values"); + if (precision > TYPE_PRECISION (enumtype)) + { + TYPE_PRECISION (enumtype) = 0; + error ("specified mode too small for enumerated values"); + } + else + precision = TYPE_PRECISION (enumtype); } else - precision = TYPE_PRECISION (enumtype); - } - else - TYPE_PRECISION (enumtype) = 0; - - if (TYPE_PACKED (enumtype) - || precision > TYPE_PRECISION (integer_type_node) - || TYPE_PRECISION (enumtype)) - { - tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); - if (tem == NULL) - { - /* This should only occur when both signed and unsigned - values of maximum precision occur among the - enumerators. */ - pedwarn (input_location, 0, - "enumeration values exceed range of largest integer"); - tem = widest_integer_literal_type_node; - } - else if (precision > TYPE_PRECISION (intmax_type_node) - && !tree_int_cst_lt (minnode, TYPE_MIN_VALUE (intmax_type_node)) - && !tree_int_cst_lt (TYPE_MAX_VALUE (uintmax_type_node), - maxnode)) - pedwarn (input_location, OPT_Wpedantic, - "enumeration values exceed range of %qs", - sign == UNSIGNED ? "uintmax_t" : "intmax_t"); - } - else - tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; + TYPE_PRECISION (enumtype) = 0; + + if (TYPE_PACKED (enumtype) + || precision > TYPE_PRECISION (integer_type_node) + || TYPE_PRECISION (enumtype)) + { + tem = c_common_type_for_size (precision, sign == UNSIGNED ? 1 : 0); + if (tem == NULL) + { + /* This should only occur when both signed and unsigned + values of maximum precision occur among the + enumerators. */ + pedwarn (input_location, 0, + "enumeration values exceed range of largest integer"); + tem = widest_integer_literal_type_node; + } + else if (precision > TYPE_PRECISION (intmax_type_node) + && !tree_int_cst_lt (minnode, + TYPE_MIN_VALUE (intmax_type_node)) + && !tree_int_cst_lt (TYPE_MAX_VALUE (uintmax_type_node), + maxnode)) + pedwarn (input_location, OPT_Wpedantic, + "enumeration values exceed range of %qs", + sign == UNSIGNED ? "uintmax_t" : "intmax_t"); + } + else + tem = sign == UNSIGNED ? unsigned_type_node : integer_type_node; - TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); - TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); - TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); - SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); - TYPE_SIZE (enumtype) = NULL_TREE; - TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); + TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); + TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); + SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); + TYPE_SIZE (enumtype) = NULL_TREE; + TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); + ENUM_UNDERLYING_TYPE (enumtype) = + c_common_type_for_size (TYPE_PRECISION (tem), TYPE_UNSIGNED (tem)); - layout_type (enumtype); + layout_type (enumtype); + } if (values != error_mark_node) { @@ -9477,8 +9560,10 @@ finish_enum (tree enumtype, tree values, tree attributes) fit in int are given type int in build_enumerator (which is the correct type while the enumeration is being parsed), so no conversions are needed here if all - enumerators fit in int. */ - if (wider_than_int) + enumerators fit in int. If the enum has a fixed + underlying type, the correct type was also given in + build_enumerator. */ + if (!ENUM_FIXED_UNDERLYING_TYPE_P (enumtype) && wider_than_int) ini = convert (enumtype, ini); DECL_INITIAL (enu) = ini; @@ -9516,6 +9601,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); + ENUM_UNDERLYING_TYPE (tem) = ENUM_UNDERLYING_TYPE (enumtype); } /* Finish debugging output for this type. */ @@ -9595,56 +9681,89 @@ build_enumerator (location_t decl_loc, location_t loc, if (the_enum->enum_overflow) error_at (loc, "overflow in enumeration values"); } - /* Even though the underlying type of an enum is unspecified, the - type of enumeration constants is explicitly defined as int - (6.4.4.3/2 in the C99 Standard). C2X allows any integer type, and - GCC allows such types for older standards as an extension. */ - bool warned_range = false; - if (!int_fits_type_p (value, - (TYPE_UNSIGNED (TREE_TYPE (value)) - ? uintmax_type_node - : intmax_type_node))) - /* GCC does not consider its types larger than intmax_t to be - extended integer types (although C2X would permit such types to - be considered extended integer types if all the features - required by <stdint.h> and <inttypes.h> macros, such as support - for integer constants and I/O, were present), so diagnose if - such a wider type is used. (If the wider type arose from a - constant of such a type, that will also have been diagnosed, - but this is the only diagnostic in the case where it arises - from choosing a wider type automatically when adding 1 - overflows.) */ - warned_range = pedwarn (loc, OPT_Wpedantic, - "enumerator value outside the range of %qs", + if (ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) + { + /* Enumeration constants must fit in the fixed underlying type. */ + if (!int_fits_type_p (value, ENUM_UNDERLYING_TYPE (the_enum->enum_type))) + error_at (loc, + "enumerator value outside the range of underlying type"); + /* Enumeration constants for an enum with fixed underlying type + have the enum type, both inside and outside the + definition. */ + value = convert (the_enum->enum_type, value); + } + else + { + /* Even though the underlying type of an enum is unspecified, the + type of enumeration constants is explicitly defined as int + (6.4.4.3/2 in the C99 Standard). C2X allows any integer type, and + GCC allows such types for older standards as an extension. */ + bool warned_range = false; + if (!int_fits_type_p (value, (TYPE_UNSIGNED (TREE_TYPE (value)) - ? "uintmax_t" - : "intmax_t")); - if (!warned_range && !int_fits_type_p (value, integer_type_node)) - pedwarn_c11 (loc, OPT_Wpedantic, - "ISO C restricts enumerator values to range of %<int%> " - "before C2X"); - - /* The ISO C Standard mandates enumerators to have type int before - C2X, even though the underlying type of an enum type is - unspecified. C2X allows enumerators of any integer type. During - the parsing of the enumeration, C2X specifies that constants - representable in int have type int, constants not representable - in int have the type of the given expression if any, and - constants not representable in int and derived by adding 1 to the - previous constant have the type of that constant unless the - addition would overflow or wraparound, in which case a wider type - of the same signedness is chosen automatically; after the - enumeration is parsed, all the constants have the type of the - enumeration if any do not fit in int. */ - if (int_fits_type_p (value, integer_type_node)) - value = convert (integer_type_node, value); + ? uintmax_type_node + : intmax_type_node))) + /* GCC does not consider its types larger than intmax_t to be + extended integer types (although C2X would permit such types to + be considered extended integer types if all the features + required by <stdint.h> and <inttypes.h> macros, such as support + for integer constants and I/O, were present), so diagnose if + such a wider type is used. (If the wider type arose from a + constant of such a type, that will also have been diagnosed, + but this is the only diagnostic in the case where it arises + from choosing a wider type automatically when adding 1 + overflows.) */ + warned_range = pedwarn (loc, OPT_Wpedantic, + "enumerator value outside the range of %qs", + (TYPE_UNSIGNED (TREE_TYPE (value)) + ? "uintmax_t" + : "intmax_t")); + if (!warned_range && !int_fits_type_p (value, integer_type_node)) + pedwarn_c11 (loc, OPT_Wpedantic, + "ISO C restricts enumerator values to range of %<int%> " + "before C2X"); + + /* The ISO C Standard mandates enumerators to have type int before + C2X, even though the underlying type of an enum type is + unspecified. C2X allows enumerators of any integer type. During + the parsing of the enumeration, C2X specifies that constants + representable in int have type int, constants not representable + in int have the type of the given expression if any, and + constants not representable in int and derived by adding 1 to the + previous constant have the type of that constant unless the + addition would overflow or wraparound, in which case a wider type + of the same signedness is chosen automatically; after the + enumeration is parsed, all the constants have the type of the + enumeration if any do not fit in int. */ + if (int_fits_type_p (value, integer_type_node)) + value = convert (integer_type_node, value); + } /* Set basis for default for next value. */ - the_enum->enum_next_value - = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), - PLUS_EXPR, value, integer_one_node, false); + if (ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) + { + tree underlying_type = ENUM_UNDERLYING_TYPE (the_enum->enum_type); + if (TREE_CODE (underlying_type) == BOOLEAN_TYPE) + /* A value of 2 following a value of 1 overflows bool, but we + cannot carry out addition directly on bool without + promotion, and converting the result of arithmetic in a + wider type back to bool would not produce the right result + for this overflow check. */ + the_enum->enum_next_value = invert_truthvalue_loc (loc, value); + else + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, convert (underlying_type, value), + convert (underlying_type, integer_one_node), + false); + } + else + the_enum->enum_next_value + = build_binary_op (EXPR_LOC_OR_LOC (value, input_location), + PLUS_EXPR, value, integer_one_node, false); the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value); - if (the_enum->enum_overflow) + if (the_enum->enum_overflow + && !ENUM_FIXED_UNDERLYING_TYPE_P (the_enum->enum_type)) { /* Choose a wider type with the same signedness if available. */ @@ -9691,7 +9810,8 @@ c_simulate_enum_decl (location_t loc, const char *name, input_location = loc; struct c_enum_contents the_enum; - tree enumtype = start_enum (loc, &the_enum, get_identifier (name)); + tree enumtype = start_enum (loc, &the_enum, get_identifier (name), + NULL_TREE); tree value_chain = NULL_TREE; string_int_pair *value; @@ -11980,6 +12100,9 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs, } } specs->type = type; + if (spec.has_enum_type_specifier + && spec.kind != ctsk_tagdef) + specs->enum_type_specifier_ref_p = true; } return specs; diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc index b468091..1a8b162 100644 --- a/gcc/c/c-objc-common.cc +++ b/gcc/c/c-objc-common.cc @@ -387,13 +387,7 @@ c_get_alias_set (tree t) /* Allow aliasing between enumeral types and the underlying integer type. This is required since those are compatible types. */ if (TREE_CODE (t) == ENUMERAL_TYPE) - { - tree t1 = c_common_type_for_size (tree_to_uhwi (TYPE_SIZE (t)), - /* short-cut commoning to signed - type. */ - false); - return get_alias_set (t1); - } + return get_alias_set (ENUM_UNDERLYING_TYPE (t)); return c_common_get_alias_set (t); } diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 602e023..5bdcd93 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -3011,6 +3011,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, } t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; declspecs_add_type (name_token->location, specs, t); continue; } @@ -3027,6 +3028,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto); t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; declspecs_add_type (loc, specs, t); continue; } @@ -3087,6 +3089,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t.spec = c_parser_peek_token (parser)->value; t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; declspecs_add_type (loc, specs, t); c_parser_consume_token (parser); break; @@ -3151,6 +3154,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, t.spec = error_mark_node; t.expr = NULL_TREE; t.expr_const_operands = true; + t.has_enum_type_specifier = false; if (type != NULL) t.spec = groktypename (type, &t.expr, &t.expr_const_operands); @@ -3218,17 +3222,20 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, /* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2). enum-specifier: - enum gnu-attributes[opt] identifier[opt] { enumerator-list } - gnu-attributes[opt] - enum gnu-attributes[opt] identifier[opt] { enumerator-list , } - gnu-attributes[opt] + enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt] + { enumerator-list } gnu-attributes[opt] + enum gnu-attributes[opt] identifier[opt] enum-type-specifier[opt] + { enumerator-list , } gnu-attributes[opt] enum-type-specifier[opt] enum gnu-attributes[opt] identifier - The form with trailing comma is new in C99. The forms with - gnu-attributes are GNU extensions. In GNU C, we accept any expression - without commas in the syntax (assignment expressions, not just - conditional expressions); assignment expressions will be diagnosed - as non-constant. + The form with trailing comma is new in C99; enum-type-specifiers + are new in C2x. The forms with gnu-attributes are GNU extensions. + In GNU C, we accept any expression without commas in the syntax + (assignment expressions, not just conditional expressions); + assignment expressions will be diagnosed as non-constant. + + enum-type-specifier: + : specifier-qualifier-list enumerator-list: enumerator @@ -3256,6 +3263,7 @@ c_parser_enum_specifier (c_parser *parser) tree std_attrs = NULL_TREE; tree attrs; tree ident = NULL_TREE; + tree fixed_underlying_type = NULL_TREE; location_t enum_loc; location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM)); @@ -3274,6 +3282,83 @@ c_parser_enum_specifier (c_parser *parser) enum_loc = ident_loc; c_parser_consume_token (parser); } + if (c_parser_next_token_is (parser, CPP_COLON) + /* Distinguish an enum-type-specifier from a bit-field + declaration of the form "enum e : constant-expression;". */ + && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + { + pedwarn_c11 (enum_loc, OPT_Wpedantic, + "ISO C does not support specifying %<enum%> underlying " + "types before C2X"); + if (ident) + { + /* The tag is in scope during the enum-type-specifier (which + may refer to the tag inside typeof). */ + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, + have_std_attrs, std_attrs, true); + if (!ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec)) + error_at (enum_loc, "%<enum%> declared both with and without " + "fixed underlying type"); + } + else + { + /* There must be an enum definition, so this initialization + (to avoid possible warnings about uninitialized data) + will be replaced later (either with the results of that + definition, or with the results of error handling for the + case of no tag and no definition). */ + ret.spec = NULL_TREE; + ret.kind = ctsk_tagdef; + ret.expr = NULL_TREE; + ret.expr_const_operands = true; + ret.has_enum_type_specifier = true; + } + c_parser_consume_token (parser); + struct c_declspecs *specs = build_null_declspecs (); + c_parser_declspecs (parser, specs, false, true, false, false, false, + false, true, cla_prefer_id); + finish_declspecs (specs); + if (specs->default_int_p) + error_at (enum_loc, "no %<enum%> underlying type specified"); + else if (TREE_CODE (specs->type) != INTEGER_TYPE + && TREE_CODE (specs->type) != BOOLEAN_TYPE) + { + error_at (enum_loc, "invalid %<enum%> underlying type"); + specs->type = integer_type_node; + } + else if (specs->restrict_p) + error_at (enum_loc, "invalid use of %<restrict%>"); + fixed_underlying_type = TYPE_MAIN_VARIANT (specs->type); + if (ident) + { + /* The type specified must be consistent with any previously + specified underlying type. If this is a newly declared + type, it is now a complete type. */ + if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) + && ENUM_UNDERLYING_TYPE (ret.spec) == NULL_TREE) + { + TYPE_MIN_VALUE (ret.spec) = + TYPE_MIN_VALUE (fixed_underlying_type); + TYPE_MAX_VALUE (ret.spec) = + TYPE_MAX_VALUE (fixed_underlying_type); + TYPE_UNSIGNED (ret.spec) = TYPE_UNSIGNED (fixed_underlying_type); + SET_TYPE_ALIGN (ret.spec, TYPE_ALIGN (fixed_underlying_type)); + TYPE_SIZE (ret.spec) = NULL_TREE; + TYPE_PRECISION (ret.spec) = + TYPE_PRECISION (fixed_underlying_type); + ENUM_UNDERLYING_TYPE (ret.spec) = fixed_underlying_type; + layout_type (ret.spec); + } + else if (ENUM_FIXED_UNDERLYING_TYPE_P (ret.spec) + && !comptypes (fixed_underlying_type, + ENUM_UNDERLYING_TYPE (ret.spec))) + { + error_at (enum_loc, "%<enum%> underlying type incompatible with " + "previous declaration"); + fixed_underlying_type = ENUM_UNDERLYING_TYPE (ret.spec); + } + } + } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { /* Parse an enum definition. */ @@ -3284,7 +3369,7 @@ c_parser_enum_specifier (c_parser *parser) forward order at the end. */ tree values; timevar_push (TV_PARSE_ENUM); - type = start_enum (enum_loc, &the_enum, ident); + type = start_enum (enum_loc, &the_enum, ident, fixed_underlying_type); values = NULL_TREE; c_parser_consume_token (parser); while (true) @@ -3368,6 +3453,7 @@ c_parser_enum_specifier (c_parser *parser) ret.kind = ctsk_tagdef; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = fixed_underlying_type != NULL_TREE; timevar_pop (TV_PARSE_ENUM); return ret; } @@ -3378,6 +3464,7 @@ c_parser_enum_specifier (c_parser *parser) ret.kind = ctsk_tagref; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; return ret; } /* Attributes may only appear when the members are defined or in @@ -3386,15 +3473,18 @@ c_parser_enum_specifier (c_parser *parser) standard C). */ if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON)) c_parser_error (parser, "expected %<;%>"); - ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, - std_attrs); - /* In ISO C, enumerated types can be referred to only if already - defined. */ - if (pedantic && !COMPLETE_TYPE_P (ret.spec)) + if (fixed_underlying_type == NULL_TREE) { - gcc_assert (ident); - pedwarn (enum_loc, OPT_Wpedantic, - "ISO C forbids forward references to %<enum%> types"); + ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs, + std_attrs, false); + /* In ISO C, enumerated types without a fixed underlying type + can be referred to only if already defined. */ + if (pedantic && !COMPLETE_TYPE_P (ret.spec)) + { + gcc_assert (ident); + pedwarn (enum_loc, OPT_Wpedantic, + "ISO C forbids forward references to %<enum%> types"); + } } return ret; } @@ -3590,6 +3680,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.kind = ctsk_tagdef; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; timevar_pop (TV_PARSE_STRUCT); return ret; } @@ -3600,6 +3691,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) ret.kind = ctsk_tagref; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; return ret; } /* Attributes may only appear when the members are defined or in @@ -3608,7 +3700,8 @@ c_parser_struct_or_union_specifier (c_parser *parser) c_parser_error (parser, "expected %<;%>"); /* ??? Existing practice is that GNU attributes are ignored after the struct or union keyword when not defining the members. */ - ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs); + ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs, + false); return ret; } @@ -3817,6 +3910,7 @@ c_parser_typeof_specifier (c_parser *parser) ret.spec = error_mark_node; ret.expr = NULL_TREE; ret.expr_const_operands = true; + ret.has_enum_type_specifier = false; if (c_parser_next_token_is_keyword (parser, RID_TYPEOF)) { is_unqual = false; @@ -19153,15 +19247,14 @@ restart: && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND - (TREE_OPERAND (lhs, 1), 0), 0))) - == BOOLEAN_TYPE) + && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND + (TREE_OPERAND (lhs, 1), 0), 0)))) /* Undo effects of boolean_increment for post {in,de}crement. */ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0); /* FALLTHRU */ case MODIFY_EXPR: if (TREE_CODE (lhs) == MODIFY_EXPR - && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE) + && C_BOOLEAN_TYPE_P (TREE_TYPE (TREE_OPERAND (lhs, 0)))) { /* Undo effects of boolean_increment. */ if (integer_onep (TREE_OPERAND (lhs, 1))) diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index e7cdd2f..d787dd4 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -122,6 +122,14 @@ along with GCC; see the file COPYING3. If not see been folded. */ #define SAVE_EXPR_FOLDED_P(EXP) TREE_LANG_FLAG_1 (SAVE_EXPR_CHECK (EXP)) +/* Whether a type has boolean semantics: either a boolean type or an + enumeration type with a boolean type as its underlying type. */ +#define C_BOOLEAN_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == BOOLEAN_TYPE \ + || (TREE_CODE (TYPE) == ENUMERAL_TYPE \ + && ENUM_UNDERLYING_TYPE (TYPE) != NULL_TREE \ + && TREE_CODE (ENUM_UNDERLYING_TYPE (TYPE)) == BOOLEAN_TYPE)) + /* Record parser information about an expression that is irrelevant for code generation alongside a tree representing its value. */ struct c_expr @@ -216,6 +224,10 @@ struct c_typespec { /* Whether the expression has operands suitable for use in constant expressions. */ bool expr_const_operands; + /* Whether the type specifier includes an enum type specifier (that + is, ": specifier-qualifier-list" in a declaration using + "enum"). */ + bool has_enum_type_specifier; /* The specifier itself. */ tree spec; /* An expression to be evaluated before the type specifier, in the @@ -412,6 +424,12 @@ struct c_declspecs { /* Whether any alignment specifier (even with zero alignment) was specified. */ BOOL_BITFIELD alignas_p : 1; + /* Whether an enum type specifier (": specifier-qualifier-list") was + specified other than in a definition of that enum (if so, this is + invalid unless it is an empty declaration "enum identifier + enum-type-specifier;", but such an empty declaration is valid in + C2x when "enum identifier;" would not be). */ + BOOL_BITFIELD enum_type_specifier_ref_p : 1; /* The address space that the declaration belongs to. */ addr_space_t address_space; }; @@ -525,6 +543,9 @@ struct c_enum_contents constant value. */ tree enum_next_value; + /* The enumeration type itself. */ + tree enum_type; + /* Nonzero means that there was overflow computing enum_next_value. */ int enum_overflow; }; @@ -625,7 +646,7 @@ extern void c_warn_unused_attributes (tree); extern tree c_warn_type_attributes (tree); extern void shadow_tag (const struct c_declspecs *); extern void shadow_tag_warned (const struct c_declspecs *, int); -extern tree start_enum (location_t, struct c_enum_contents *, tree); +extern tree start_enum (location_t, struct c_enum_contents *, tree, tree); extern bool start_function (struct c_declspecs *, struct c_declarator *, tree); extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool, tree, location_t * = NULL); @@ -637,7 +658,7 @@ extern void temp_store_parm_decls (tree, tree); extern void temp_pop_parm_decls (void); extern tree xref_tag (enum tree_code, tree); extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree, - bool, tree); + bool, tree, bool); extern struct c_parm *build_c_parm (struct c_declspecs *, tree, struct c_declarator *, location_t); extern struct c_declarator *build_attrs_declarator (tree, diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 92f3afc..6c16647 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -420,9 +420,11 @@ composite_type (tree t1, tree t2) (DR#013 question 3). For consistency, use the enumerated type as the composite type. */ - if (code1 == ENUMERAL_TYPE && code2 == INTEGER_TYPE) + if (code1 == ENUMERAL_TYPE + && (code2 == INTEGER_TYPE || code2 == BOOLEAN_TYPE)) return t1; - if (code2 == ENUMERAL_TYPE && code1 == INTEGER_TYPE) + if (code2 == ENUMERAL_TYPE + && (code1 == INTEGER_TYPE || code1 == BOOLEAN_TYPE)) return t2; gcc_assert (code1 == code2); @@ -1025,9 +1027,9 @@ tree common_type (tree t1, tree t2) { if (TREE_CODE (t1) == ENUMERAL_TYPE) - t1 = c_common_type_for_size (TYPE_PRECISION (t1), 1); + t1 = ENUM_UNDERLYING_TYPE (t1); if (TREE_CODE (t2) == ENUMERAL_TYPE) - t2 = c_common_type_for_size (TYPE_PRECISION (t2), 1); + t2 = ENUM_UNDERLYING_TYPE (t2); /* If both types are BOOLEAN_TYPE, then return boolean_type_node. */ if (TREE_CODE (t1) == BOOLEAN_TYPE @@ -1125,7 +1127,7 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, && COMPLETE_TYPE_P (t1) && TREE_CODE (t2) != ENUMERAL_TYPE) { - t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1)); + t1 = ENUM_UNDERLYING_TYPE (t1); if (TREE_CODE (t2) != VOID_TYPE) { if (enum_and_int_p != NULL) @@ -1138,7 +1140,7 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p, && COMPLETE_TYPE_P (t2) && TREE_CODE (t1) != ENUMERAL_TYPE) { - t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2)); + t2 = ENUM_UNDERLYING_TYPE (t2); if (TREE_CODE (t1) != VOID_TYPE) { if (enum_and_int_p != NULL) @@ -2193,15 +2195,19 @@ perform_integral_promotions (tree exp) gcc_assert (INTEGRAL_TYPE_P (type)); - /* Normally convert enums to int, - but convert wide enums to something wider. */ + /* Convert enums to the result of applying the integer promotions to + their underlying type. */ if (code == ENUMERAL_TYPE) { - type = c_common_type_for_size (MAX (TYPE_PRECISION (type), - TYPE_PRECISION (integer_type_node)), - ((TYPE_PRECISION (type) - >= TYPE_PRECISION (integer_type_node)) - && TYPE_UNSIGNED (type))); + type = ENUM_UNDERLYING_TYPE (type); + if (c_promoting_integer_type_p (type)) + { + if (TYPE_UNSIGNED (type) + && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) + type = unsigned_type_node; + else + type = integer_type_node; + } return convert (type, exp); } @@ -3932,7 +3938,7 @@ parser_build_binary_op (location_t location, enum tree_code code, } while (1); } - if (TREE_CODE (TREE_TYPE (t)) != BOOLEAN_TYPE) + if (!C_BOOLEAN_TYPE_P (TREE_TYPE (t))) warn_logical_not_parentheses (location, code, arg1.value, arg2.value); } @@ -4537,7 +4543,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, while (TREE_CODE (e) == COMPOUND_EXPR) e = TREE_OPERAND (e, 1); - if ((TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (TREE_TYPE (arg)) || truth_value_p (TREE_CODE (e)))) { auto_diagnostic_group d; @@ -4669,7 +4675,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, "decrement of enumeration value is invalid in C++"); } - if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) { if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR) warning_at (location, OPT_Wbool_operation, @@ -4831,7 +4837,7 @@ build_unary_op (location_t location, enum tree_code code, tree xarg, goto return_build_unary_op; } - if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) + if (C_BOOLEAN_TYPE_P (TREE_TYPE (arg))) val = boolean_increment (code, arg); else val = build2 (code, TREE_TYPE (arg), arg, inc); @@ -7087,7 +7093,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, rhstype); bool save = in_late_binary_op; - if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE + if (C_BOOLEAN_TYPE_P (type) || codel == COMPLEX_TYPE || (coder == REAL_TYPE && (codel == INTEGER_TYPE || codel == ENUMERAL_TYPE) && sanitize_flags_p (SANITIZE_FLOAT_CAST))) @@ -7734,7 +7740,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, return convert (type, rhs); } - else if (codel == BOOLEAN_TYPE + else if (C_BOOLEAN_TYPE_P (type) /* The type nullptr_t may be converted to bool. The result is false. */ && (coder == POINTER_TYPE || coder == NULLPTR_TYPE)) @@ -11002,7 +11008,7 @@ c_finish_return (location_t loc, tree retval, tree origtype) return NULL_TREE; save = in_late_binary_op; - if (TREE_CODE (TREE_TYPE (res)) == BOOLEAN_TYPE + if (C_BOOLEAN_TYPE_P (TREE_TYPE (res)) || TREE_CODE (TREE_TYPE (res)) == COMPLEX_TYPE || (TREE_CODE (TREE_TYPE (t)) == REAL_TYPE && (TREE_CODE (TREE_TYPE (res)) == INTEGER_TYPE @@ -11164,7 +11170,7 @@ c_start_switch (location_t switch_loc, while (TREE_CODE (e) == COMPOUND_EXPR) e = TREE_OPERAND (e, 1); - if ((TREE_CODE (type) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (type) || truth_value_p (TREE_CODE (e))) /* Explicit cast to int suppresses this warning. */ && !(TREE_CODE (type) == INTEGER_TYPE @@ -12493,9 +12499,9 @@ build_binary_op (location_t location, enum tree_code code, else if (code1 == NULLPTR_TYPE && null_pointer_constant_p (orig_op0)) result_type = (INTEGRAL_TYPE_P (type0) ? build_pointer_type (type0) : type0); - if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op0)) || truth_value_p (TREE_CODE (orig_op0))) - ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE + ^ (C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op1)) || truth_value_p (TREE_CODE (orig_op1)))) maybe_warn_bool_compare (location, code, orig_op0, orig_op1); break; @@ -12638,9 +12644,9 @@ build_binary_op (location_t location, enum tree_code code, instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1); } - if ((TREE_CODE (TREE_TYPE (orig_op0)) == BOOLEAN_TYPE + if ((C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op0)) || truth_value_p (TREE_CODE (orig_op0))) - ^ (TREE_CODE (TREE_TYPE (orig_op1)) == BOOLEAN_TYPE + ^ (C_BOOLEAN_TYPE_P (TREE_TYPE (orig_op1)) || truth_value_p (TREE_CODE (orig_op1)))) maybe_warn_bool_compare (location, code, orig_op0, orig_op1); break; diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc index bd356ce..d6404a0 100644 --- a/gcc/common/config/riscv/riscv-common.cc +++ b/gcc/common/config/riscv/riscv-common.cc @@ -51,6 +51,11 @@ static const riscv_implied_info_t riscv_implied_info[] = {"d", "f"}, {"f", "zicsr"}, {"d", "zicsr"}, + + {"zdinx", "zfinx"}, + {"zfinx", "zicsr"}, + {"zdinx", "zicsr"}, + {"zk", "zkn"}, {"zk", "zkr"}, {"zk", "zkt"}, @@ -99,6 +104,9 @@ static const riscv_implied_info_t riscv_implied_info[] = {"zfh", "zfhmin"}, {"zfhmin", "f"}, + + {"zhinx", "zhinxmin"}, + {"zhinxmin", "zfinx"}, {NULL, NULL} }; @@ -160,6 +168,11 @@ static const struct riscv_ext_version riscv_ext_version_table[] = {"zbc", ISA_SPEC_CLASS_NONE, 1, 0}, {"zbs", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zfinx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zdinx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zhinx", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zhinxmin", ISA_SPEC_CLASS_NONE, 1, 0}, + {"zbkb", ISA_SPEC_CLASS_NONE, 1, 0}, {"zbkc", ISA_SPEC_CLASS_NONE, 1, 0}, {"zbkx", ISA_SPEC_CLASS_NONE, 1, 0}, @@ -1172,6 +1185,11 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] = {"zbc", &gcc_options::x_riscv_zb_subext, MASK_ZBC}, {"zbs", &gcc_options::x_riscv_zb_subext, MASK_ZBS}, + {"zfinx", &gcc_options::x_riscv_zinx_subext, MASK_ZFINX}, + {"zdinx", &gcc_options::x_riscv_zinx_subext, MASK_ZDINX}, + {"zhinx", &gcc_options::x_riscv_zinx_subext, MASK_ZHINX}, + {"zhinxmin", &gcc_options::x_riscv_zinx_subext, MASK_ZHINXMIN}, + {"zbkb", &gcc_options::x_riscv_zk_subext, MASK_ZBKB}, {"zbkc", &gcc_options::x_riscv_zk_subext, MASK_ZBKC}, {"zbkx", &gcc_options::x_riscv_zk_subext, MASK_ZBKX}, diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 1a71f02..2388205 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -254,7 +254,7 @@ typedef struct simd_vec_cost advsimd_vec_cost; /* SVE-specific extensions to the information provided by simd_vec_cost. */ struct sve_vec_cost : simd_vec_cost { - constexpr sve_vec_cost (const simd_vec_cost &base, + CONSTEXPR sve_vec_cost (const simd_vec_cost &base, unsigned int clast_cost, unsigned int fadda_f16_cost, unsigned int fadda_f32_cost, @@ -354,7 +354,7 @@ using aarch64_scalar_vec_issue_info = aarch64_base_vec_issue_info; Advanced SIMD and SVE. */ struct aarch64_simd_vec_issue_info : aarch64_base_vec_issue_info { - constexpr aarch64_simd_vec_issue_info (aarch64_base_vec_issue_info base, + CONSTEXPR aarch64_simd_vec_issue_info (aarch64_base_vec_issue_info base, unsigned int ld2_st2_general_ops, unsigned int ld3_st3_general_ops, unsigned int ld4_st4_general_ops) @@ -382,7 +382,7 @@ using aarch64_advsimd_vec_issue_info = aarch64_simd_vec_issue_info; is a concept of "predicate operations". */ struct aarch64_sve_vec_issue_info : aarch64_simd_vec_issue_info { - constexpr aarch64_sve_vec_issue_info + CONSTEXPR aarch64_sve_vec_issue_info (aarch64_simd_vec_issue_info base, unsigned int pred_ops_per_cycle, unsigned int while_pred_ops, diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc index 23b4d42..6347407 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc @@ -177,7 +177,7 @@ public: class svac_impl : public function_base { public: - constexpr svac_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svac_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -209,7 +209,7 @@ public: class svadr_bhwd_impl : public function_base { public: - constexpr svadr_bhwd_impl (unsigned int shift) : m_shift (shift) {} + CONSTEXPR svadr_bhwd_impl (unsigned int shift) : m_shift (shift) {} rtx expand (function_expander &e) const override @@ -259,7 +259,7 @@ public: class svbrk_binary_impl : public function_base { public: - constexpr svbrk_binary_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svbrk_binary_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -275,7 +275,7 @@ public: class svbrk_unary_impl : public function_base { public: - constexpr svbrk_unary_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svbrk_unary_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -309,7 +309,7 @@ public: class svclast_impl : public quiet<function_base> { public: - constexpr svclast_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svclast_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -381,7 +381,7 @@ public: class svcmp_impl : public function_base { public: - constexpr svcmp_impl (tree_code code, int unspec_for_fp) + CONSTEXPR svcmp_impl (tree_code code, int unspec_for_fp) : m_code (code), m_unspec_for_fp (unspec_for_fp) {} gimple * @@ -437,7 +437,7 @@ public: class svcmp_wide_impl : public function_base { public: - constexpr svcmp_wide_impl (tree_code code, int unspec_for_sint, + CONSTEXPR svcmp_wide_impl (tree_code code, int unspec_for_sint, int unspec_for_uint) : m_code (code), m_unspec_for_sint (unspec_for_sint), m_unspec_for_uint (unspec_for_uint) {} @@ -512,7 +512,7 @@ public: class svcnt_bhwd_impl : public function_base { public: - constexpr svcnt_bhwd_impl (machine_mode ref_mode) : m_ref_mode (ref_mode) {} + CONSTEXPR svcnt_bhwd_impl (machine_mode ref_mode) : m_ref_mode (ref_mode) {} gimple * fold (gimple_folder &f) const override @@ -949,7 +949,7 @@ public: class svext_bhw_impl : public function_base { public: - constexpr svext_bhw_impl (scalar_int_mode from_mode) + CONSTEXPR svext_bhw_impl (scalar_int_mode from_mode) : m_from_mode (from_mode) {} rtx @@ -1053,7 +1053,7 @@ public: class svlast_impl : public quiet<function_base> { public: - constexpr svlast_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svlast_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -1399,7 +1399,7 @@ public: class svldxf1_impl : public full_width_access { public: - constexpr svldxf1_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svldxf1_impl (int unspec) : m_unspec (unspec) {} unsigned int call_properties (const function_instance &) const override @@ -1426,7 +1426,7 @@ public: class svldxf1_extend_impl : public extending_load { public: - constexpr svldxf1_extend_impl (type_suffix_index memory_type, int unspec) + CONSTEXPR svldxf1_extend_impl (type_suffix_index memory_type, int unspec) : extending_load (memory_type), m_unspec (unspec) {} unsigned int @@ -1616,7 +1616,7 @@ public: class svnot_impl : public rtx_code_function { public: - constexpr svnot_impl () : rtx_code_function (NOT, NOT, -1) {} + CONSTEXPR svnot_impl () : rtx_code_function (NOT, NOT, -1) {} rtx expand (function_expander &e) const override @@ -1664,7 +1664,7 @@ public: class svpfirst_svpnext_impl : public function_base { public: - constexpr svpfirst_svpnext_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svpfirst_svpnext_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -1682,7 +1682,7 @@ public: class svprf_bhwd_impl : public function_base { public: - constexpr svprf_bhwd_impl (machine_mode mode) : m_mode (mode) {} + CONSTEXPR svprf_bhwd_impl (machine_mode mode) : m_mode (mode) {} unsigned int call_properties (const function_instance &) const override @@ -1706,7 +1706,7 @@ public: class svprf_bhwd_gather_impl : public function_base { public: - constexpr svprf_bhwd_gather_impl (machine_mode mode) : m_mode (mode) {} + CONSTEXPR svprf_bhwd_gather_impl (machine_mode mode) : m_mode (mode) {} unsigned int call_properties (const function_instance &) const override @@ -1744,7 +1744,7 @@ public: class svptest_impl : public function_base { public: - constexpr svptest_impl (rtx_code compare) : m_compare (compare) {} + CONSTEXPR svptest_impl (rtx_code compare) : m_compare (compare) {} rtx expand (function_expander &e) const override @@ -1849,7 +1849,7 @@ public: class svqdec_svqinc_bhwd_impl : public function_base { public: - constexpr svqdec_svqinc_bhwd_impl (rtx_code code_for_sint, + CONSTEXPR svqdec_svqinc_bhwd_impl (rtx_code code_for_sint, rtx_code code_for_uint, scalar_int_mode elem_mode) : m_code_for_sint (code_for_sint), @@ -1896,7 +1896,7 @@ public: class svqdec_bhwd_impl : public svqdec_svqinc_bhwd_impl { public: - constexpr svqdec_bhwd_impl (scalar_int_mode elem_mode) + CONSTEXPR svqdec_bhwd_impl (scalar_int_mode elem_mode) : svqdec_svqinc_bhwd_impl (SS_MINUS, US_MINUS, elem_mode) {} }; @@ -1904,7 +1904,7 @@ public: class svqinc_bhwd_impl : public svqdec_svqinc_bhwd_impl { public: - constexpr svqinc_bhwd_impl (scalar_int_mode elem_mode) + CONSTEXPR svqinc_bhwd_impl (scalar_int_mode elem_mode) : svqdec_svqinc_bhwd_impl (SS_PLUS, US_PLUS, elem_mode) {} }; @@ -1912,7 +1912,7 @@ public: class svqdecp_svqincp_impl : public function_base { public: - constexpr svqdecp_svqincp_impl (rtx_code code_for_sint, + CONSTEXPR svqdecp_svqincp_impl (rtx_code code_for_sint, rtx_code code_for_uint) : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint) @@ -2275,7 +2275,7 @@ public: class svsub_impl : public rtx_code_function { public: - constexpr svsub_impl () + CONSTEXPR svsub_impl () : rtx_code_function (MINUS, MINUS, UNSPEC_COND_FSUB) {} rtx @@ -2304,7 +2304,7 @@ public: class svtrn_impl : public binary_permute { public: - constexpr svtrn_impl (int base) + CONSTEXPR svtrn_impl (int base) : binary_permute (base ? UNSPEC_TRN2 : UNSPEC_TRN1), m_base (base) {} gimple * @@ -2345,7 +2345,7 @@ public: class svunpk_impl : public quiet<function_base> { public: - constexpr svunpk_impl (bool high_p) : m_high_p (high_p) {} + CONSTEXPR svunpk_impl (bool high_p) : m_high_p (high_p) {} gimple * fold (gimple_folder &f) const override @@ -2387,7 +2387,7 @@ public: class svusdot_impl : public function_base { public: - constexpr svusdot_impl (bool su) : m_su (su) {} + CONSTEXPR svusdot_impl (bool su) : m_su (su) {} rtx expand (function_expander &e) const override @@ -2415,7 +2415,7 @@ private: class svuzp_impl : public binary_permute { public: - constexpr svuzp_impl (unsigned int base) + CONSTEXPR svuzp_impl (unsigned int base) : binary_permute (base ? UNSPEC_UZP2 : UNSPEC_UZP1), m_base (base) {} gimple * @@ -2438,7 +2438,7 @@ public: class svwhilelx_impl : public while_comparison { public: - constexpr svwhilelx_impl (int unspec_for_sint, int unspec_for_uint, bool eq_p) + CONSTEXPR svwhilelx_impl (int unspec_for_sint, int unspec_for_uint, bool eq_p) : while_comparison (unspec_for_sint, unspec_for_uint), m_eq_p (eq_p) {} @@ -2525,7 +2525,7 @@ public: class svzip_impl : public binary_permute { public: - constexpr svzip_impl (unsigned int base) + CONSTEXPR svzip_impl (unsigned int base) : binary_permute (base ? UNSPEC_ZIP2 : UNSPEC_ZIP1), m_base (base) {} gimple * diff --git a/gcc/config/aarch64/aarch64-sve-builtins-functions.h b/gcc/config/aarch64/aarch64-sve-builtins-functions.h index ec943c5..472e26c 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-functions.h +++ b/gcc/config/aarch64/aarch64-sve-builtins-functions.h @@ -44,7 +44,7 @@ public: class multi_vector_function : public function_base { public: - constexpr multi_vector_function (unsigned int vectors_per_tuple) + CONSTEXPR multi_vector_function (unsigned int vectors_per_tuple) : m_vectors_per_tuple (vectors_per_tuple) {} unsigned int @@ -63,7 +63,7 @@ public: class full_width_access : public multi_vector_function { public: - constexpr full_width_access (unsigned int vectors_per_tuple = 1) + CONSTEXPR full_width_access (unsigned int vectors_per_tuple = 1) : multi_vector_function (vectors_per_tuple) {} tree @@ -88,7 +88,7 @@ public: class extending_load : public function_base { public: - constexpr extending_load (type_suffix_index memory_type) + CONSTEXPR extending_load (type_suffix_index memory_type) : m_memory_type (memory_type) {} unsigned int @@ -131,7 +131,7 @@ public: class truncating_store : public function_base { public: - constexpr truncating_store (scalar_int_mode to_mode) : m_to_mode (to_mode) {} + CONSTEXPR truncating_store (scalar_int_mode to_mode) : m_to_mode (to_mode) {} unsigned int call_properties (const function_instance &) const override @@ -168,7 +168,7 @@ public: class rtx_code_function_base : public function_base { public: - constexpr rtx_code_function_base (rtx_code code_for_sint, + CONSTEXPR rtx_code_function_base (rtx_code code_for_sint, rtx_code code_for_uint, int unspec_for_fp = -1) : m_code_for_sint (code_for_sint), m_code_for_uint (code_for_uint), @@ -227,7 +227,7 @@ public: class unspec_based_function_base : public function_base { public: - constexpr unspec_based_function_base (int unspec_for_sint, + CONSTEXPR unspec_based_function_base (int unspec_for_sint, int unspec_for_uint, int unspec_for_fp) : m_unspec_for_sint (unspec_for_sint), @@ -434,7 +434,7 @@ public: class fixed_insn_function : public function_base { public: - constexpr fixed_insn_function (insn_code code) : m_code (code) {} + CONSTEXPR fixed_insn_function (insn_code code) : m_code (code) {} rtx expand (function_expander &e) const override @@ -476,7 +476,7 @@ public: class binary_permute : public permute { public: - constexpr binary_permute (int unspec) : m_unspec (unspec) {} + CONSTEXPR binary_permute (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -493,13 +493,13 @@ public: class reduction : public function_base { public: - constexpr reduction (int unspec) + CONSTEXPR reduction (int unspec) : m_unspec_for_sint (unspec), m_unspec_for_uint (unspec), m_unspec_for_fp (unspec) {} - constexpr reduction (int unspec_for_sint, int unspec_for_uint, + CONSTEXPR reduction (int unspec_for_sint, int unspec_for_uint, int unspec_for_fp) : m_unspec_for_sint (unspec_for_sint), m_unspec_for_uint (unspec_for_uint), @@ -532,7 +532,7 @@ public: class shift_wide : public function_base { public: - constexpr shift_wide (rtx_code code, int wide_unspec) + CONSTEXPR shift_wide (rtx_code code, int wide_unspec) : m_code (code), m_wide_unspec (wide_unspec) {} rtx @@ -567,7 +567,7 @@ public: class unary_count : public quiet<function_base> { public: - constexpr unary_count (rtx_code code) : m_code (code) {} + CONSTEXPR unary_count (rtx_code code) : m_code (code) {} rtx expand (function_expander &e) const override @@ -590,7 +590,7 @@ public: class while_comparison : public function_base { public: - constexpr while_comparison (int unspec_for_sint, int unspec_for_uint) + CONSTEXPR while_comparison (int unspec_for_sint, int unspec_for_uint) : m_unspec_for_sint (unspec_for_sint), m_unspec_for_uint (unspec_for_uint) {} @@ -619,7 +619,7 @@ public: /* Declare the global function base NAME, creating it from an instance of class CLASS with constructor arguments ARGS. */ #define FUNCTION(NAME, CLASS, ARGS) \ - namespace { static constexpr const CLASS NAME##_obj ARGS; } \ + namespace { static CONSTEXPR const CLASS NAME##_obj ARGS; } \ namespace functions { const function_base *const NAME = &NAME##_obj; } #endif diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc index bf1d05e..8e26bd8 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc @@ -447,7 +447,7 @@ long_type_suffix (function_resolver &r, type_suffix_index type) /* Declare the function shape NAME, pointing it to an instance of class <NAME>_def. */ #define SHAPE(NAME) \ - static constexpr const NAME##_def NAME##_obj; \ + static CONSTEXPR const NAME##_def NAME##_obj; \ namespace shapes { const function_shape *const NAME = &NAME##_obj; } /* Base class for functions that are not overloaded. */ @@ -587,7 +587,7 @@ struct binary_imm_long_base : public overloaded_base<0> /* Base class for inc_dec and inc_dec_pat. */ struct inc_dec_base : public overloaded_base<0> { - constexpr inc_dec_base (bool pat_p) : m_pat_p (pat_p) {} + CONSTEXPR inc_dec_base (bool pat_p) : m_pat_p (pat_p) {} /* Resolve based on the first argument only, which must be either a scalar or a vector. If it's a scalar, it must be a 32-bit or @@ -1924,7 +1924,7 @@ SHAPE (get) whose size is tied to the [bhwd] suffix of "svfoo". */ struct inc_dec_def : public inc_dec_base { - constexpr inc_dec_def () : inc_dec_base (false) {} + CONSTEXPR inc_dec_def () : inc_dec_base (false) {} void build (function_builder &b, const function_group_info &group) const override @@ -1949,7 +1949,7 @@ SHAPE (inc_dec) whose size is tied to the [bhwd] suffix of "svfoo". */ struct inc_dec_pat_def : public inc_dec_base { - constexpr inc_dec_pat_def () : inc_dec_base (true) {} + CONSTEXPR inc_dec_pat_def () : inc_dec_base (true) {} void build (function_builder &b, const function_group_info &group) const override diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc index ca8f20d..a7d7435 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc @@ -158,7 +158,7 @@ public: class svmatch_svnmatch_impl : public function_base { public: - constexpr svmatch_svnmatch_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svmatch_svnmatch_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override @@ -233,7 +233,7 @@ public: class svqrshl_impl : public unspec_based_function { public: - constexpr svqrshl_impl () + CONSTEXPR svqrshl_impl () : unspec_based_function (UNSPEC_SQRSHL, UNSPEC_UQRSHL, -1) {} gimple * @@ -267,7 +267,7 @@ public: class svqshl_impl : public unspec_based_function { public: - constexpr svqshl_impl () + CONSTEXPR svqshl_impl () : unspec_based_function (UNSPEC_SQSHL, UNSPEC_UQSHL, -1) {} gimple * @@ -303,7 +303,7 @@ public: class svrshl_impl : public unspec_based_function { public: - constexpr svrshl_impl () + CONSTEXPR svrshl_impl () : unspec_based_function (UNSPEC_SRSHL, UNSPEC_URSHL, -1) {} gimple * @@ -403,7 +403,7 @@ public: class svtbl2_impl : public quiet<multi_vector_function> { public: - constexpr svtbl2_impl () : quiet<multi_vector_function> (2) {} + CONSTEXPR svtbl2_impl () : quiet<multi_vector_function> (2) {} rtx expand (function_expander &e) const override @@ -431,7 +431,7 @@ public: class svwhilerw_svwhilewr_impl : public full_width_access { public: - constexpr svwhilerw_svwhilewr_impl (int unspec) : m_unspec (unspec) {} + CONSTEXPR svwhilerw_svwhilewr_impl (int unspec) : m_unspec (unspec) {} rtx expand (function_expander &e) const override diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index 37228f6..e168c83 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -99,7 +99,7 @@ struct registered_function_hasher : nofree_ptr_hash <registered_function> }; /* Information about each single-predicate or single-vector type. */ -static constexpr const vector_type_info vector_types[] = { +static CONSTEXPR const vector_type_info vector_types[] = { #define DEF_SVE_TYPE(ACLE_NAME, NCHARS, ABI_NAME, SCALAR_TYPE) \ { #ACLE_NAME, #ABI_NAME, "u" #NCHARS #ABI_NAME }, #include "aarch64-sve-builtins.def" @@ -116,7 +116,7 @@ static const char *const pred_suffixes[NUM_PREDS + 1] = { }; /* Static information about each mode_suffix_index. */ -constexpr const mode_suffix_info mode_suffixes[] = { +CONSTEXPR const mode_suffix_info mode_suffixes[] = { #define VECTOR_TYPE_none NUM_VECTOR_TYPES #define DEF_SVE_MODE(NAME, BASE, DISPLACEMENT, UNITS) \ { "_" #NAME, VECTOR_TYPE_##BASE, VECTOR_TYPE_##DISPLACEMENT, UNITS_##UNITS }, @@ -126,7 +126,7 @@ constexpr const mode_suffix_info mode_suffixes[] = { }; /* Static information about each type_suffix_index. */ -constexpr const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { +CONSTEXPR const type_suffix_info type_suffixes[NUM_TYPE_SUFFIXES + 1] = { #define DEF_SVE_TYPE_SUFFIX(NAME, ACLE_TYPE, CLASS, BITS, MODE) \ { "_" #NAME, \ VECTOR_TYPE_##ACLE_TYPE, \ @@ -522,7 +522,7 @@ static const predication_index preds_z_or_none[] = { static const predication_index preds_z[] = { PRED_z, NUM_PREDS }; /* A list of all SVE ACLE functions. */ -static constexpr const function_group_info function_groups[] = { +static CONSTEXPR const function_group_info function_groups[] = { #define DEF_SVE_FUNCTION(NAME, SHAPE, TYPES, PREDS) \ { #NAME, &functions::NAME, &shapes::SHAPE, types_##TYPES, preds_##PREDS, \ REQUIRED_EXTENSIONS | AARCH64_FL_SVE }, diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 5d1ab5a..0458c65 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -2679,7 +2679,7 @@ struct processor }; /* Architectures implementing AArch64. */ -static constexpr processor all_architectures[] = +static CONSTEXPR const processor all_architectures[] = { #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, D, E) \ {NAME, CORE, CORE, AARCH64_ARCH_##ARCH_IDENT, \ diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 05da9af..e60f9bc 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -571,10 +571,6 @@ enum class aarch64_feature : unsigned char { #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, R4_REGNUM) #define EH_RETURN_HANDLER_RTX aarch64_eh_return_handler_rtx () -/* Don't use __builtin_setjmp until we've defined it. */ -#undef DONT_USE_BUILTIN_SETJMP -#define DONT_USE_BUILTIN_SETJMP 1 - #undef TARGET_COMPUTE_FRAME_LAYOUT #define TARGET_COMPUTE_FRAME_LAYOUT aarch64_layout_frame diff --git a/gcc/config/aarch64/driver-aarch64.cc b/gcc/config/aarch64/driver-aarch64.cc index 2ae47c0..a1d412c 100644 --- a/gcc/config/aarch64/driver-aarch64.cc +++ b/gcc/config/aarch64/driver-aarch64.cc @@ -64,7 +64,7 @@ struct aarch64_core_data #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \ { CORE_NAME, #ARCH, IMP, PART, VARIANT, feature_deps::cpu_##CORE_IDENT }, -static constexpr aarch64_core_data aarch64_cpu_data[] = +static CONSTEXPR const aarch64_core_data aarch64_cpu_data[] = { #include "aarch64-cores.def" { NULL, NULL, INVALID_IMP, INVALID_CORE, ALL_VARIANTS, 0 } @@ -82,7 +82,7 @@ struct aarch64_arch_driver_info #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \ { #ARCH_IDENT + 1, NAME, feature_deps::ARCH_IDENT ().enable }, -static constexpr aarch64_arch_driver_info aarch64_arches[] = +static CONSTEXPR const aarch64_arch_driver_info aarch64_arches[] = { #include "aarch64-arches.def" {NULL, NULL, 0} diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc index 5105565..ea8ca64 100644 --- a/gcc/config/bpf/bpf.cc +++ b/gcc/config/bpf/bpf.cc @@ -184,13 +184,13 @@ enum bpf_builtins /* Compile Once - Run Everywhere (CO-RE) support. */ BPF_BUILTIN_PRESERVE_ACCESS_INDEX, + BPF_BUILTIN_PRESERVE_FIELD_INFO, BPF_BUILTIN_MAX, }; static GTY (()) tree bpf_builtins[(int) BPF_BUILTIN_MAX]; - void bpf_register_coreattr_pass (void); /* Initialize the per-function machine status. */ @@ -966,6 +966,9 @@ bpf_init_builtins (void) def_builtin ("__builtin_preserve_access_index", BPF_BUILTIN_PRESERVE_ACCESS_INDEX, build_function_type_list (ptr_type_node, ptr_type_node, 0)); + def_builtin ("__builtin_preserve_field_info", + BPF_BUILTIN_PRESERVE_FIELD_INFO, + build_function_type_list (unsigned_type_node, ptr_type_node, unsigned_type_node, 0)); } #undef TARGET_INIT_BUILTINS @@ -975,6 +978,199 @@ static tree bpf_core_compute (tree, vec<unsigned int> *); static int bpf_core_get_index (const tree); static bool is_attr_preserve_access (tree); +/* BPF Compile Once - Run Everywhere (CO-RE) support. Construct a CO-RE + relocation record for EXPR of kind KIND to be emitted in the .BTF.ext + section. Does nothing if we are not targetting BPF CO-RE, or if the + constructed relocation would be a no-op. */ + +static void +maybe_make_core_relo (tree expr, enum btf_core_reloc_kind kind) +{ + /* If we are not targetting BPF CO-RE, do not make a relocation. We + might not be generating any debug info at all. */ + if (!TARGET_BPF_CORE) + return; + + auto_vec<unsigned int, 16> accessors; + tree container = bpf_core_compute (expr, &accessors); + + /* Any valid use of the builtin must have at least one access. Otherwise, + there is nothing to record and nothing to do. This is primarily a + guard against optimizations leading to unexpected expressions in the + argument of the builtin. For example, if the builtin is used to read + a field of a structure which can be statically determined to hold a + constant value, the argument to the builtin will be optimized to that + constant. This is OK, and means the builtin call is superfluous. + e.g. + struct S foo; + foo.a = 5; + int x = __preserve_access_index (foo.a); + ... do stuff with x + 'foo.a' in the builtin argument will be optimized to '5' with -01+. + This sequence does not warrant recording a CO-RE relocation. */ + + if (accessors.length () < 1) + return; + accessors.reverse (); + + rtx_code_label *label = gen_label_rtx (); + LABEL_PRESERVE_P (label) = 1; + emit_label (label); + + /* Determine what output section this relocation will apply to. + If this function is associated with a section, use that. Otherwise, + fall back on '.text'. */ + const char * section_name; + if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) + section_name = DECL_SECTION_NAME (current_function_decl); + else + section_name = ".text"; + + /* Add the CO-RE relocation information to the BTF container. */ + bpf_core_reloc_add (TREE_TYPE (container), section_name, &accessors, label, + kind); +} + +/* Expand a call to __builtin_preserve_field_info by evaluating the requested + information about SRC according to KIND, and return a tree holding + the result. */ + +static tree +bpf_core_field_info (tree src, enum btf_core_reloc_kind kind) +{ + unsigned int result; + poly_int64 bitsize, bitpos; + tree var_off = NULL_TREE; + machine_mode mode; + int unsignedp, reversep, volatilep; + location_t loc = EXPR_LOCATION (src); + + get_inner_reference (src, &bitsize, &bitpos, &var_off, &mode, &unsignedp, + &reversep, &volatilep); + + /* Note: Use DECL_BIT_FIELD_TYPE rather than DECL_BIT_FIELD here, because it + remembers whether the field in question was originally declared as a + bitfield, regardless of how it has been optimized. */ + bool bitfieldp = (TREE_CODE (src) == COMPONENT_REF + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (src, 1))); + + unsigned int align = TYPE_ALIGN (TREE_TYPE (src)); + if (TREE_CODE (src) == COMPONENT_REF) + { + tree field = TREE_OPERAND (src, 1); + if (DECL_BIT_FIELD_TYPE (field)) + align = TYPE_ALIGN (DECL_BIT_FIELD_TYPE (field)); + else + align = TYPE_ALIGN (TREE_TYPE (field)); + } + + unsigned int start_bitpos = bitpos & ~(align - 1); + unsigned int end_bitpos = start_bitpos + align; + + switch (kind) + { + case BPF_RELO_FIELD_BYTE_OFFSET: + { + if (var_off != NULL_TREE) + { + error_at (loc, "unsupported variable field offset"); + return error_mark_node; + } + + if (bitfieldp) + result = start_bitpos / 8; + else + result = bitpos / 8; + } + break; + + case BPF_RELO_FIELD_BYTE_SIZE: + { + if (mode == BLKmode && bitsize == -1) + { + error_at (loc, "unsupported variable size field access"); + return error_mark_node; + } + + if (bitfieldp) + { + /* To match LLVM behavior, byte size of bitfields is recorded as + the full size of the base type. A 3-bit bitfield of type int is + therefore recorded as having a byte size of 4 bytes. */ + result = end_bitpos - start_bitpos; + if (result & (result - 1)) + { + error_at (loc, "unsupported field expression"); + return error_mark_node; + } + result = result / 8; + } + else + result = bitsize / 8; + } + break; + + case BPF_RELO_FIELD_EXISTS: + /* The field always exists at compile time. */ + result = 1; + break; + + case BPF_RELO_FIELD_SIGNED: + result = !unsignedp; + break; + + case BPF_RELO_FIELD_LSHIFT_U64: + case BPF_RELO_FIELD_RSHIFT_U64: + { + if (mode == BLKmode && bitsize == -1) + { + error_at (loc, "unsupported variable size field access"); + return error_mark_node; + } + if (var_off != NULL_TREE) + { + error_at (loc, "unsupported variable field offset"); + return error_mark_node; + } + + if (!bitfieldp) + { + if (bitsize > 64) + { + error_at (loc, "field size too large"); + return error_mark_node; + } + result = 64 - bitsize; + break; + } + + if (end_bitpos - start_bitpos > 64) + { + error_at (loc, "field size too large"); + return error_mark_node; + } + + if (kind == BPF_RELO_FIELD_LSHIFT_U64) + { + if (TARGET_BIG_ENDIAN) + result = bitpos + 64 - start_bitpos - align; + else + result = start_bitpos + 64 - bitpos - bitsize; + } + else /* RSHIFT_U64 */ + result = 64 - bitsize; + } + break; + + default: + error ("invalid second argument to built-in function"); + return error_mark_node; + break; + } + + return build_int_cst (unsigned_type_node, result); +} + /* Expand a call to a BPF-specific built-in function that was set up with bpf_init_builtins. */ @@ -1025,17 +1221,15 @@ bpf_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, /* The result of the load is in R0. */ return gen_rtx_REG (ops[0].mode, BPF_R0); } + else if (code == -1) { - /* A resolved overloaded builtin, e.g. __bpf_preserve_access_index_si */ + /* A resolved overloaded __builtin_preserve_access_index. */ tree arg = CALL_EXPR_ARG (exp, 0); if (arg == NULL_TREE) return NULL_RTX; - auto_vec<unsigned int, 16> accessors; - tree container; - if (TREE_CODE (arg) == SSA_NAME) { gimple *def_stmt = SSA_NAME_DEF_STMT (arg); @@ -1049,51 +1243,42 @@ bpf_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, /* Avoid double-recording information if the argument is an access to a struct/union marked __attribute__((preserve_access_index)). This Will be handled by the attribute handling pass. */ - if (is_attr_preserve_access (arg)) - return expand_normal (arg); - - container = bpf_core_compute (arg, &accessors); - - /* Any valid use of the builtin must have at least one access. Otherwise, - there is nothing to record and nothing to do. This is primarily a - guard against optimizations leading to unexpected expressions in the - argument of the builtin. For example, if the builtin is used to read - a field of a structure which can be statically determined to hold a - constant value, the argument to the builtin will be optimized to that - constant. This is OK, and means the builtin call is superfluous. - e.g. - struct S foo; - foo.a = 5; - int x = __preserve_access_index (foo.a); - ... do stuff with x - 'foo.a' in the builtin argument will be optimized to '5' with -01+. - This sequence does not warrant recording a CO-RE relocation. */ - - if (accessors.length () < 1) - return expand_normal (arg); - - accessors.reverse (); - - container = TREE_TYPE (container); - - rtx_code_label *label = gen_label_rtx (); - LABEL_PRESERVE_P (label) = 1; - emit_label (label); - - /* Determine what output section this relocation will apply to. - If this function is associated with a section, use that. Otherwise, - fall back on '.text'. */ - const char * section_name; - if (current_function_decl && DECL_SECTION_NAME (current_function_decl)) - section_name = DECL_SECTION_NAME (current_function_decl); + if (!is_attr_preserve_access (arg)) + maybe_make_core_relo (arg, BPF_RELO_FIELD_BYTE_OFFSET); + + return expand_normal (arg); + } + + else if (code == -2) + { + /* A resolved overloaded __builtin_preserve_field_info. */ + tree src = CALL_EXPR_ARG (exp, 0); + tree kind_tree = CALL_EXPR_ARG (exp, 1); + unsigned HOST_WIDE_INT kind_val; + if (tree_fits_uhwi_p (kind_tree)) + kind_val = tree_to_uhwi (kind_tree); else - section_name = ".text"; + error ("invalid argument to built-in function"); - /* Add the CO-RE relocation information to the BTF container. */ - bpf_core_reloc_add (container, section_name, &accessors, label); + enum btf_core_reloc_kind kind = (enum btf_core_reloc_kind) kind_val; - return expand_normal (arg); + if (TREE_CODE (src) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (src); + if (is_gimple_assign (def_stmt)) + src = gimple_assign_rhs1 (def_stmt); + } + if (TREE_CODE (src) == ADDR_EXPR) + src = TREE_OPERAND (src, 0); + + tree result = bpf_core_field_info (src, kind); + + if (result != error_mark_node) + maybe_make_core_relo (src, kind); + + return expand_normal (result); } + gcc_unreachable (); } @@ -1259,41 +1444,64 @@ bpf_core_get_index (const tree node) __builtin_preserve_access_index. */ static tree -bpf_core_newdecl (tree type) +bpf_core_newdecl (tree type, bool is_pai) { - tree rettype = build_function_type_list (type, type, NULL); + tree rettype; char name[80]; - int len = snprintf (name, sizeof (name), "%s", "__builtin_pai_"); + static unsigned long pai_count = 0; + static unsigned long pfi_count = 0; - static unsigned long cnt = 0; - len = snprintf (name + len, sizeof (name) - len, "%lu", cnt++); + if (is_pai) + { + rettype = build_function_type_list (type, type, NULL); + int len = snprintf (name, sizeof (name), "%s", "__builtin_pai_"); + len = snprintf (name + len, sizeof (name) - len, "%lu", pai_count++); + } + else + { + rettype = build_function_type_list (unsigned_type_node, type, + unsigned_type_node, NULL); + int len = snprintf (name, sizeof (name), "%s", "__builtin_pfi_"); + len = snprintf (name + len, sizeof (name) - len, "%lu", pfi_count++); + } - return add_builtin_function_ext_scope (name, rettype, -1, BUILT_IN_MD, NULL, - NULL_TREE); + return add_builtin_function_ext_scope (name, rettype, is_pai ? -1 : -2, + BUILT_IN_MD, NULL, NULL_TREE); } /* Return whether EXPR could access some aggregate data structure that BPF CO-RE support needs to know about. */ -static int +static bool bpf_core_is_maybe_aggregate_access (tree expr) { - enum tree_code code = TREE_CODE (expr); - if (code == COMPONENT_REF || code == ARRAY_REF) - return 1; - - if (code == ADDR_EXPR) + switch (TREE_CODE (expr)) + { + case COMPONENT_REF: + case BIT_FIELD_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + return true; + case ADDR_EXPR: + case NOP_EXPR: return bpf_core_is_maybe_aggregate_access (TREE_OPERAND (expr, 0)); - - return 0; + default: + return false; + } } +struct core_walk_data { + location_t loc; + tree arg; +}; + /* Callback function used with walk_tree from bpf_resolve_overloaded_builtin. */ static tree bpf_core_walk (tree *tp, int *walk_subtrees, void *data) { - location_t loc = *((location_t *) data); + struct core_walk_data *dat = (struct core_walk_data *) data; + bool is_pai = dat->arg == NULL_TREE; /* If this is a type, don't do anything. */ if (TYPE_P (*tp)) @@ -1302,10 +1510,18 @@ bpf_core_walk (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } + /* Build a new function call to a resolved builtin for the desired operation. + If this is a preserve_field_info call, pass along the argument to the + resolved builtin call. */ if (bpf_core_is_maybe_aggregate_access (*tp)) { - tree newdecl = bpf_core_newdecl (TREE_TYPE (*tp)); - tree newcall = build_call_expr_loc (loc, newdecl, 1, *tp); + tree newdecl = bpf_core_newdecl (TREE_TYPE (*tp), is_pai); + tree newcall; + if (is_pai) + newcall = build_call_expr_loc (dat->loc, newdecl, 1, *tp); + else + newcall = build_call_expr_loc (dat->loc, newdecl, 2, *tp, dat->arg); + *tp = newcall; *walk_subtrees = 0; } @@ -1330,6 +1546,30 @@ bpf_small_register_classes_for_mode_p (machine_mode mode) #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P \ bpf_small_register_classes_for_mode_p +/* Return whether EXPR is a valid first argument for a call to + __builtin_preserve_field_info. */ + +static bool +bpf_is_valid_preserve_field_info_arg (tree expr) +{ + switch (TREE_CODE (expr)) + { + case COMPONENT_REF: + case BIT_FIELD_REF: + case ARRAY_REF: + case ARRAY_RANGE_REF: + return true; + case NOP_EXPR: + return bpf_is_valid_preserve_field_info_arg (TREE_OPERAND (expr, 0)); + case ADDR_EXPR: + /* Do not accept ADDR_EXPRs like &foo.bar, but do accept accesses like + foo.baz where baz is an array. */ + return (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == ARRAY_TYPE); + default: + return false; + } +} + /* Implement TARGET_RESOLVE_OVERLOADED_BUILTIN (see gccint manual section Target Macros::Misc.). We use this for the __builtin_preserve_access_index builtin for CO-RE @@ -1344,7 +1584,12 @@ bpf_small_register_classes_for_mode_p (machine_mode mode) static tree bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) { - if (DECL_MD_FUNCTION_CODE (fndecl) != BPF_BUILTIN_PRESERVE_ACCESS_INDEX) + bool is_pai = DECL_MD_FUNCTION_CODE (fndecl) + == BPF_BUILTIN_PRESERVE_ACCESS_INDEX; + bool is_pfi = DECL_MD_FUNCTION_CODE (fndecl) + == BPF_BUILTIN_PRESERVE_FIELD_INFO; + + if (!is_pai && !is_pfi) return NULL_TREE; /* We only expect one argument, but it may be an arbitrarily-complicated @@ -1352,18 +1597,26 @@ bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) vec<tree, va_gc> *params = static_cast<vec<tree, va_gc> *> (arglist); unsigned n_params = params ? params->length() : 0; - if (n_params != 1) + if ((is_pai && n_params != 1) || (is_pfi && n_params != 2)) { - error_at (loc, "expected exactly 1 argument"); - return NULL_TREE; + error_at (loc, "wrong number of arguments"); + return error_mark_node; } tree param = (*params)[0]; - /* If not generating BPF_CORE information, the builtin does nothing. */ - if (!TARGET_BPF_CORE) + /* If not generating BPF_CORE information, preserve_access_index does nothing, + and simply "resolves to" the argument. */ + if (!TARGET_BPF_CORE && is_pai) return param; + if (is_pfi && !bpf_is_valid_preserve_field_info_arg (param)) + { + error_at (EXPR_LOC_OR_LOC (param, loc), + "argument is not a field access"); + return error_mark_node; + } + /* Do remove_c_maybe_const_expr for the arg. TODO: WHY do we have to do this here? Why doesn't c-typeck take care of it before or after this hook? */ @@ -1387,7 +1640,11 @@ bpf_resolve_overloaded_builtin (location_t loc, tree fndecl, void *arglist) This ensures that all the relevant information remains within the expression trees the builtin finally gets. */ - walk_tree (¶m, bpf_core_walk, (void *) &loc, NULL); + struct core_walk_data data; + data.loc = loc; + data.arg = is_pai ? NULL_TREE : (*params)[1]; + + walk_tree (¶m, bpf_core_walk, (void *) &data, NULL); return param; } @@ -1524,7 +1781,8 @@ handle_attr_preserve (function *fn) emit_label (label); /* Add the CO-RE relocation information to the BTF container. */ - bpf_core_reloc_add (container, section_name, &accessors, label); + bpf_core_reloc_add (container, section_name, &accessors, label, + BPF_RELO_FIELD_BYTE_OFFSET); } } } diff --git a/gcc/config/bpf/coreout.cc b/gcc/config/bpf/coreout.cc index 8897a04..9f71040 100644 --- a/gcc/config/bpf/coreout.cc +++ b/gcc/config/bpf/coreout.cc @@ -152,7 +152,8 @@ static GTY (()) vec<bpf_core_section_ref, va_gc> *bpf_core_sections; void bpf_core_reloc_add (const tree type, const char * section_name, - vec<unsigned int> *accessors, rtx_code_label *label) + vec<unsigned int> *accessors, rtx_code_label *label, + enum btf_core_reloc_kind kind) { char buf[40]; unsigned int i, n = 0; @@ -173,7 +174,7 @@ bpf_core_reloc_add (const tree type, const char * section_name, bpfcr->bpfcr_type = get_btf_id (ctf_lookup_tree_type (ctfc, type)); bpfcr->bpfcr_insn_label = label; - bpfcr->bpfcr_kind = BPF_RELO_FIELD_BYTE_OFFSET; + bpfcr->bpfcr_kind = kind; /* Add the CO-RE reloc to the appropriate section. */ bpf_core_section_ref sec; diff --git a/gcc/config/bpf/coreout.h b/gcc/config/bpf/coreout.h index 3c7bdfd..498853f 100644 --- a/gcc/config/bpf/coreout.h +++ b/gcc/config/bpf/coreout.h @@ -103,7 +103,7 @@ extern void btf_ext_init (void); extern void btf_ext_output (void); extern void bpf_core_reloc_add (const tree, const char *, vec<unsigned int> *, - rtx_code_label *); + rtx_code_label *, enum btf_core_reloc_kind); extern int bpf_core_get_sou_member_index (ctf_container_ref, const tree); #ifdef __cplusplus diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index baf1f1f..aaa678e 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -113,6 +113,7 @@ UNSPEC_PEEPSIB UNSPEC_INSN_FALSE_DEP UNSPEC_SBB + UNSPEC_CC_NE ;; For SSE/MMX support: UNSPEC_FIX_NOTRUNC @@ -11470,7 +11471,7 @@ "&& reload_completed" [(parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_dup 1) (const_int 0))) + (unspec:CCC [(match_dup 1) (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 0) (neg:DWIH (match_dup 1)))]) (parallel [(set (match_dup 2) @@ -11499,7 +11500,8 @@ (match_operand:SWI48 1 "nonimmediate_gr_operand")) (parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_operand:SWI48 2 "general_reg_operand") (const_int 0))) + (unspec:CCC [(match_operand:SWI48 2 "general_reg_operand") + (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 2) (neg:SWI48 (match_dup 2)))]) (parallel [(set (match_dup 0) @@ -11517,7 +11519,7 @@ && !reg_mentioned_p (operands[2], operands[1])" [(parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_dup 2) (const_int 0))) + (unspec:CCC [(match_dup 2) (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 2) (neg:SWI48 (match_dup 2)))]) (parallel [(set (match_dup 0) @@ -11543,7 +11545,8 @@ (clobber (reg:CC FLAGS_REG))]) (parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_operand:SWI48 1 "general_reg_operand") (const_int 0))) + (unspec:CCC [(match_operand:SWI48 1 "general_reg_operand") + (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 1) (neg:SWI48 (match_dup 1)))]) (parallel [(set (match_dup 0) @@ -11559,7 +11562,7 @@ "REGNO (operands[0]) != REGNO (operands[1])" [(parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_dup 1) (const_int 0))) + (unspec:CCC [(match_dup 1) (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 1) (neg:SWI48 (match_dup 1)))]) (parallel [(set (match_dup 0) @@ -11635,9 +11638,9 @@ (define_insn "*neg<mode>_ccc_1" [(set (reg:CCC FLAGS_REG) - (ne:CCC - (match_operand:SWI 1 "nonimmediate_operand" "0") - (const_int 0))) + (unspec:CCC + [(match_operand:SWI 1 "nonimmediate_operand" "0") + (const_int 0)] UNSPEC_CC_NE)) (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m") (neg:SWI (match_dup 1)))] "" @@ -11647,9 +11650,9 @@ (define_insn "*neg<mode>_ccc_2" [(set (reg:CCC FLAGS_REG) - (ne:CCC - (match_operand:SWI 1 "nonimmediate_operand" "0") - (const_int 0))) + (unspec:CCC + [(match_operand:SWI 1 "nonimmediate_operand" "0") + (const_int 0)] UNSPEC_CC_NE)) (clobber (match_scratch:SWI 0 "=<r>"))] "" "neg{<imodesuffix>}\t%0" @@ -11659,8 +11662,8 @@ (define_expand "x86_neg<mode>_ccc" [(parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_operand:SWI48 1 "register_operand") - (const_int 0))) + (unspec:CCC [(match_operand:SWI48 1 "register_operand") + (const_int 0)] UNSPEC_CC_NE)) (set (match_operand:SWI48 0 "register_operand") (neg:SWI48 (match_dup 1)))])]) @@ -11686,8 +11689,9 @@ ;; Negate with jump on overflow. (define_expand "negv<mode>3" [(parallel [(set (reg:CCO FLAGS_REG) - (ne:CCO (match_operand:SWI 1 "register_operand") - (match_dup 3))) + (unspec:CCO + [(match_operand:SWI 1 "register_operand") + (match_dup 3)] UNSPEC_CC_NE)) (set (match_operand:SWI 0 "register_operand") (neg:SWI (match_dup 1)))]) (set (pc) (if_then_else @@ -11703,8 +11707,9 @@ (define_insn "*negv<mode>3" [(set (reg:CCO FLAGS_REG) - (ne:CCO (match_operand:SWI 1 "nonimmediate_operand" "0") - (match_operand:SWI 2 "const_int_operand"))) + (unspec:CCO [(match_operand:SWI 1 "nonimmediate_operand" "0") + (match_operand:SWI 2 "const_int_operand")] + UNSPEC_CC_NE)) (set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m") (neg:SWI (match_dup 1)))] "ix86_unary_operator_ok (NEG, <MODE>mode, operands) @@ -11770,7 +11775,7 @@ "&& 1" [(parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_dup 1) (const_int 0))) + (unspec:CCC [(match_dup 1) (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 2) (neg:DWIH (match_dup 1)))]) (parallel [(set (match_dup 5) @@ -11814,7 +11819,7 @@ "&& 1" [(parallel [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_dup 1) (const_int 0))) + (unspec:CCC [(match_dup 1) (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 2) (neg:DWIH (match_dup 1)))]) (parallel [(set (match_dup 5) @@ -21456,7 +21461,7 @@ (const_int 0))))] "" [(set (reg:CCC FLAGS_REG) - (ne:CCC (match_dup 1) (const_int 0))) + (unspec:CCC [(match_dup 1) (const_int 0)] UNSPEC_CC_NE)) (set (match_dup 0) (neg:SWI (ltu:SWI (reg:CCC FLAGS_REG) (const_int 0))))]) diff --git a/gcc/config/riscv/arch-canonicalize b/gcc/config/riscv/arch-canonicalize index fd7651a..2498db5 100755 --- a/gcc/config/riscv/arch-canonicalize +++ b/gcc/config/riscv/arch-canonicalize @@ -41,6 +41,11 @@ LONG_EXT_PREFIXES = ['z', 's', 'h', 'x'] IMPLIED_EXT = { "d" : ["f", "zicsr"], "f" : ["zicsr"], + "zdinx" : ["zfinx", "zicsr"], + "zfinx" : ["zicsr"], + "zhinx" : ["zhinxmin", "zfinx", "zicsr"], + "zhinxmin" : ["zfinx", "zicsr"], + "zk" : ["zkn", "zkr", "zkt"], "zkn" : ["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"], "zks" : ["zbkb", "zbkc", "zbkx", "zksed", "zksh"], diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md index 951dcc5..4088c48 100644 --- a/gcc/config/riscv/constraints.md +++ b/gcc/config/riscv/constraints.md @@ -21,8 +21,9 @@ ;; Register constraints -(define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : NO_REGS" - "A floating-point register (if available).") +(define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : + (TARGET_ZFINX ? GR_REGS : NO_REGS)" + "A floating-point register (if available, reuse GPR as FPR when use zfinx).") (define_register_constraint "j" "SIBCALL_REGS" "@internal") diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index 39dffab..50380ec 100644 --- a/gcc/config/riscv/iterators.md +++ b/gcc/config/riscv/iterators.md @@ -59,9 +59,9 @@ (define_mode_iterator ANYI [QI HI SI (DI "TARGET_64BIT")]) ;; Iterator for hardware-supported floating-point modes. -(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT") - (DF "TARGET_DOUBLE_FLOAT") - (HF "TARGET_ZFH")]) +(define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT || TARGET_ZFINX") + (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX") + (HF "TARGET_ZFH || TARGET_ZHINX")]) ;; Iterator for floating-point modes that can be loaded into X registers. (define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")]) diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc index 9fa4d6c..021f6c6 100644 --- a/gcc/config/riscv/riscv-builtins.cc +++ b/gcc/config/riscv/riscv-builtins.cc @@ -87,7 +87,7 @@ struct riscv_builtin_description { unsigned int (*avail) (void); }; -AVAIL (hard_float, TARGET_HARD_FLOAT) +AVAIL (hard_float, TARGET_HARD_FLOAT || TARGET_ZFINX) AVAIL (clean32, TARGET_ZICBOM && !TARGET_64BIT) @@ -342,7 +342,7 @@ riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, void riscv_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) { - if (!TARGET_HARD_FLOAT) + if (!(TARGET_HARD_FLOAT || TARGET_ZFINX)) return; tree frflags = GET_BUILTIN_DECL (CODE_FOR_riscv_frflags); diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc index 78f6eac..826ae00 100644 --- a/gcc/config/riscv/riscv-c.cc +++ b/gcc/config/riscv/riscv-c.cc @@ -61,7 +61,7 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile) if (TARGET_HARD_FLOAT) builtin_define_with_int_value ("__riscv_flen", UNITS_PER_FP_REG * 8); - if (TARGET_HARD_FLOAT && TARGET_FDIV) + if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && TARGET_FDIV) { builtin_define ("__riscv_fdiv"); builtin_define ("__riscv_fsqrt"); diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h index 63ac56a..1dfe8c8 100644 --- a/gcc/config/riscv/riscv-opts.h +++ b/gcc/config/riscv/riscv-opts.h @@ -83,6 +83,16 @@ enum stack_protector_guard { #define TARGET_ZBC ((riscv_zb_subext & MASK_ZBC) != 0) #define TARGET_ZBS ((riscv_zb_subext & MASK_ZBS) != 0) +#define MASK_ZFINX (1 << 0) +#define MASK_ZDINX (1 << 1) +#define MASK_ZHINX (1 << 2) +#define MASK_ZHINXMIN (1 << 3) + +#define TARGET_ZFINX ((riscv_zinx_subext & MASK_ZFINX) != 0) +#define TARGET_ZDINX ((riscv_zinx_subext & MASK_ZDINX) != 0) +#define TARGET_ZHINX ((riscv_zinx_subext & MASK_ZHINX) != 0) +#define TARGET_ZHINXMIN ((riscv_zinx_subext & MASK_ZHINXMIN) != 0) + #define MASK_ZBKB (1 << 0) #define MASK_ZBKC (1 << 1) #define MASK_ZBKX (1 << 2) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 3d02954..77bc65b 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -5420,6 +5420,13 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode) != call_used_or_fixed_reg_p (regno + i)) return false; + /* Only use even registers in RV32 ZDINX */ + if (!TARGET_64BIT && TARGET_ZDINX){ + if (GET_MODE_CLASS (mode) == MODE_FLOAT && + GET_MODE_UNIT_SIZE (mode) == GET_MODE_SIZE (DFmode)) + return !(regno & 1); + } + return true; } @@ -5659,7 +5666,7 @@ riscv_option_override (void) error ("%<-mdiv%> requires %<-march%> to subsume the %<M%> extension"); /* Likewise floating-point division and square root. */ - if (TARGET_HARD_FLOAT && (target_flags_explicit & MASK_FDIV) == 0) + if ((TARGET_HARD_FLOAT || TARGET_ZFINX) && (target_flags_explicit & MASK_FDIV) == 0) target_flags |= MASK_FDIV; /* Handle -mtune, use -mcpu if -mtune is not given, and use default -mtune @@ -5705,6 +5712,11 @@ riscv_option_override (void) if (TARGET_RVE && riscv_abi != ABI_ILP32E) error ("rv32e requires ilp32e ABI"); + // Zfinx require abi ilp32,ilp32e or lp64. + if (TARGET_ZFINX && riscv_abi != ABI_ILP32 + && riscv_abi != ABI_LP64 && riscv_abi != ABI_ILP32E) + error ("z*inx requires ABI ilp32, ilp32e or lp64"); + /* We do not yet support ILP32 on RV64. */ if (BITS_PER_WORD != POINTER_SIZE) error ("ABI requires %<-march=rv%d%>", POINTER_SIZE); @@ -6337,7 +6349,7 @@ riscv_libgcc_floating_mode_supported_p (scalar_float_mode mode) precision of the _FloatN type; evaluate all other operations and constants to the range and precision of the semantic type; - If we have the zfh extensions then we support _Float16 in native + If we have the zfh/zhinx extensions then we support _Float16 in native precision, so we should set this to 16. */ static enum flt_eval_method riscv_excess_precision (enum excess_precision_type type) @@ -6346,8 +6358,9 @@ riscv_excess_precision (enum excess_precision_type type) { case EXCESS_PRECISION_TYPE_FAST: case EXCESS_PRECISION_TYPE_STANDARD: - return (TARGET_ZFH ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 - : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT); + return ((TARGET_ZFH || TARGET_ZHINX) + ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 + : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT); case EXCESS_PRECISION_TYPE_IMPLICIT: case EXCESS_PRECISION_TYPE_FLOAT16: return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16; diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index ae907a7..798f737 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -441,7 +441,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (plus:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fadd.<fmt>\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "<UNITMODE>")]) @@ -572,7 +572,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (minus:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fsub.<fmt>\t%0,%1,%2" [(set_attr "type" "fadd") (set_attr "mode" "<UNITMODE>")]) @@ -742,7 +742,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (mult:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmul.<fmt>\t%0,%1,%2" [(set_attr "type" "fmul") (set_attr "mode" "<UNITMODE>")]) @@ -1049,7 +1049,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (div:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT && TARGET_FDIV" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && TARGET_FDIV" "fdiv.<fmt>\t%0,%1,%2" [(set_attr "type" "fdiv") (set_attr "mode" "<UNITMODE>")]) @@ -1064,7 +1064,7 @@ (define_insn "sqrt<mode>2" [(set (match_operand:ANYF 0 "register_operand" "=f") (sqrt:ANYF (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT && TARGET_FDIV" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && TARGET_FDIV" { return "fsqrt.<fmt>\t%0,%1"; } @@ -1079,7 +1079,7 @@ (fma:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmadd.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1090,7 +1090,7 @@ (fma:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmsub.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1102,7 +1102,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fnmadd.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1114,7 +1114,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fnmsub.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1127,7 +1127,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (<MODE>mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (<MODE>mode)" "fmadd.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1140,7 +1140,7 @@ (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")) (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (<MODE>mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (<MODE>mode)" "fmsub.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1153,7 +1153,7 @@ (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f"))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (<MODE>mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (<MODE>mode)" "fnmadd.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1166,7 +1166,7 @@ (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f") (neg:ANYF (match_operand:ANYF 3 "register_operand" " f")))))] - "TARGET_HARD_FLOAT && !HONOR_SIGNED_ZEROS (<MODE>mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SIGNED_ZEROS (<MODE>mode)" "fnmsub.<fmt>\t%0,%1,%2,%3" [(set_attr "type" "fmadd") (set_attr "mode" "<UNITMODE>")]) @@ -1181,7 +1181,7 @@ (define_insn "abs<mode>2" [(set (match_operand:ANYF 0 "register_operand" "=f") (abs:ANYF (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fabs.<fmt>\t%0,%1" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1191,7 +1191,7 @@ (unspec:ANYF [(match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")] UNSPEC_COPYSIGN))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fsgnj.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1199,7 +1199,7 @@ (define_insn "neg<mode>2" [(set (match_operand:ANYF 0 "register_operand" "=f") (neg:ANYF (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fneg.<fmt>\t%0,%1" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1216,7 +1216,7 @@ (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) (use (match_operand:ANYF 2 "register_operand" " f"))] UNSPEC_FMIN))] - "TARGET_HARD_FLOAT && !HONOR_SNANS (<MODE>mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SNANS (<MODE>mode)" "fmin.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1226,7 +1226,7 @@ (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f")) (use (match_operand:ANYF 2 "register_operand" " f"))] UNSPEC_FMAX))] - "TARGET_HARD_FLOAT && !HONOR_SNANS (<MODE>mode)" + "(TARGET_HARD_FLOAT || TARGET_ZFINX) && !HONOR_SNANS (<MODE>mode)" "fmax.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1235,7 +1235,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (smin:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmin.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1244,7 +1244,7 @@ [(set (match_operand:ANYF 0 "register_operand" "=f") (smax:ANYF (match_operand:ANYF 1 "register_operand" " f") (match_operand:ANYF 2 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fmax.<fmt>\t%0,%1,%2" [(set_attr "type" "fmove") (set_attr "mode" "<UNITMODE>")]) @@ -1305,7 +1305,7 @@ [(set (match_operand:SF 0 "register_operand" "=f") (float_truncate:SF (match_operand:DF 1 "register_operand" " f")))] - "TARGET_DOUBLE_FLOAT" + "TARGET_DOUBLE_FLOAT || TARGET_ZDINX" "fcvt.s.d\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF")]) @@ -1314,7 +1314,7 @@ [(set (match_operand:HF 0 "register_operand" "=f") (float_truncate:HF (match_operand:SF 1 "register_operand" " f")))] - "TARGET_ZFHMIN" + "TARGET_ZFHMIN || TARGET_ZHINXMIN" "fcvt.h.s\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "HF")]) @@ -1323,7 +1323,8 @@ [(set (match_operand:HF 0 "register_operand" "=f") (float_truncate:HF (match_operand:DF 1 "register_operand" " f")))] - "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT" + "(TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT) || + (TARGET_ZHINXMIN && TARGET_ZDINX)" "fcvt.h.d\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "HF")]) @@ -1449,7 +1450,7 @@ [(set (match_operand:SF 0 "register_operand" "=f") (float_extend:SF (match_operand:HF 1 "register_operand" " f")))] - "TARGET_ZFHMIN" + "TARGET_ZFHMIN || TARGET_ZHINXMIN" "fcvt.s.h\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "SF")]) @@ -1458,7 +1459,7 @@ [(set (match_operand:DF 0 "register_operand" "=f") (float_extend:DF (match_operand:SF 1 "register_operand" " f")))] - "TARGET_DOUBLE_FLOAT" + "TARGET_DOUBLE_FLOAT || TARGET_ZDINX" "fcvt.d.s\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF")]) @@ -1467,7 +1468,8 @@ [(set (match_operand:DF 0 "register_operand" "=f") (float_extend:DF (match_operand:HF 1 "register_operand" " f")))] - "TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT" + "(TARGET_ZFHMIN && TARGET_DOUBLE_FLOAT) || + (TARGET_ZHINXMIN && TARGET_ZDINX)" "fcvt.d.h\t%0,%1" [(set_attr "type" "fcvt") (set_attr "mode" "DF")]) @@ -1513,7 +1515,7 @@ [(set (match_operand:GPR 0 "register_operand" "=r") (fix:GPR (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<GPR:ifmt>.<ANYF:fmt> %0,%1,rtz" [(set_attr "type" "fcvt") (set_attr "mode" "<ANYF:MODE>")]) @@ -1522,7 +1524,7 @@ [(set (match_operand:GPR 0 "register_operand" "=r") (unsigned_fix:GPR (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<GPR:ifmt>u.<ANYF:fmt> %0,%1,rtz" [(set_attr "type" "fcvt") (set_attr "mode" "<ANYF:MODE>")]) @@ -1531,7 +1533,7 @@ [(set (match_operand:ANYF 0 "register_operand" "= f") (float:ANYF (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<ANYF:fmt>.<GPR:ifmt>\t%0,%z1" [(set_attr "type" "fcvt") (set_attr "mode" "<ANYF:MODE>")]) @@ -1540,7 +1542,7 @@ [(set (match_operand:ANYF 0 "register_operand" "= f") (unsigned_float:ANYF (match_operand:GPR 1 "reg_or_0_operand" " rJ")))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<ANYF:fmt>.<GPR:ifmt>u\t%0,%z1" [(set_attr "type" "fcvt") (set_attr "mode" "<ANYF:MODE>")]) @@ -1550,7 +1552,7 @@ (unspec:GPR [(match_operand:ANYF 1 "register_operand" " f")] RINT))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fcvt.<GPR:ifmt>.<ANYF:fmt> %0,%1,<rint_rm>" [(set_attr "type" "fcvt") (set_attr "mode" "<ANYF:MODE>")]) @@ -2278,7 +2280,7 @@ (match_operand:ANYF 2 "register_operand")]) (label_ref (match_operand 3 "")) (pc)))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" { riscv_expand_conditional_branch (operands[3], GET_CODE (operands[0]), operands[1], operands[2]); @@ -2367,7 +2369,7 @@ (match_operator:SI 1 "fp_scc_comparison" [(match_operand:ANYF 2 "register_operand") (match_operand:ANYF 3 "register_operand")]))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" { riscv_expand_float_scc (operands[0], GET_CODE (operands[1]), operands[2], operands[3]); @@ -2379,7 +2381,7 @@ (match_operator:X 1 "fp_native_comparison" [(match_operand:ANYF 2 "register_operand" " f") (match_operand:ANYF 3 "register_operand" " f")]))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "f%C1.<fmt>\t%0,%2,%3" [(set_attr "type" "fcmp") (set_attr "mode" "<UNITMODE>")]) @@ -2389,7 +2391,7 @@ (unspec:X [(match_operand:ANYF 1 "register_operand") (match_operand:ANYF 2 "register_operand")] QUIET_COMPARISON))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" { rtx op0 = operands[0]; rtx op1 = operands[1]; @@ -2809,19 +2811,19 @@ (define_insn "riscv_frflags" [(set (match_operand:SI 0 "register_operand" "=r") (unspec_volatile [(const_int 0)] UNSPECV_FRFLAGS))] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "frflags\t%0") (define_insn "riscv_fsflags" [(unspec_volatile [(match_operand:SI 0 "csr_operand" "rK")] UNSPECV_FSFLAGS)] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "fsflags\t%0") (define_insn "*riscv_fsnvsnan<mode>2" [(unspec_volatile [(match_operand:ANYF 0 "register_operand" "f") (match_operand:ANYF 1 "register_operand" "f")] UNSPECV_FSNVSNAN)] - "TARGET_HARD_FLOAT" + "TARGET_HARD_FLOAT || TARGET_ZFINX" "feq.<fmt>\tzero,%0,%1" [(set_attr "type" "fcmp") (set_attr "mode" "<UNITMODE>")]) diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt index 9493117..426ea95 100644 --- a/gcc/config/riscv/riscv.opt +++ b/gcc/config/riscv/riscv.opt @@ -207,6 +207,9 @@ TargetVariable int riscv_zb_subext TargetVariable +int riscv_zinx_subext + +TargetVariable int riscv_zk_subext TargetVariable diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 2e7f76a..de9bcbf 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -940,9 +940,10 @@ because of offering further optimization opportunities. */ if (register_operand (operands[0], DImode)) { - xtensa_split_DI_reg_imm (operands); - emit_move_insn (operands[0], operands[1]); - emit_move_insn (operands[2], operands[3]); + rtx ops[4] = { operands[0], operands[1] }; + xtensa_split_DI_reg_imm (ops); + emit_move_insn (ops[0], ops[1]); + emit_move_insn (ops[2], ops[3]); DONE; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 550515c..d065fd1 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,34 @@ +2022-10-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/107379 + * name-lookup.cc (push_namespace): Call find_namespace_slot again + after pushdecl as the hash table might be expanded during pushdecl. + +2022-10-27 Nathan Sidwell <nathan@acm.org> + + * mangle.cc (write_closure_template_head): New. + (write_closure_type_name): Call it. + +2022-10-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/107382 + PR c++/107383 + * typeck.cc (cp_build_binary_op): Don't compute semantic_result_type + if result_type is NULL. + +2022-10-26 Marek Polacek <polacek@redhat.com> + + PR c++/106393 + * call.cc (expr_represents_temporary_p): New, factored out of... + (conv_binds_ref_to_temporary): ...here. Don't return false just + because a ck_base is missing. Use expr_represents_temporary_p. + (do_warn_dangling_reference): New. + (maybe_warn_dangling_reference): New. + (extend_ref_init_temps): Call maybe_warn_dangling_reference. + * cp-tree.h: Adjust comment. + * typeck.cc (check_return_expr): Suppress -Wdangling-reference + warnings. + 2022-10-25 Nathan Sidwell <nathan@acm.org> * parser.cc (synthesize_implicit_template_parm): Fix thinko about diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 6a34e9c..951b9fd 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9313,6 +9313,16 @@ conv_binds_ref_to_prvalue (conversion *c) return conv_is_prvalue (next_conversion (c)); } +/* True iff EXPR represents a (subobject of a) temporary. */ + +static bool +expr_represents_temporary_p (tree expr) +{ + while (handled_component_p (expr)) + expr = TREE_OPERAND (expr, 0); + return TREE_CODE (expr) == TARGET_EXPR; +} + /* True iff C is a conversion that binds a reference to a temporary. This is a superset of conv_binds_ref_to_prvalue: here we're also interested in xvalues. */ @@ -9330,18 +9340,14 @@ conv_binds_ref_to_temporary (conversion *c) struct Derived : Base {}; const Base& b(Derived{}); where we bind 'b' to the Base subobject of a temporary object of type - Derived. The subobject is an xvalue; the whole object is a prvalue. */ - if (c->kind != ck_base) - return false; - c = next_conversion (c); - if (c->kind == ck_identity && c->u.expr) - { - tree expr = c->u.expr; - while (handled_component_p (expr)) - expr = TREE_OPERAND (expr, 0); - if (TREE_CODE (expr) == TARGET_EXPR) - return true; - } + Derived. The subobject is an xvalue; the whole object is a prvalue. + + The ck_base doesn't have to be present for cases like X{}.m. */ + if (c->kind == ck_base) + c = next_conversion (c); + if (c->kind == ck_identity && c->u.expr + && expr_represents_temporary_p (c->u.expr)) + return true; return false; } @@ -13428,6 +13434,121 @@ initialize_reference (tree type, tree expr, return expr; } +/* Helper for maybe_warn_dangling_reference to find a problematic CALL_EXPR + that initializes the LHS (and at least one of its arguments represents + a temporary, as outlined in maybe_warn_dangling_reference), or NULL_TREE + if none found. For instance: + + const S& s = S().self(); // S::self (&TARGET_EXPR <...>) + const int& r = (42, f(1)); // f(1) + const int& t = b ? f(1) : f(2); // f(1) + const int& u = b ? f(1) : f(g); // f(1) + const int& v = b ? f(g) : f(2); // f(2) + const int& w = b ? f(g) : f(g); // NULL_TREE + const int& y = (f(1), 42); // NULL_TREE + const int& z = f(f(1)); // f(f(1)) + + EXPR is the initializer. */ + +static tree +do_warn_dangling_reference (tree expr) +{ + STRIP_NOPS (expr); + switch (TREE_CODE (expr)) + { + case CALL_EXPR: + { + tree fndecl = cp_get_callee_fndecl_nofold (expr); + if (!fndecl + || warning_suppressed_p (fndecl, OPT_Wdangling_reference) + || !warning_enabled_at (DECL_SOURCE_LOCATION (fndecl), + OPT_Wdangling_reference) + /* If the function doesn't return a reference, don't warn. This + can be e.g. + const int& z = std::min({1, 2, 3, 4, 5, 6, 7}); + which doesn't dangle: std::min here returns an int. */ + || !TYPE_REF_OBJ_P (TREE_TYPE (TREE_TYPE (fndecl)))) + return NULL_TREE; + + /* Here we're looking to see if any of the arguments is a temporary + initializing a reference parameter. */ + for (int i = 0; i < call_expr_nargs (expr); ++i) + { + tree arg = CALL_EXPR_ARG (expr, i); + /* Check that this argument initializes a reference, except for + the argument initializing the object of a member function. */ + if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) + && !TYPE_REF_P (TREE_TYPE (arg))) + continue; + /* It could also be another call taking a temporary and returning + it and initializing this reference parameter. */ + if (do_warn_dangling_reference (arg)) + return expr; + STRIP_NOPS (arg); + if (TREE_CODE (arg) == ADDR_EXPR) + arg = TREE_OPERAND (arg, 0); + if (expr_represents_temporary_p (arg)) + return expr; + /* Don't warn about member function like: + std::any a(...); + S& s = a.emplace<S>({0}, 0); + which constructs a new object and returns a reference to it, but + we still want to detect: + struct S { const S& self () { return *this; } }; + const S& s = S().self(); + where 's' dangles. If we've gotten here, the object this function + is invoked on is not a temporary. */ + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)) + break; + } + return NULL_TREE; + } + case COMPOUND_EXPR: + return do_warn_dangling_reference (TREE_OPERAND (expr, 1)); + case COND_EXPR: + if (tree t = do_warn_dangling_reference (TREE_OPERAND (expr, 1))) + return t; + return do_warn_dangling_reference (TREE_OPERAND (expr, 2)); + case PAREN_EXPR: + return do_warn_dangling_reference (TREE_OPERAND (expr, 0)); + default: + return NULL_TREE; + } +} + +/* Implement -Wdangling-reference, to detect cases like + + int n = 1; + const int& r = std::max(n - 1, n + 1); // r is dangling + + This creates temporaries from the arguments, returns a reference to + one of the temporaries, but both temporaries are destroyed at the end + of the full expression. + + This works by checking if a reference is initialized with a function + that returns a reference, and at least one parameter of the function + is a reference that is bound to a temporary. It assumes that such a + function actually returns one of its arguments. + + DECL is the reference being initialized, INIT is the initializer. */ + +static void +maybe_warn_dangling_reference (const_tree decl, tree init) +{ + if (!warn_dangling_reference) + return; + if (!TYPE_REF_P (TREE_TYPE (decl))) + return; + if (tree call = do_warn_dangling_reference (init)) + { + auto_diagnostic_group d; + if (warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wdangling_reference, + "possibly dangling reference to a temporary")) + inform (EXPR_LOCATION (call), "the temporary was destroyed at " + "the end of the full expression %qE", call); + } +} + /* If *P is an xvalue expression, prevent temporary lifetime extension if it gets used to initialize a reference. */ @@ -13525,6 +13646,9 @@ extend_ref_init_temps (tree decl, tree init, vec<tree, va_gc> **cleanups, tree type = TREE_TYPE (init); if (processing_template_decl) return init; + + maybe_warn_dangling_reference (decl, init); + if (TYPE_REF_P (type)) init = extend_ref_init_temps_1 (decl, init, cleanups, cond_guard); else diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 867096b..6d84514 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -459,7 +459,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. DELETE_EXPR_USE_VEC (in DELETE_EXPR). - (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out). ICS_ELLIPSIS_FLAG (in _CONV) DECL_INITIALIZED_P (in VAR_DECL) TYPENAME_IS_CLASS_P (in TYPENAME_TYPE) @@ -4508,30 +4507,6 @@ get_vec_init_expr (tree t) #define OPAQUE_ENUM_P(TYPE) \ (TREE_CODE (TYPE) == ENUMERAL_TYPE && ENUM_IS_OPAQUE (TYPE)) -/* Determines whether an ENUMERAL_TYPE has an explicit - underlying type. */ -#define ENUM_FIXED_UNDERLYING_TYPE_P(NODE) (TYPE_LANG_FLAG_5 (NODE)) - -/* Returns the underlying type of the given enumeration type. The - underlying type is determined in different ways, depending on the - properties of the enum: - - - In C++0x, the underlying type can be explicitly specified, e.g., - - enum E1 : char { ... } // underlying type is char - - - In a C++0x scoped enumeration, the underlying type is int - unless otherwises specified: - - enum class E2 { ... } // underlying type is int - - - Otherwise, the underlying type is determined based on the - values of the enumerators. In this case, the - ENUM_UNDERLYING_TYPE will not be set until after the definition - of the enumeration is completed by finish_enum. */ -#define ENUM_UNDERLYING_TYPE(TYPE) \ - TREE_TYPE (ENUMERAL_TYPE_CHECK (TYPE)) - /* [dcl.init.aggr] An aggregate is an array or a class with no user-provided @@ -4567,6 +4542,9 @@ get_vec_init_expr (tree t) When appearing in a CONSTRUCTOR, the expression is an unconverted compound literal. + When appearing in a CALL_EXPR, it means that it is a call to + a constructor. + When appearing in a FIELD_DECL, it means that this field has been duly initialized in its constructor. */ #define TREE_HAS_CONSTRUCTOR(NODE) (TREE_LANG_FLAG_4 (NODE)) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 1215463..e396218 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1727,6 +1727,66 @@ write_unnamed_type_name (const tree type) write_compact_number (discriminator); } +// A template head, for templated lambdas. +// <template-head> ::= Tp* Ty +// Tp* Tn <type> +// Tp* Tt <template-head> E +// New in ABI=18. Returns true iff we emitted anything -- used for ABI +// version warning. + +static bool +write_closure_template_head (tree tmpl) +{ + bool any = false; + + // We only need one level of template parms + tree inner = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl)); + + for (int ix = 0, len = TREE_VEC_LENGTH (inner); ix != len; ix++) + { + tree parm = TREE_VEC_ELT (inner, ix); + if (parm == error_mark_node) + continue; + parm = TREE_VALUE (parm); + + if (DECL_VIRTUAL_P (parm)) + // A synthetic parm, we're done. + break; + + any = true; + if (abi_version_at_least (18)) + { + if (TREE_CODE (parm) == PARM_DECL + ? TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) + : TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))) + write_string ("Tp"); + + switch (TREE_CODE (parm)) + { + default: + gcc_unreachable (); + + case TYPE_DECL: + write_string ("Ty"); + break; + + case PARM_DECL: + write_string ("Tn"); + write_type (TREE_TYPE (parm)); + break; + + case TEMPLATE_DECL: + write_string ("Tt"); + write_closure_template_head (parm); + write_string ("E"); + break; + } + } + } + + return any; +} + /* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters */ @@ -1740,6 +1800,14 @@ write_closure_type_name (const tree type) MANGLE_TRACE_TREE ("closure-type-name", type); write_string ("Ul"); + + if (auto ti = maybe_template_info (fn)) + if (write_closure_template_head (TI_TEMPLATE (ti))) + // If there were any explicit template parms, we may need to + // issue a mangling diagnostic. + if (abi_warn_or_compat_version_crosses (18)) + G.need_abi_warning = true; + write_method_parms (parms, /*method_p=*/1, fn); write_char ('E'); write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 14e937d..dfa6fb4 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -8596,6 +8596,13 @@ push_namespace (tree name, bool make_inline) /* This should find the slot created by pushdecl. */ gcc_checking_assert (slot && *slot == ns); } + else + { + /* pushdecl could have expanded the hash table, so + slot might be invalid. */ + slot = find_namespace_slot (current_namespace, name); + gcc_checking_assert (slot); + } make_namespace_finish (ns, slot); /* Add the anon using-directive here, we don't do it in diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index ab6979b..2e0fd8f 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -6179,7 +6179,8 @@ cp_build_binary_op (const op_location_t &location, } if (may_need_excess_precision && (orig_type0 != type0 || orig_type1 != type1) - && build_type == NULL_TREE) + && build_type == NULL_TREE + && result_type) { gcc_assert (common); semantic_result_type = cp_common_type (orig_type0, orig_type1); @@ -11246,6 +11247,17 @@ check_return_expr (tree retval, bool *no_warning) if (processing_template_decl) return saved_retval; + /* A naive attempt to reduce the number of -Wdangling-reference false + positives: if we know that this function can return a variable with + static storage duration rather than one of its parameters, suppress + the warning. */ + if (warn_dangling_reference + && TYPE_REF_P (functype) + && bare_retval + && VAR_P (bare_retval) + && TREE_STATIC (bare_retval)) + suppress_warning (current_function_decl, OPT_Wdangling_reference); + /* Actually copy the value returned into the appropriate location. */ if (retval && retval != result) retval = cp_build_init_expr (result, retval); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 3a1d4a5..48f3b9a 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -15750,6 +15750,83 @@ Load 32-bits from the @code{struct sk_buff} packet data pointed by the register BPF Compile Once-Run Everywhere (CO-RE) support. Instruct GCC to generate CO-RE relocation records for any accesses to aggregate data structures (struct, union, array types) in @var{expr}. This builtin is otherwise transparent, the return value is whatever @var{expr} evaluates to. It is also overloaded: @var{expr} may be of any type (not necessarily a pointer), the return type is the same. Has no effect if @code{-mco-re} is not in effect (either specified or implied). @end deftypefn +@deftypefn {Built-in Function} unsigned int __builtin_preserve_field_info (@var{expr}, unsigned int @var{kind}) +BPF Compile Once-Run Everywhere (CO-RE) support. This builtin is used to +extract information to aid in struct/union relocations. @var{expr} is +an access to a field of a struct or union. Depending on @var{kind}, different +information is returned to the program. A CO-RE relocation for the access in +@var{expr} with kind @var{kind} is recorded if @code{-mco-re} is in effect. + +The following values are supported for @var{kind}: +@table @var +@item FIELD_BYTE_OFFSET = 0 +The returned value is the offset, in bytes, of the field from the +beginning of the containing structure. For bitfields, the byte offset +of the containing word. + +@item FIELD_BYTE_SIZE = 1 +The returned value is the size, in bytes, of the field. For bitfields, +the size in bytes of the containing word. + +@item FIELD_EXISTENCE = 2 +The returned value is 1 if the field exists, 0 otherwise. Always 1 at +compile time. + +@item FIELD_SIGNEDNESS = 3 +The returned value is 1 if the field is signed, 0 otherwise. + +@item FIELD_LSHIFT_U64 = 4 +@itemx FIELD_RSHIFT_U64 = 5 +The returned value is the number of bits of left- or right-shifting +respectively needed in order to recover the original value of the field, +after it has been loaded by a read of FIELD_BYTE_SIZE bytes into an +unsigned 64-bit value. Primarily useful for reading bitfield values +from structures which may change between kernel versions. + +@end table + +Note that the return value is a constant which is known at +compile-time. If the field has a variable offset then +FIELD_BYTE_OFFSET, FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are not +supported. Similarly, if the field has a variable size then +FIELD_BYTE_SIZE, FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are not +supported. + +For example, __builtin_preserve_field_info can be used to reliably +extract bitfield values from a structure which may change between +kernel versions: + +@example +struct S +@{ + short a; + int x:7; + int y:5; +@}; + +int +read_y (struct S *arg) +@{ + unsigned long long val; + unsigned int offset = __builtin_preserve_field_info (arg->y, FIELD_BYTE_OFFSET); + unsigned int size = __builtin_presrve_field_info (arg->y, FIELD_BYTE_SIZE); + + /* Read size bytes from arg + offset into val. */ + bpf_probe_read (&val, size, arg + offset); + + val <<= __builtin_preserve_field_info (arg->y, FIELD_LSHIFT_U64); + + if (__builtin_preserve_field_info (arg->y, FIELD_SIGNEDNESS)) + val = ((long long) val >> __builtin_preserve_field_info (arg->y, FIELD_RSHIFT_U64)); + else + val >>= __builtin_preserve_field_info (arg->y, FIELD_RSHIFT_U64); + + return val; +@} + +@end example +@end deftypefn + @node FR-V Built-in Functions @subsection FR-V Built-in Functions diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ed79440..f138db2 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -211,7 +211,8 @@ in the following sections. -Wno-class-conversion -Wclass-memaccess @gol -Wcomma-subscript -Wconditionally-supported @gol -Wno-conversion-null -Wctad-maybe-unsupported @gol --Wctor-dtor-privacy -Wno-delete-incomplete @gol +-Wctor-dtor-privacy -Wdangling-reference @gol +-Wno-delete-incomplete @gol -Wdelete-non-virtual-dtor -Wno-deprecated-array-compare @gol -Wdeprecated-copy -Wdeprecated-copy-dtor @gol -Wno-deprecated-enum-enum-conversion -Wno-deprecated-enum-float-conversion @gol @@ -3589,6 +3590,54 @@ public static member functions. Also warn if there are no non-private methods, and there's at least one private member function that isn't a constructor or destructor. +@item -Wdangling-reference @r{(C++ and Objective-C++ only)} +@opindex Wdangling-reference +@opindex Wno-dangling-reference +Warn when a reference is bound to a temporary whose lifetime has ended. +For example: + +@smallexample +int n = 1; +const int& r = std::max(n - 1, n + 1); // r is dangling +@end smallexample + +In the example above, two temporaries are created, one for each +argument, and a reference to one of the temporaries is returned. +However, both temporaries are destroyed at the end of the full +expression, so the reference @code{r} is dangling. This warning +also detects dangling references in member initializer lists: + +@smallexample +const int& f(const int& i) @{ return i; @} +struct S @{ + const int &r; // r is dangling + S() : r(f(10)) @{ @} +@}; +@end smallexample + +Member functions are checked as well, but only their object argument: + +@smallexample +struct S @{ + const S& self () @{ return *this; @} +@}; +const S& s = S().self(); // s is dangling +@end smallexample + +Certain functions are safe in this respect, for example @code{std::use_facet}: +they take and return a reference, but they don't return one of its arguments, +which can fool the warning. Such functions can be excluded from the warning +by wrapping them in a @code{#pragma}: + +@smallexample +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" +const T& foo (const T&) @{ @dots{} @} +#pragma GCC diagnostic pop +@end smallexample + +This warning is enabled by @option{-Wall}. + @item -Wdelete-non-virtual-dtor @r{(C++ and Objective-C++ only)} @opindex Wdelete-non-virtual-dtor @opindex Wno-delete-non-virtual-dtor @@ -16422,6 +16471,10 @@ by this option. @end table +Note the enabled sanitizer options tend to increase a false-positive rate +of selected warnings, most notably @option{-Wmaybe-uninitialized}. +And thus we recommend to disable @option{-Werror}. + While @option{-ftrapv} causes traps for signed overflows to be emitted, @option{-fsanitize=undefined} gives a diagnostic message. This currently works only for the C family of languages. diff --git a/gcc/doc/makefile.texi b/gcc/doc/makefile.texi index fe0bbcd..5186c1c 100644 --- a/gcc/doc/makefile.texi +++ b/gcc/doc/makefile.texi @@ -135,6 +135,16 @@ Compares the results of stages 2 and 3. This ensures that the compiler is running properly, since it should produce the same object files regardless of how it itself was compiled. +@item distclean-stage@var{N} (@var{N} = 1@dots{}4, profile, feedback) +Wipe stage @var{N} and all the following ones. + +For example, +@samp{make distclean-stage3} wipes stage 3 and all the following ones, +so that another @command{make} then rebuilds them from scratch. +This can be useful if you're doing changes where +``bubbling'' the changes as described above is not sufficient, +but a full @command{make restrap} isn't necessary either. + @item profiledbootstrap Builds a compiler with profiling feedback information. In this case, the second and third stages are named @samp{profile} and @samp{feedback}, diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f764113..1ca82cd 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2022-10-26 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103413 + * symbol.cc (gfc_type_compatible): A boz-literal-constant has no type + and thus is not considered compatible to any type. + 2022-10-21 José Rui Faustino de Sousa <jrfsousa@gmail.com> PR fortran/100097 diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc index 6050359..49fb378 100644 --- a/gcc/fortran/symbol.cc +++ b/gcc/fortran/symbol.cc @@ -5139,6 +5139,10 @@ gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2) bool is_union1 = (ts1->type == BT_UNION); bool is_union2 = (ts2->type == BT_UNION); + /* A boz-literal-constant has no type. */ + if (ts1->type == BT_BOZ || ts2->type == BT_BOZ) + return false; + if (is_class1 && ts1->u.derived->components && ((ts1->u.derived->attr.is_class diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index f919237..a899d82 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -494,6 +494,14 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name) else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR) res = range_of_cond_expr (r, as_a<gassign *> (s), src); + // If the result is varying, check for basic nonnegativeness. + // Specifically this helps for now with strict enum in cases like + // g++.dg/warn/pr33738.C. + bool so_p; + if (res && r.varying_p () && INTEGRAL_TYPE_P (r.type ()) + && gimple_stmt_nonnegative_warnv_p (s, &so_p)) + r.set_nonnegative (r.type ()); + if (!res) { // If no name specified or range is unsupported, bail. diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5b95b38..7e531c3 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -6c188108858e3ae8c8ea8e4cc55427d8cf01bbc8 +5e658f4659c551330ea68f5667e4f951b218f32d The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/ipa-visibility.cc b/gcc/ipa-visibility.cc index 3ed2b7c..238f7eb 100644 --- a/gcc/ipa-visibility.cc +++ b/gcc/ipa-visibility.cc @@ -886,8 +886,12 @@ function_and_variable_visibility (bool whole_program) && vnode->ref_list.referring.length ()) { enum tls_model new_model = decl_default_tls_model (decl); - gcc_checking_assert (new_model >= decl_tls_model (decl)); - set_decl_tls_model (decl, new_model); + STATIC_ASSERT (TLS_MODEL_GLOBAL_DYNAMIC < TLS_MODEL_LOCAL_DYNAMIC); + STATIC_ASSERT (TLS_MODEL_INITIAL_EXEC < TLS_MODEL_LOCAL_EXEC); + /* We'd prefer to assert that recomputed model is not weaker than + what the front-end assigned, but cannot: see PR 107353. */ + if (new_model >= decl_tls_model (decl)) + set_decl_tls_model (decl, new_model); } } } @@ -5718,6 +5718,7 @@ ira (FILE *f) regstat_free_ri (); regstat_init_n_sets_and_refs (); regstat_compute_ri (); + resize_reg_info (); }; int max_regno_before_rm = max_reg_num (); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index 84fc5a4..e36fa44 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,3 +1,8 @@ +2022-10-27 Martin Liska <mliska@suse.cz> + + PR lto/107418 + * lto-dump.cc (lto_main): Do not load LTO stream for aliases. + 2022-09-15 Richard Biener <rguenther@suse.de> * lto-lang.cc (lto_build_c_type_nodes): Do not initialize diff --git a/gcc/lto/lto-dump.cc b/gcc/lto/lto-dump.cc index f3d852d..5c4dbf5 100644 --- a/gcc/lto/lto-dump.cc +++ b/gcc/lto/lto-dump.cc @@ -227,7 +227,6 @@ void dump_list (void) { dump_list_functions (); dump_list_variables (); - return; } /* Dump specific variables and functions used in IL. */ @@ -243,7 +242,6 @@ void dump_symbol () printf ("\n"); } } - return; } /* Dump specific gimple body of specified function. */ @@ -259,19 +257,17 @@ void dump_body () return; } cgraph_node *cnode; - FOR_EACH_FUNCTION (cnode) - if (cnode->definition - && !cnode->alias - && !strcmp (cnode->name (), flag_dump_body)) + FOR_EACH_DEFINED_FUNCTION (cnode) + if (!cnode->alias + && !strcmp (cnode->asm_name (), flag_dump_body)) { - printf ("Gimple Body of Function: %s\n", cnode->name ()); + printf ("GIMPLE body of function: %s\n\n", cnode->asm_name ()); cnode->get_untransformed_body (); debug_function (cnode->decl, flags); flag = 1; } if (!flag) error_at (input_location, "Function not found."); - return; } /* List of command line options for dumping. */ @@ -292,13 +288,12 @@ void dump_tool_help () " -callgraph Dump the callgraph in graphviz format.\n" " -type-stats Dump statistics of tree types.\n" " -tree-stats Dump statistics of trees.\n" - " -gimple-stats Dump statistics of gimple statements.\n" - " -dump-body= Dump the specific gimple body.\n" + " -gimple-stats Dump statistics of GIMPLE statements.\n" + " -dump-body= Dump the specific GIMPLE body.\n" " -dump-level= Deciding the optimization level of body.\n" " -help Display the dump tool help.\n"; fputs (msg, stdout); - return; } unsigned int @@ -347,7 +342,8 @@ lto_main (void) /* Dump gimple statement statistics. */ cgraph_node *node; FOR_EACH_DEFINED_FUNCTION (node) - node->get_untransformed_body (); + if (!node->alias) + node->get_untransformed_body (); if (!GATHER_STATISTICS) warning_at (input_location, 0, "Not configured with " @@ -364,7 +360,7 @@ lto_main (void) "%<--enable-gather-detailed-mem-stats%>."); else { - printf ("Tree Statistics\n"); + printf ("Tree statistics\n"); dump_tree_statistics (); } } diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk index 49065ce..2b8557f 100644 --- a/gcc/optc-save-gen.awk +++ b/gcc/optc-save-gen.awk @@ -1291,7 +1291,22 @@ for (i = 0; i < n_opts; i++) { var_opt_val_type[n_opt_val] = otype; var_opt_val[n_opt_val] = "x_" name; var_opt_hash[n_opt_val] = flag_set_p("Optimization", flags[i]); - var_opt_init[n_opt_val] = opt_args("Init", flags[i]); + + # If applicable, optimize streaming for the common case that + # the current value is unchanged from the 'Init' value: + # XOR-encode it so that we stream value zero. + # Not handling non-parameters as those really generally don't + # have large initializers. + # Not handling enums as we don't know if '(enum ...) 10' is + # even valid (see synthesized 'if' conditionals below). + if (flag_set_p("Param", flags[i]) \ + && !(otype ~ "^enum ")) { + # Those without 'Init' are zero-initialized and thus + # already encoded ideally. + init = opt_args("Init", flags[i]) + var_opt_optimize_init[n_opt_val] = init; + } + n_opt_val++; } } @@ -1369,9 +1384,10 @@ for (i = 0; i < n_opt_val; i++) { } else { sgn = "int"; } - if (name ~ "^x_param" && !(otype ~ "^enum ") && var_opt_init[i]) { - print " if (" var_opt_init[i] " > (" var_opt_val_type[i] ") 10)"; - print " bp_pack_var_len_" sgn " (bp, ptr->" name" ^ " var_opt_init[i] ");"; + # If applicable, encode the streamed value. + if (var_opt_optimize_init[i]) { + print " if (" var_opt_optimize_init[i] " > (" var_opt_val_type[i] ") 10)"; + print " bp_pack_var_len_" sgn " (bp, ptr->" name" ^ " var_opt_optimize_init[i] ");"; print " else"; print " bp_pack_var_len_" sgn " (bp, ptr->" name");"; } else { @@ -1405,9 +1421,10 @@ for (i = 0; i < n_opt_val; i++) { sgn = "int"; } print " ptr->" name" = (" var_opt_val_type[i] ") bp_unpack_var_len_" sgn " (bp);"; - if (name ~ "^x_param" && !(otype ~ "^enum ") && var_opt_init[i]) { - print " if (" var_opt_init[i] " > (" var_opt_val_type[i] ") 10)"; - print " ptr->" name" ^= " var_opt_init[i] ";"; + # If applicable, decode the streamed value. + if (var_opt_optimize_init[i]) { + print " if (" var_opt_optimize_init[i] " > (" var_opt_val_type[i] ") 10)"; + print " ptr->" name" ^= " var_opt_optimize_init[i] ";"; } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 09c4108..83d372a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,111 @@ +2022-10-27 H.J. Lu <hjl.tools@gmail.com> + + PR target/107172 + * gcc.target/i386/pr107172.c: New test. + +2022-10-27 Nathan Sidwell <nathan@acm.org> + + * g++.dg/abi/lambda-ctx1-18.C: Adjust. + * g++.dg/abi/lambda-ctx1-18vs17.C: Adjust. + * g++.dg/abi/lambda-tpl1-17.C: New. + * g++.dg/abi/lambda-tpl1-18.C: New. + * g++.dg/abi/lambda-tpl1-18vs17.C: New. + * g++.dg/abi/lambda-tpl1.h: New. + +2022-10-27 Aldy Hernandez <aldyh@redhat.com> + + PR tree-optimization/107394 + * gcc.dg/tree-ssa/pr107394.c: New test. + +2022-10-27 Jakub Jelinek <jakub@redhat.com> + + PR c++/107382 + PR c++/107383 + * g++.dg/diagnostic/bad-binary-ops2.C: New test. + +2022-10-27 Jiawei <jiawei@iscas.ac.cn> + + * gcc.target/riscv/_Float16-zhinx-1.c: New test. + * gcc.target/riscv/_Float16-zhinx-2.c: New test. + * gcc.target/riscv/_Float16-zhinx-3.c: New test. + * gcc.target/riscv/_Float16-zhinxmin-1.c: New test. + * gcc.target/riscv/_Float16-zhinxmin-2.c: New test. + * gcc.target/riscv/_Float16-zhinxmin-3.c: New test. + +2022-10-26 David Malcolm <dmalcolm@redhat.com> + + * gcc.dg/analyzer/fd-3.c (test_5): Expect "opened here" message + even when flags are symbolic. + (test_read_from_symbolic_fd): New. + (test_write_to_symbolic_fd): New. + +2022-10-26 Harald Anlauf <anlauf@gmx.de> + + PR fortran/103413 + * gfortran.dg/illegal_boz_arg_4.f90: New test. + +2022-10-26 David Faust <david.faust@oracle.com> + + * gcc.target/bpf/core-builtin-fieldinfo-errors-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-errors-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-existence-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-offset-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-sign-1.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-sign-2.c: New test. + * gcc.target/bpf/core-builtin-fieldinfo-size-1.c: New test. + +2022-10-26 Marek Polacek <polacek@redhat.com> + + PR c++/106393 + * g++.dg/cpp23/elision4.C: Use -Wdangling-reference, add dg-warning. + * g++.dg/cpp23/elision7.C: Likewise. + * g++.dg/warn/Wdangling-pointer-2.C: Use -Wno-dangling-reference. + * g++.dg/warn/Wdangling-reference1.C: New test. + * g++.dg/warn/Wdangling-reference2.C: New test. + * g++.dg/warn/Wdangling-reference3.C: New test. + +2022-10-26 Ju-Zhe Zhong <juzhe.zhong@rivai.ai> + + * gcc.target/riscv/rvv/base/mov-1.c: New. + * gcc.target/riscv/rvv/base/mov-10.c: New. + * gcc.target/riscv/rvv/base/mov-11.c: New. + * gcc.target/riscv/rvv/base/mov-12.c: New. + * gcc.target/riscv/rvv/base/mov-13.c: New. + * gcc.target/riscv/rvv/base/mov-2.c: New. + * gcc.target/riscv/rvv/base/mov-3.c: New. + * gcc.target/riscv/rvv/base/mov-4.c: New. + * gcc.target/riscv/rvv/base/mov-5.c: New. + * gcc.target/riscv/rvv/base/mov-6.c: New. + * gcc.target/riscv/rvv/base/mov-7.c: New. + * gcc.target/riscv/rvv/base/mov-8.c: New. + * gcc.target/riscv/rvv/base/mov-9.c: New. + +2022-10-26 Monk Chiang <monk.chiang@sifive.com> + + * gcc.target/riscv/predef-24.c:New. + * gcc.target/riscv/predef-25.c:New. + +2022-10-26 Jiufu Guo <guojiufu@linux.ibm.com> + + PR target/106460 + * gcc.target/powerpc/pr106460.c: New test. + +2022-10-26 Kito Cheng <kito.cheng@sifive.com> + + * gcc.target/riscv/arch-18.c: New. + * gcc.target/riscv/arch-5.c: Remove test for prefixed + with `h`. + * gcc.target/riscv/predef-23.c: New. + +2022-10-26 Eugene Rozenfeld <erozen@microsoft.com> + + * lib/profopt.exp: Don't force DWARF4 for AutoFDO tests + 2022-10-25 Patrick Palka <ppalka@redhat.com> PR c++/106848 diff --git a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C index c1c9e27..3dd68a4 100644 --- a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C +++ b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18.C @@ -6,6 +6,6 @@ // These correctly include the lambda's extra context as a // substitution candidate, and thus demangle as expected // { dg-final { scan-assembler {_ZNK1C1fMUlT_E_clIMS_iEEDaS1_:} } } -// { dg-final { scan-assembler {_ZNK2L2MUlT_T0_E_clIifEEvS0_S1_:} } } -// { dg-final { scan-assembler {_ZNK1B2L3MUlT_T0_E_clIjdEEvS1_S2_:} } } +// { dg-final { scan-assembler {_ZNK2L2MUlTyTyT_T0_E_clIifEEvS0_S1_:} } } +// { dg-final { scan-assembler {_ZNK1B2L3MUlTyTyT_T0_E_clIjdEEvS1_S2_:} } } // { dg-final { scan-assembler {_Z3fooIN1qMUlvE_ENS0_UlvE0_EEiOT_OT0_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C index f5ec905..ec6709a 100644 --- a/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C +++ b/gcc/testsuite/g++.dg/abi/lambda-ctx1-18vs17.C @@ -3,7 +3,7 @@ #include "lambda-ctx1.h" -// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK1B2L3MUlT_T0_E_clIjdEEvS0_S1_'\) and '-fabi-version=18' \('_ZNK1B2L3MUlT_T0_E_clIjdEEvS1_S2_'\) [^\n]*\n} } -// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK2L2MUlT_T0_E_clIifEEvS_S0_'\) and '-fabi-version=18' \('_ZNK2L2MUlT_T0_E_clIifEEvS0_S1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK1B2L3MUlT_T0_E_clIjdEEvS0_S1_'\) and '-fabi-version=18' \('_ZNK1B2L3MUlTyTyT_T0_E_clIjdEEvS1_S2_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK2L2MUlT_T0_E_clIifEEvS_S0_'\) and '-fabi-version=18' \('_ZNK2L2MUlTyTyT_T0_E_clIifEEvS0_S1_'\) [^\n]*\n} } // { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK1C1fMUlT_E_clIMS_iEEDaS0_'\) and '-fabi-version=18' \('_ZNK1C1fMUlT_E_clIMS_iEEDaS1_'\) [^\n]*\n} } // { dg-regexp {[^\n]*lambda-ctx1.h:[:0-9]* warning: the mangled name [^\n]* \('_Z3fooIN1qMUlvE_EN1qMUlvE0_EEiOT_OT0_'\) and '-fabi-version=18' \('_Z3fooIN1qMUlvE_ENS0_UlvE0_EEiOT_OT0_'\) [^\n]*\n} } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C b/gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C new file mode 100644 index 0000000..b61aaf9 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1-17.C @@ -0,0 +1,20 @@ +// { dg-do compile { target c++20 } } +// { dg-options -fabi-version=17 } + +#include "lambda-tpl1.h" + +// { dg-final { scan-assembler {_ZNK6l_autoMUlT_E_clIiEEDaS_:} } } +// { dg-final { scan-assembler {_ZNK5l_tplMUlT_E_clIiEEDaS_:} } } +// { dg-final { scan-assembler {_ZNK10l_tpl_autoMUlT_T0_E_clIiiEEDaS_S0_:} } } +// { dg-final { scan-assembler {_ZNK12l_tpl_nt_aryMUlRAT__iE_clILi2EEEDaS0_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_nt_autoMUlvE_clILi0EEEDav:} } } +// { dg-final { scan-assembler {_ZNK9l_tpl_tplMUlR3TPLIT_EE_clI1UEEDaS2_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_tpl_tplMUlR6TPLTPLIT_EE_clI3TPLEEDaS2_:} } } +// { dg-final { scan-assembler {_ZNK5l_varMUlDpT_E_clIJiiiEEEDaS0_:} } } + +// This mangling might not be correct, it is my best guess: +// { FIXMEdg-final { scan-assembler {_ZNK6l_var2MUlDpRAT__iE_clIJLi2ELi2EEEEDaS1_:} } } + +// { dg-final { scan-assembler {_ZNK6l_var3MUlRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS1_:} } } +// { dg-final { scan-assembler {_ZNK6l_var4MUlR1YIJDpT_EEE_clIJ1US6_EEEDaS3_:} } } +// { dg-final { scan-assembler {_ZZ2FnILi1EEvvENKUlT_E_clIiEEDaS0_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C new file mode 100644 index 0000000..dbeea40 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18.C @@ -0,0 +1,25 @@ +// { dg-do compile { target c++20 } } + +#include "lambda-tpl1.h" + +// { dg-final { scan-assembler {_ZNK6l_autoMUlT_E_clIiEEDaS0_:} } } +// { dg-final { scan-assembler {_ZNK5l_tplMUlTyT_E_clIiEEDaS0_:} } } +// { dg-final { scan-assembler {_ZNK10l_tpl_autoMUlTyT_T0_E_clIiiEEDaS0_S1_:} } } +// { dg-final { scan-assembler {_ZNK12l_tpl_nt_aryMUlTniRAT__iE_clILi2EEEDaS1_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_nt_autoMUlTnDavE_clILi0EEEDav:} } } +// { dg-final { scan-assembler {_ZNK9l_tpl_tplMUlTtTyTnjER3TPLIT_EE_clI1UEEDaS3_:} } } +// { dg-final { scan-assembler {_ZNK13l_tpl_tpl_tplMUlTtTtTyTnjEER6TPLTPLIT_EE_clI3TPLEEDaS3_:} } } +// { dg-final { scan-assembler {_ZNK5l_varMUlTpTyDpT_E_clIJiiiEEEDaS1_:} } } + +// { FIXMEdg-final { scan-assembler {_ZNK6l_var2MUlTpTniDpRAT__iE_clIJLi2ELi2EEEEDaS2_:} } } + +// { dg-final { scan-assembler {_ZNK6l_var3MUlTtTpTniETpTniRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS2_:} } } + +// { dg-final { scan-assembler {_ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US7_EEEDaS4_:} } } +// This is a different mangling to clang, which gets +// _ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US6_EEEDaS3_ +// However, I think that is incorrect -- it doesn't demangle as +// expected (using the llvm demangler). +// https://github.com/llvm/llvm-project/issues/58631 + +// { dg-final { scan-assembler {_ZZ2FnILi1EEvvENKUlTyT_E_clIiEEDaS0_:} } } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C new file mode 100644 index 0000000..8bead73 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1-18vs17.C @@ -0,0 +1,16 @@ +// { dg-do compile { target c++20 } } +// { dg-options {-fabi-version=18 -Wabi=17} } + +#include "lambda-tpl1.h" + +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZZ2FnILi1EEvvENKUlT_E_clIiEEDaS0_'\) and '-fabi-version=18' \('_ZZ2FnILi1EEvvENKUlTyT_E_clIiEEDaS0_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK6l_var4MUlR1YIJDpT_EEE_clIJ1US6_EEEDaS3_'\) and '-fabi-version=18' \('_ZNK6l_var4MUlTpTtTyTnjER1YIJDpT_EEE_clIJ1US7_EEEDaS4_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK6l_var3MUlRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS1_'\) and '-fabi-version=18' \('_ZNK6l_var3MUlTtTpTniETpTniRT_IJXspT0_EEEE_clI1XJLi1ELi2ELi3EEEEDaS2_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK5l_varMUlDpT_E_clIJiiiEEEDaS0_'\) and '-fabi-version=18' \('_ZNK5l_varMUlTpTyDpT_E_clIJiiiEEEDaS1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK13l_tpl_tpl_tplMUlR6TPLTPLIT_EE_clI3TPLEEDaS2_'\) and '-fabi-version=18' \('_ZNK13l_tpl_tpl_tplMUlTtTtTyTnjEER6TPLTPLIT_EE_clI3TPLEEDaS3_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK9l_tpl_tplMUlR3TPLIT_EE_clI1UEEDaS2_'\) and '-fabi-version=18' \('_ZNK9l_tpl_tplMUlTtTyTnjER3TPLIT_EE_clI1UEEDaS3_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK13l_tpl_nt_autoMUlvE_clILi0EEEDav'\) and '-fabi-version=18' \('_ZNK13l_tpl_nt_autoMUlTnDavE_clILi0EEEDav'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK12l_tpl_nt_aryMUlRAT__iE_clILi2EEEDaS0_'\) and '-fabi-version=18' \('_ZNK12l_tpl_nt_aryMUlTniRAT__iE_clILi2EEEDaS1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK10l_tpl_autoMUlT_T0_E_clIiiEEDaS_S0_'\) and '-fabi-version=18' \('_ZNK10l_tpl_autoMUlTyT_T0_E_clIiiEEDaS0_S1_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK5l_tplMUlT_E_clIiEEDaS_'\) and '-fabi-version=18' \('_ZNK5l_tplMUlTyT_E_clIiEEDaS0_'\) [^\n]*\n} } +// { dg-regexp {[^\n]*lambda-tpl1.h:[:0-9]* warning: the mangled name [^\n]* \('_ZNK6l_autoMUlT_E_clIiEEDaS_'\) and '-fabi-version=18' \('_ZNK6l_autoMUlT_E_clIiEEDaS0_'\) [^\n]*\n} } diff --git a/gcc/testsuite/g++.dg/abi/lambda-tpl1.h b/gcc/testsuite/g++.dg/abi/lambda-tpl1.h new file mode 100644 index 0000000..5d6fe5e --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/lambda-tpl1.h @@ -0,0 +1,59 @@ +inline auto l_auto = [] (auto) {}; + +inline auto l_tpl = [] <typename T> (T) {}; + +inline auto l_tpl_auto = [] <typename T> (T, auto) {}; + +inline auto l_tpl_nt_ary = [] <int I> (int (&)[I]) {}; + +inline auto l_tpl_nt_auto = [] <auto I = 0> () {}; + +template<typename T, unsigned I> class U; + +template<template<typename, unsigned> typename> class TPL {}; +inline auto l_tpl_tpl = [] <template<typename, unsigned> typename T> (TPL<T> &) {}; + +template<template<template<typename, unsigned> typename> typename> class TPLTPL {}; +inline auto l_tpl_tpl_tpl = []<template<template<typename, unsigned> typename> typename T> (TPLTPL<T> &) {}; + +inline auto l_var = []<typename... Args> (Args...) {}; + +#if FIXME // we fail to parse (&...) correctly +inline auto l_var2 = []<int... I> (int (&...)[I]) {}; +#endif + +template<int...I> class X {}; +inline auto l_var3 = []<template<int...> typename T, int...I> (T<I...> &a) {}; + +template<template<typename, unsigned> typename...T> class Y{}; +inline auto l_var4 = []<template<typename, unsigned> typename... T> (Y<T...> &a) {}; + +template<int I> inline void Fn () +{ + auto l = []<typename T> (T) {}; + l (1); +} + +void f () +{ + l_auto (1); + l_tpl (1); + l_tpl_auto (1, 1); + int ary[2]; + l_tpl_nt_ary (ary); + l_tpl_nt_auto (); + TPL<U> v; + l_tpl_tpl (v); + TPLTPL<TPL> u; + l_tpl_tpl_tpl (u); + l_var (1, 2, 3); +#if FIXME + l_var2 (ary, ary); +#endif + X<1,2,3> x; + l_var3 (x); + Y<U,U> y; + l_var4 (y); + + Fn<1> (); +} diff --git a/gcc/testsuite/g++.dg/cpp23/elision4.C b/gcc/testsuite/g++.dg/cpp23/elision4.C index c19b86b..d39053a 100644 --- a/gcc/testsuite/g++.dg/cpp23/elision4.C +++ b/gcc/testsuite/g++.dg/cpp23/elision4.C @@ -1,5 +1,6 @@ // PR c++/101165 - P2266R1 - Simpler implicit move // { dg-do compile { target c++23 } } +// { dg-options "-Wdangling-reference" } // Test from P2266R1, $ 5.2. LibreOffice OString constructor. struct X { @@ -33,6 +34,6 @@ T& temporary2(T&& x) { return static_cast<T&>(x); } void test () { - int& r1 = temporary1 (42); - int& r2 = temporary2 (42); + int& r1 = temporary1 (42); // { dg-warning "dangling reference" } + int& r2 = temporary2 (42); // { dg-warning "dangling reference" } } diff --git a/gcc/testsuite/g++.dg/cpp23/elision7.C b/gcc/testsuite/g++.dg/cpp23/elision7.C index 19fa89a..0045842 100644 --- a/gcc/testsuite/g++.dg/cpp23/elision7.C +++ b/gcc/testsuite/g++.dg/cpp23/elision7.C @@ -1,5 +1,6 @@ // PR c++/101165 - P2266R1 - Simpler implicit move // { dg-do compile { target c++23 } } +// { dg-options "-Wdangling-reference" } struct X { X (); @@ -68,5 +69,5 @@ f7 (T &&t) void do_f7 () { - const int &x = f7 (0); + const int &x = f7 (0); // { dg-warning "dangling reference" } } diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C new file mode 100644 index 0000000..627e8a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops2.C @@ -0,0 +1,26 @@ +// PR c++/107382 +// PR c++/107383 +// { dg-do compile } +// { dg-options "-O2 -fexcess-precision=standard" } + +void +foo () +{ + float t[2] = { 1, 2 }; + int const *s = 0; + t[1] / s; // { dg-error "invalid operands of types 'float' and 'const int\\\*' to binary 'operator/'" } +} + +void +bar () +{ + float t[2] = { 1, 2 }; + int const *s[2] = { 0, 0 }; + t[1] / s[0]; // { dg-error "invalid operands of types 'float' and 'const int\\\*' to binary 'operator/'" } +} + +void +baz (float a, int* b) +{ + a -= b; // { dg-error "invalid operands of types 'float' and 'int\\\*' to binary 'operator-'" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C index 151418f..802ac9c 100644 --- a/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C +++ b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-2.C @@ -1,5 +1,5 @@ /* { dg-do compile } - { dg-options "-O1 -Wall -Wno-class-memaccess" } */ + { dg-options "-O1 -Wall -Wno-class-memaccess -Wno-dangling-reference" } */ struct A { A (); }; diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C new file mode 100644 index 0000000..97c81ee --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference1.C @@ -0,0 +1,144 @@ +// PR c++/106393 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } + +const int& f(const int& i) { return i; } +const int& f_(const int& i) { return i; } +const int& h(int); +const int& rp(const int *); +int g; +const int& globref(const int&) { return g; } +struct X { + int* i; + operator const int&() const { return *i; } +}; +X x{&g}; + +const int& r1 = f(10); // { dg-warning "dangling reference" } +// r2 = _ZGR2r2_ = (int) *f ((const int &) &TARGET_EXPR <D.2429, 10>) + 1; (const int &) &_ZGR2r2_ +const int& r2 = f(10) + 1; +// Don't warn here, we have +// r3 = f (X::operator const int& (&x)) +const int& r3 = f(x); +// Don't warn here, because we've seen the definition of globref +// and could figure out that it may not return one of its parms. +// Questionable -- it can also hide bugs --, but it helps here. +const int& r4 = globref(1); +const int& r5 = (42, f(10)); // { dg-warning "dangling reference" } +const int& r6 = (f(10), 42); +const int& r7 = (f(10)); // { dg-warning "dangling reference" } +const int& r8 = g ? f(10) : f(9); // { dg-warning "dangling reference" } +const int& r9 = (42, g ? f(10) : f(9)); // { dg-warning "dangling reference" } +const int& r10 = (g ? f(10) : f(9), 42); +// Binds to a reference temporary for r11. No dangling reference. +const int& r11 = g ? f(10) : 9; +const int& r12 = g ? 9 : f(10); +// r12 = f (f ((const int &) &TARGET_EXPR <D.2459, 1>)) +const int& r13 = f(f(1)); // { dg-warning "dangling reference" } +const int& r14 = f(f_(1)); // { dg-warning "dangling reference" } +const int& r15 = f(g ? f(1) : f(2)); // { dg-warning "dangling reference" } +const int& r16 = f(*&f(1)); // { dg-warning "dangling reference" } +const int& r17 = rp(&f(1)); +const int& r18 = rp(&f(g)); +const int& r19 = h(f(1)); +// Other forms of initializers. +const int& r20(f(10)); // { dg-warning "dangling reference" } +const int& r21(f(10)); // { dg-warning "dangling reference" } +// Returns a ref, but doesn't have a parameter of reference type. +const int& r22 = h(10); +const int& r23 = g ? h(10) : f(10); // { dg-warning "dangling reference" } +const int& r24 = g ? f(10) : h(10); // { dg-warning "dangling reference" } +const int& r25 = g ? h(10) : (1, f(10)); // { dg-warning "dangling reference" } +const int& r26 = g ? (1, f(10)) : h(10); // { dg-warning "dangling reference" } +const int& r29 = f((f_(1), 1)); // { dg-warning "dangling reference" } +const int& r30 = f((f_(1), g)); + +struct Z { + operator int() { return 42; } +}; + +const int& r27 = f(Z()); // { dg-warning "dangling reference" } +const int& r28 = f(true ? Z() : Z()); // { dg-warning "dangling reference" } + +const int& operator|(const int &, Z); +const int& r31 = 1 | Z(); // { dg-warning "dangling reference" } + +// OK: the reference is bound to the 10 so still valid at the point +// where it's copied into i1. +int i1 = f(10); + +int +test1 () +{ + const int &lr = f(10); // { dg-warning "dangling reference" } + int i2 = f(10); + return lr; +} + +struct B { }; +struct D : B { }; +struct C { + D d; +}; + +C c; +D d; + +using U = D[3]; + +const B& frotz(const D&); +const B& b1 = frotz(C{}.d); // { dg-warning "dangling reference" } +const B& b2 = frotz(D{}); // { dg-warning "dangling reference" } +const B& b3 = frotz(c.d); +const B& b4 = frotz(d); +const B& b5 = frotz(U{}[0]); // { dg-warning "dangling reference" } + +// Try returning a subobject. +const B& bar (const D& d) { return d; } +const B& b6 = bar (D{}); // { dg-warning "dangling reference" } +const B& baz (const C& c) { return c.d; } +const B& b7 = baz (C{}); // { dg-warning "dangling reference" } +const D& qux (const C& c) { return c.d; } +const D& d1 = qux (C{}); // { dg-warning "dangling reference" } + +struct E { + E(int); +}; +const E& operator*(const E&); +const E& b8 = *E(1); // { dg-warning "dangling reference" } + +struct F : virtual B { }; +struct G : virtual B { }; +struct H : F, G { }; +const B& yum (const F& f) { return f; } +const B& b9 = yum (F{}); // { dg-warning "dangling reference" } +const B& lox (const H& h) { return h; } +const B& b10 = lox (H{}); // { dg-warning "dangling reference" } + +struct S { + const int &r; // { dg-warning "dangling reference" } + S() : r(f(10)) { } // { dg-message "destroyed" } +}; + +// From cppreference. +template<class T> +const T& max(const T& a, const T& b) +{ + return (a < b) ? b : a; +} + +int n = 1; +const int& refmax = max(n - 1, n + 1); // { dg-warning "dangling reference" } + +struct Y { + operator int&(); + operator int&&(); + const int& foo(const int&); +}; + +// x1 = Y::operator int&& (&TARGET_EXPR <D.2410, {}>) +int&& x1 = Y(); // { dg-warning "dangling reference" } +int&& x2 = Y{}; // { dg-warning "dangling reference" } +int& x3 = Y(); // { dg-warning "dangling reference" } +int& x4 = Y{}; // { dg-warning "dangling reference" } +const int& t1 = Y().foo(10); // { dg-warning "dangling reference" } diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C new file mode 100644 index 0000000..dafdb43 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference2.C @@ -0,0 +1,28 @@ +// PR c++/106393 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } + +namespace std { +struct any {}; +template <typename _ValueType> _ValueType any_cast(any &&); +template <typename _Tp> struct remove_reference { using type = _Tp; }; +template <typename _Tp> _Tp forward(typename remove_reference<_Tp>::type); +template <typename _Tp> typename remove_reference<_Tp>::type move(_Tp); +} // namespace std + +const int &r = std::any_cast<int&>(std::any()); // { dg-warning "dangling reference" } + +template <class T> struct C { + T t_; // { dg-warning "dangling reference" } + C(T); + template <class U> C(U c) : t_(std::forward<T>(c.t_)) {} +}; +struct A {}; +struct B { + B(A); +}; +int main() { + A a; + C<A> ca(a); + C<B &&>(std::move(ca)); +} diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C new file mode 100644 index 0000000..4bc20c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference3.C @@ -0,0 +1,24 @@ +// PR c++/106393 +// { dg-do compile { target c++11 } } +// { dg-options "-Wdangling-reference" } + +struct A { + int ar[4]; + int& operator[](int i) { return ar[i]; } +}; +const int &r = A()[2]; // { dg-warning "dangling reference" } + +struct S { + const S& self () { return *this; } +}; +const S& s = S().self(); // { dg-warning "dangling reference" } + +struct G { + const G& g() { return *this; } +}; + +struct F { + G& f(); +}; + +const G& g = F().f().g(); // { dg-warning "dangling reference" } diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-3.c b/gcc/testsuite/gcc.dg/analyzer/fd-3.c index 55e84e3..8e71b14 100644 --- a/gcc/testsuite/gcc.dg/analyzer/fd-3.c +++ b/gcc/testsuite/gcc.dg/analyzer/fd-3.c @@ -50,9 +50,9 @@ test_5 (char *path, void *buf) int flags = O_RDONLY; if (some_condition()) flags |= O_NOATIME; - int fd = open (path, flags); + int fd = open (path, flags); /* { dg-message "\\(1\\) opened here" } */ read (fd, buf, 1); /* { dg-warning "'read' on possibly invalid file descriptor 'fd'" } */ - /* { dg-message "\\(1\\) 'fd' could be invalid" "" { target *-*-* } .-1 } */ + /* { dg-message "\\(2\\) 'fd' could be invalid" "" { target *-*-* } .-1 } */ close (fd); } @@ -82,4 +82,16 @@ test_7 (char *path, void *buf) } close(fd); -}
\ No newline at end of file +} + +void +test_read_from_symbolic_fd (int fd, void *buf) +{ + read (fd, buf, 1); +} + +void +test_write_to_symbolic_fd (int fd, void *buf) +{ + write (fd, buf, 1); +} diff --git a/gcc/testsuite/gcc.dg/c11-enum-4.c b/gcc/testsuite/gcc.dg/c11-enum-4.c new file mode 100644 index 0000000..57dd92a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-enum-4.c @@ -0,0 +1,7 @@ +/* Test C2x enumerations with fixed underlying type are diagnosed for C11. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors" } */ + +enum e1 : int; /* { dg-error "ISO C does not support specifying 'enum' underlying types" } */ +enum e2 : short { A }; /* { dg-error "ISO C does not support specifying 'enum' underlying types" } */ +enum : short { B }; /* { dg-error "ISO C does not support specifying 'enum' underlying types" } */ diff --git a/gcc/testsuite/gcc.dg/c11-enum-5.c b/gcc/testsuite/gcc.dg/c11-enum-5.c new file mode 100644 index 0000000..91d681f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-enum-5.c @@ -0,0 +1,7 @@ +/* Test C2x enumerations with fixed underlying type are diagnosed for C11. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic" } */ + +enum e1 : int; /* { dg-warning "ISO C does not support specifying 'enum' underlying types" } */ +enum e2 : short { A }; /* { dg-warning "ISO C does not support specifying 'enum' underlying types" } */ +enum : short { B }; /* { dg-warning "ISO C does not support specifying 'enum' underlying types" } */ diff --git a/gcc/testsuite/gcc.dg/c11-enum-6.c b/gcc/testsuite/gcc.dg/c11-enum-6.c new file mode 100644 index 0000000..cd708bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-enum-6.c @@ -0,0 +1,8 @@ +/* Test C2x enumerations with fixed underlying type are not diagnosed for C11 + with -pedantic-errors -Wno-c11-c2x-compat. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11 -pedantic-errors -Wno-c11-c2x-compat" } */ + +enum e1 : int; +enum e2 : short { A }; +enum : short { B }; diff --git a/gcc/testsuite/gcc.dg/c2x-enum-6.c b/gcc/testsuite/gcc.dg/c2x-enum-6.c new file mode 100644 index 0000000..5ab9694 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-6.c @@ -0,0 +1,167 @@ +/* Test C2x enumerations with fixed underlying type. Valid code. */ +/* { dg-do run } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +/* Check a type while defining an enum (via a diagnostic for incompatible + pointer types if the wrong type was chosen). */ +#define TYPE_CHECK(cst, type) \ + cst ## _type_check = sizeof (1 ? (type *) 0 : (typeof (cst) *) 0) + +extern int i; + +enum e1 : short { e1a = __SHRT_MAX__, + TYPE_CHECK (e1a, short), + e1z = (long long) 0, + TYPE_CHECK (e1z, enum e1), + e1b = -__SHRT_MAX__ - 1, + e1c, + TYPE_CHECK (e1c, enum e1) }; +extern enum e1 e1v; +extern typeof (e1a) e1v; +extern typeof (e1b) e1v; +extern typeof (e1c) e1v; +extern typeof (e1z) e1v; +extern short e1v; +static_assert (e1a == __SHRT_MAX__); +static_assert (e1b == -__SHRT_MAX__ - 1); +static_assert (e1c == -__SHRT_MAX__); +static_assert (e1a > 0); +static_assert (e1b < 0); +static_assert (e1c < 0); +static_assert (e1z == 0); +extern typeof (+e1v) i; +extern typeof (+e1a) i; +extern typeof (e1a + e1b) i; +enum e1 : short; +enum e1 : volatile short; +enum e1 : _Atomic short; +enum e1 : typeof (short); + +enum e2 : bool { b0, b1, b0a = 0, b1a = 1 }; +extern enum e2 e2v; +extern typeof (b0) e2v; +extern typeof (b0a) e2v; +extern typeof (b1) e2v; +extern typeof (b1a) e2v; +extern bool e2v; +extern typeof (+e2v) i; +extern typeof (+b0) i; +static_assert (b0 == 0); +static_assert (b1 == 1); +static_assert (b0a == 0); +static_assert (b1a == 1); + +enum e3 : volatile const _Atomic unsigned short; +enum e3 : unsigned short { e3a, e3b }; +extern enum e3 e3v; +extern typeof (e3a) e3v; +extern typeof (e3b) e3v; +extern unsigned short e3v; + +/* The enum type is complete from the end of the first enum type specifier + (which is nested inside another enum type specifier in this example). */ +enum e4 : typeof ((enum e4 : long { e4a = sizeof (enum e4) })0, 0L); +extern enum e4 e4v; +extern typeof (e4a) e4v; +extern long e4v; + +enum e5 : unsigned int; +extern enum e5 e5v; +extern typeof (e5v + e5v) e5v; +extern unsigned int e5v; + +enum : unsigned short { e6a, e6b, TYPE_CHECK (e6a, unsigned short) } e6v; +extern typeof (e6a) e6v; +extern typeof (e6b) e6v; +extern unsigned short e6v; + +struct s1; +struct s2 { int a; }; +union u1; +union u2 { int a; }; +enum xe1 { XE1 }; +enum xe2 : long long { XE2 }; +enum xe3 : unsigned long; + +void +f () +{ + /* Tags can be redeclared in an inner scope. */ + enum s1 : char; + enum s2 : int { S2 }; + enum u1 : long { U1 }; + enum u2 : unsigned char; + enum xe1 : long long; + enum xe2 : short; + enum xe3 : char { XE3 }; + static_assert (sizeof (enum xe3) == 1); + static_assert (sizeof (enum xe2) == sizeof (short)); + static_assert (sizeof (enum xe1) == sizeof (long long)); +} + +void *p; +typeof (nullptr) np; + +extern void abort (void); +extern void exit (int); + +int +main () +{ + /* Conversions to enums with fixed underlying type have the same semantics as + converting to the underlying type. */ + volatile enum e1 e1vm; + volatile enum e2 e2vm; + e1vm = __LONG_LONG_MAX__; /* { dg-warning "overflow" } */ + if (e1vm != (short) __LONG_LONG_MAX__) + abort (); + e2vm = 10; + if (e2vm != 1) + abort (); + e2vm = 0; + if (e2vm != 0) + abort (); + /* Arithmetic on enums with fixed underlying type has the same semantics as + arithmetic on the underlying type; in particular, the special semantics + for bool apply to enums with bool as fixed underlying type. */ + if (e2vm++ != 0) + abort (); + if (e2vm != 1) + abort (); + if (e2vm++ != 1) + abort (); + if (e2vm != 1) + abort (); + if (e2vm-- != 1) + abort (); + if (e2vm != 0) + abort (); + if (e2vm-- != 0) + abort (); + if (e2vm != 1) + abort (); + if (++e2vm != 1) + abort (); + if (e2vm != 1) + abort (); + e2vm = 0; + if (++e2vm != 1) + abort (); + if (e2vm != 1) + abort (); + if (--e2vm != 0) + abort (); + if (e2vm != 0) + abort (); + if (--e2vm != 1) + abort (); + if (e2vm != 1) + abort (); + e2vm = p; + e2vm = np; + e2vm = (bool) p; + e2vm = (bool) np; + if (e2vm != 0) + abort (); + exit (0); +} diff --git a/gcc/testsuite/gcc.dg/c2x-enum-7.c b/gcc/testsuite/gcc.dg/c2x-enum-7.c new file mode 100644 index 0000000..08bae31 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-7.c @@ -0,0 +1,97 @@ +/* Test C2x enumerations with fixed underlying type. Invalid code. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +/* An enum type specifier may only be used when the enum is defined, or in a + declaration of the form "enum name enum-type-specifier;". */ +extern enum e1 : int; /* { dg-error "storage class specifier in empty declaration with 'enum' underlying type" } */ +_Thread_local enum e2 : short; /* { dg-error "'_Thread_local' in empty declaration with 'enum' underlying type" } */ +const enum e3 : long; /* { dg-error "type qualifier in empty declaration with 'enum' underlying type" } */ +alignas (8) enum e4 : long; /* { dg-error "'alignas' in empty declaration with 'enum' underlying type" } */ +inline enum e5 : unsigned; /* { dg-error "'inline' in empty declaration" } */ +_Noreturn enum e6 : unsigned; /* { dg-error "'_Noreturn' in empty declaration" } */ +auto enum e7 : unsigned; /* { dg-error "'auto' in file-scope empty declaration" } */ +register enum e8 : unsigned; /* { dg-error "'register' in file-scope empty declaration" } */ + +/* When the enum is defined, some extra declaration specifiers are permitted, + but diagnosed as useless. */ +extern enum e9 : int { E9 }; /* { dg-warning "useless storage class specifier in empty declaration" } */ +_Thread_local enum e10 : short { E10 }; /* { dg-warning "useless '_Thread_local' in empty declaration" } */ +const enum e11 : long { E11 }; /* { dg-warning "useless type qualifier in empty declaration" } */ +alignas (8) enum e12 : long { E12 }; /* { dg-warning "useless '_Alignas' in empty declaration" } */ + +/* Nothing else may be declared with an enum type specifier for an enum not + being defined in that declaration. */ +enum e13 : short x13; /* { dg-error "'enum' underlying type may not be specified here" } */ +enum e14 : short f14 (); /* { dg-error "'enum' underlying type may not be specified here" } */ +typeof (enum e15 : long) x15; /* { dg-error "'enum' underlying type may not be specified here" } */ +int f16 (enum e16 : char p); /* { dg-error "'enum' underlying type may not be specified here" } */ +/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */ +int f17 (enum e17 : char); /* { dg-error "'enum' underlying type may not be specified here" } */ +/* { dg-warning "will not be visible outside of this definition or declaration" "warning" { target *-*-* } .-1 } */ +struct s18 { enum e18 : int x; }; /* { dg-error "'enum' underlying type may not be specified here" } */ + +/* But those are OK if the enum content is defined. */ +enum e19 : short { E19 } x19; +enum e20 : long { E20 } f20 (); +typeof (enum e21 : long { E21 }) x21; +int f22 (enum e22 : long long { E22 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */ +int f23 (enum e23 : long long { E23 } p); /* { dg-warning "will not be visible outside of this definition or declaration" } */ +struct s24 { enum e24 : int { E24 } x; }; + +/* Incompatible kinds of tags in the same scope are errors. */ +struct s25; +enum s25 : int; /* { dg-error "wrong kind of tag" } */ +struct s26; +enum s26 : int { E26 }; /* { dg-error "wrong kind of tag" } */ +struct s27 { int x; }; +enum s27 : int; /* { dg-error "wrong kind of tag" } */ +struct s28 { int x; }; +enum s28 : int { E28 }; /* { dg-error "wrong kind of tag" } */ +union u29; +enum u29 : int; /* { dg-error "wrong kind of tag" } */ +union u30; +enum u30 : int { E30 }; /* { dg-error "wrong kind of tag" } */ +union u31 { int x; }; +enum u31 : int; /* { dg-error "wrong kind of tag" } */ +union u32 { int x; }; +enum u32 : int { E32 }; /* { dg-error "wrong kind of tag" } */ + +/* If an enum has a fixed underlying type, that must be given when defining the + enum. */ +enum e33 : short; +enum e33 { E33 }; /* { dg-error "'enum' declared with but defined without fixed underlying type" } */ + +/* An enum defined without a fixed underlying type cannot then be declared with + one. */ +enum e34 { E34A = -__INT_MAX__, E34B = __INT_MAX__ }; +enum e34 : int; /* { dg-error "'enum' declared both with and without fixed underlying type" } */ + +/* An enum with a fixed underlying type cannot be declared with an incompatible + fixed underlying type. */ +enum e35 : int; +enum e35 : unsigned int; /* { dg-error "'enum' underlying type incompatible with previous declaration" } */ +enum e36 : int; +enum e36 : unsigned int { E36 }; /* { dg-error "'enum' underlying type incompatible with previous declaration" } */ +enum e37 : unsigned int { E37 }; +enum e37 : int; /* { dg-error "'enum' underlying type incompatible with previous declaration" } */ + +/* Enumeration constants must fit in the fixed underlying type. */ +enum e38 : unsigned char { E38 = (unsigned long long)((unsigned char) -1) + 1 }; /* { dg-error "enumerator value outside the range of underlying type" } */ +enum e39 : unsigned int { E39 = -1 }; /* { dg-error "enumerator value outside the range of underlying type" } */ +enum e40 : int { E40 = __INT_MAX__, E40A }; /* { dg-error "overflow in enumeration values" } */ +enum e41 : unsigned int { E41 = (unsigned int) -1, E41A }; /* { dg-error "overflow in enumeration values" } */ +enum e42 : bool { E42 = 2 }; /* { dg-error "enumerator value outside the range of underlying type" } */ +enum e43 : bool { E43 = 1, E43A }; /* { dg-error "overflow in enumeration values" } */ + +/* The underlying type must be an integer type, not itself an enum (or + bit-precise) type. */ +enum e44 : double; /* { dg-error "invalid 'enum' underlying type" } */ +typedef int T; +enum e45 : T; +typedef int *TP; +enum e46 : TP; /* { dg-error "invalid 'enum' underlying type" } */ +enum e47 : enum e45; /* { dg-error "invalid 'enum' underlying type" } */ +enum e48 : const; /* { dg-error "no 'enum' underlying type specified" } */ +/* 'restrict' is not valid on integer types. */ +enum e49 : int restrict; /* { dg-error "invalid use of 'restrict'" } */ diff --git a/gcc/testsuite/gcc.dg/c2x-enum-8.c b/gcc/testsuite/gcc.dg/c2x-enum-8.c new file mode 100644 index 0000000..f7757fc --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-enum-8.c @@ -0,0 +1,7 @@ +/* Test C2x enumerations with fixed underlying type. Test -Wc11-c2x-compat + warnings. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors -Wc11-c2x-compat" } */ + +enum e1 : int; /* { dg-warning "ISO C does not support specifying 'enum' underlying types before" } */ +enum e2 : short { E2 }; /* { dg-warning "ISO C does not support specifying 'enum' underlying types before" } */ diff --git a/gcc/testsuite/gcc.dg/gnu2x-enum-1.c b/gcc/testsuite/gcc.dg/gnu2x-enum-1.c new file mode 100644 index 0000000..b72ed73 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-enum-1.c @@ -0,0 +1,11 @@ +/* Test C2x enumerations with fixed underlying type together with GNU + extensions: an enum cannot be forward declared without a fixed underlying + type and then declared or defined with one. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu2x" } */ + +enum e1; +enum e1 : int; /* { dg-error "'enum' declared both with and without fixed underlying type" } */ + +enum e2; +enum e2 : long { A }; /* { dg-error "'enum' declared both with and without fixed underlying type" } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr107394.c b/gcc/testsuite/gcc.dg/tree-ssa/pr107394.c new file mode 100644 index 0000000..0e1e5ac --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr107394.c @@ -0,0 +1,22 @@ +// { dg-do compile } +// { dg-options "-O2" } + +static double +quux (double x) +{ + return __builtin_fabs (x); +} + +__attribute__ ((flatten, optimize ("-ffinite-math-only"))) static int +bar (int *p) +{ + *p = quux (0.0); + + return 0; +} + +void +foo (int *p) +{ + (void) bar (p); +} diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c b/gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c index 1f5c621..ccb4ef6 100644 --- a/gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c +++ b/gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c @@ -46,6 +46,6 @@ int main () } /* { dg-final { scan-tree-dump {(no need for alias check [^\n]* when VF is 1|no alias between [^\n]* when [^\n]* is outside \(-16, 16\))} "vect" { target vect_element_align } } } */ -/* { dg-final { scan-tree-dump-times "loop vectorized" 1 "vect" { target { vect_element_align && !amdgcn-*-* } } } } */ +/* { dg-final { scan-tree-dump-times "loop vectorized" 1 "vect" { target { vect_element_align && { ! amdgcn-*-* } } } } } */ /* { dg-final { scan-tree-dump-times "loop vectorized" 2 "vect" { target amdgcn-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-1.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-1.c index 01cf34f..42e50d9 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-1.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-1.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-2.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-2.c index 1a4a157..a9aeefc 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-2.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-2.c @@ -1,4 +1,5 @@ -/* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ +/* { dg-require-effective-target vect_long_long } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-3.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-3.c index 849f4a0..c7d0fd2 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-3.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-3.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-4.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-4.c index 5bc9c41..6a3ed8c 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-4.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-4.c @@ -1,4 +1,5 @@ -/* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ +/* { dg-require-effective-target vect_long_long } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-5.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-5.c index 1dc24d3..b2889df 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-5.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-5.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-6.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-6.c index 7d24c29..2445f53 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-6.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-6.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-7.c b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-7.c index 3b505db..4b1ec8a 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-7.c +++ b/gcc/testsuite/gcc.dg/vect/vect-bitfield-read-7.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target vect_int } */ +/* { dg-require-effective-target vect_shift } */ #include <stdarg.h> #include "tree-vect.h" diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c new file mode 100644 index 0000000..2c67c38 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-1.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct F { + int bar; + char c; + int baz; + int arr[]; +}; + +enum { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE = 1, +}; + +unsigned int test (struct F *f) { + + unsigned x = __builtin_preserve_field_info (f->arr, FIELD_BYTE_SIZE); /* { dg-error "unsupported variable size field access" } */ + + unsigned y = __builtin_preserve_field_info (f->baz, 99); /* { dg-error "invalid second argument to built-in function" } */ + + return x + y; +} diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c new file mode 100644 index 0000000..31d7a03 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-errors-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct F { + int bar; + char c; + int baz; +}; + +enum { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE = 1, +}; + +int test (struct F *f) { + int a; + unsigned x = __builtin_preserve_field_info (({ a = f->bar + f->baz; }), FIELD_BYTE_OFFSET); /* { dg-error "argument is not a field access" } */ + + int b; + unsigned y = __builtin_preserve_field_info (&(f->c), FIELD_BYTE_SIZE); /* { dg-error "argument is not a field access" } */ + + return a + b + x + y; +} diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c new file mode 100644 index 0000000..c55f21a --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-existence-1.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +enum { + FIELD_EXISTENCE = 2, +}; + +typedef unsigned uint; + +struct S { + unsigned char c; + int d; + uint u; + short ar[3]; +}; + +unsigned int foo (struct S *s) +{ + unsigned c = __builtin_preserve_field_info (s->c, FIELD_EXISTENCE); + unsigned d = __builtin_preserve_field_info (s->d, FIELD_EXISTENCE); + unsigned u = __builtin_preserve_field_info (s->u, FIELD_EXISTENCE); + unsigned ar = __builtin_preserve_field_info (s->ar[1], FIELD_EXISTENCE); + + return c + d + u + ar; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 4 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x2\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c new file mode 100644 index 0000000..dabf73d --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-be.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re -mbig-endian" } */ + +struct S { + int x1: 6; + int x2: 3; + int x3: 7; + int x4: 16; +}; + +enum { + FIELD_LSHIFT_U64 = 4, +}; + +unsigned int foo (struct S *s) +{ + /* little endian: x1=58, x2=55, x3=48, x4=32 */ + /* big endian: x1=32, x2=38, x3=41, x4=48 */ + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_LSHIFT_U64); + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_LSHIFT_U64); + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_LSHIFT_U64); + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_LSHIFT_U64); + + return x1 + x2 + x3 + x4; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],38" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],41" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c new file mode 100644 index 0000000..99e3982 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-1-le.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re -mlittle-endian" } */ + +struct S { + int x1: 6; + int x2: 3; + int x3: 7; + int x4: 16; +}; + +enum { + FIELD_LSHIFT_U64 = 4, +}; + +unsigned int foo (struct S *s) +{ + /* little endian: x1=58, x2=55, x3=48, x4=32 */ + /* big endian: x1=32, x2=38, x3=41, x4=48 */ + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_LSHIFT_U64); + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_LSHIFT_U64); + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_LSHIFT_U64); + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_LSHIFT_U64); + + return x1 + x2 + x3 + x4; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],58" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],55" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c new file mode 100644 index 0000000..25be969 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-lshift-2.c @@ -0,0 +1,37 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + char c; + short s; + int x; +}; + +union U { + struct S s[2]; + long long ll; +}; + +enum { + FIELD_LSHIFT_U64 = 4, +}; + +unsigned int foo (union U *u) +{ + /* s0s = 48, s1c = 56, ll = 0; endianness independent. */ + unsigned s0s = __builtin_preserve_field_info (u->s[0].s, FIELD_LSHIFT_U64); + unsigned s1c = __builtin_preserve_field_info (u->s[1].c, FIELD_LSHIFT_U64); + unsigned ll = __builtin_preserve_field_info (u->ll, FIELD_LSHIFT_U64); + + return s0s + s1c + ll; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],56" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0:0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x4\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c new file mode 100644 index 0000000..590eea0 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-offset-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + unsigned int a1: 7; + unsigned int a2: 4; + unsigned int a3: 13; + unsigned int a4: 5; + int x; +}; + +struct T { + unsigned int y; + struct S s[2]; + char c; + char d; +}; + +enum { + FIELD_BYTE_OFFSET = 0, +}; + + +unsigned int foo (struct T *t) +{ + unsigned s0a1 = __builtin_preserve_field_info (t->s[0].a1, FIELD_BYTE_OFFSET); + unsigned s0a4 = __builtin_preserve_field_info (t->s[0].a4, FIELD_BYTE_OFFSET); + unsigned s0x = __builtin_preserve_field_info (t->s[0].x, FIELD_BYTE_OFFSET); + + unsigned s1a1 = __builtin_preserve_field_info (t->s[1].a1, FIELD_BYTE_OFFSET); + unsigned s1a4 = __builtin_preserve_field_info (t->s[1].a4, FIELD_BYTE_OFFSET); + unsigned s1x = __builtin_preserve_field_info (t->s[1].x, FIELD_BYTE_OFFSET); + + unsigned c = __builtin_preserve_field_info (t->c, FIELD_BYTE_OFFSET); + unsigned d = __builtin_preserve_field_info (t->d, FIELD_BYTE_OFFSET); + + return s0a1 + s0a4 + s0x + s1a1 + s1a4 + s1x + c + d; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],4" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],8" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],12" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],16" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],20" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],21" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:1:0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:0:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0\[\t \]+\[^\n\]*bpfcr_kind" 8 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c new file mode 100644 index 0000000..d0c75d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-1.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + int x1: 6; + int x2: 3; + int x3: 7; + int x4: 16; +}; + +enum { + FIELD_RSHIFT_U64 = 5, +}; + +unsigned int foo (struct S *s) +{ + /* x1=58, x2=61, x3=57, x4=48; endianness independent. */ + unsigned x1 = __builtin_preserve_field_info (s->x1, FIELD_RSHIFT_U64); + unsigned x2 = __builtin_preserve_field_info (s->x2, FIELD_RSHIFT_U64); + unsigned x3 = __builtin_preserve_field_info (s->x3, FIELD_RSHIFT_U64); + unsigned x4 = __builtin_preserve_field_info (s->x4, FIELD_RSHIFT_U64); + + return x1 + x2 + x3 + x4; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],58" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],61" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],57" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],48" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x5\[\t \]+\[^\n\]*bpfcr_kind" 4 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c new file mode 100644 index 0000000..a71ddc1 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-rshift-2.c @@ -0,0 +1,35 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + int x; + char c; +}; + +union U { + int i; + struct S s; +}; + +enum { + FIELD_RSHIFT_U64 = 5, +}; + +unsigned int foo (union U *u) +{ + /* sx = 32, sc = 56, i = 32; endianness independent. */ + unsigned sx = __builtin_preserve_field_info (u->s.x, FIELD_RSHIFT_U64); + unsigned sc = __builtin_preserve_field_info (u->s.c, FIELD_RSHIFT_U64); + unsigned i = __builtin_preserve_field_info (u->i, FIELD_RSHIFT_U64); + + return sx + sc + i; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],32" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],56" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x5\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c new file mode 100644 index 0000000..3b2081e --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +enum { + FIELD_SIGNEDNESS = 3, +}; + +typedef unsigned uint; + +struct S { + unsigned char c; + int d; + uint u; + short ar[3]; +}; + +unsigned int foo (struct S *s) +{ + unsigned d = __builtin_preserve_field_info (s->d, FIELD_SIGNEDNESS); + unsigned u = __builtin_preserve_field_info (s->u, FIELD_SIGNEDNESS); + unsigned ar = __builtin_preserve_field_info (s->ar[1], FIELD_SIGNEDNESS); + + return d + u + ar; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:3:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x3\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c new file mode 100644 index 0000000..bf18429 --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-sign-2.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +enum { + FIELD_SIGNEDNESS = 3, +}; + +enum Esig { + SA = -1, + SB, + SC, +}; + +enum Eun { + UA = 0, + UB, +}; + +struct S { + enum Esig sig : 3; + enum Eun un : 3; +}; + +union U { + int i; + struct S s; +}; + +unsigned int foo (union U *u) +{ + unsigned i = __builtin_preserve_field_info (u->i, FIELD_SIGNEDNESS); + unsigned sig = __builtin_preserve_field_info (u->s.sig, FIELD_SIGNEDNESS); + unsigned un = __builtin_preserve_field_info (u->s.un, FIELD_SIGNEDNESS); + + return i + sig + un; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],1" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],0" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "3\[\t \]+\[^\n\]*bpfcr_kind" 3 } } */ diff --git a/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c new file mode 100644 index 0000000..8747bde --- /dev/null +++ b/gcc/testsuite/gcc.target/bpf/core-builtin-fieldinfo-size-1.c @@ -0,0 +1,43 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -dA -gbtf -mco-re" } */ + +struct S { + unsigned int a1: 7; + unsigned int a2: 4; + unsigned int a3: 13; + unsigned int a4: 5; + char carr[5][3]; +}; + +enum { + FIELD_BYTE_SIZE = 1, +}; + +union U { + long long l[3]; + struct S s; +}; + +unsigned int foo (union U *u) +{ + unsigned ls = __builtin_preserve_field_info (u->l, FIELD_BYTE_SIZE); + unsigned s = __builtin_preserve_field_info (u->s, FIELD_BYTE_SIZE); + unsigned a2 = __builtin_preserve_field_info (u->s.a2, FIELD_BYTE_SIZE); + unsigned a3 = __builtin_preserve_field_info (u->s.a3, FIELD_BYTE_SIZE); + unsigned ca = __builtin_preserve_field_info (u->s.carr, FIELD_BYTE_SIZE); + + return ls + s + a2 + a3 + ca; +} + +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],24" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],20" 1 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],4" 2 } } */ +/* { dg-final { scan-assembler-times "\[\t \]mov\[\t \]%r\[0-9\],15" 1 } } */ + +/* { dg-final { scan-assembler-times "ascii \"0:0.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:1.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:2.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ +/* { dg-final { scan-assembler-times "ascii \"0:1:4.0\"\[\t \]+\[^\n\]*btf_aux_string" 1 } } */ + +/* { dg-final { scan-assembler-times "0x1\[\t \]+\[^\n\]*bpfcr_kind" 5 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr107172.c b/gcc/testsuite/gcc.target/i386/pr107172.c new file mode 100644 index 0000000..d2c85f3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr107172.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -ftree-vrp" } */ + +int a, c, d; +int +main() +{ + long e = 1; + int f = a = 1; +L1: + if (a) + a = 2; + int h = e = ~e; + c = -1; + if (e >= a) + goto L2; + if (-1 > a) + goto L1; + if (a) + f = -1; +L2: + d = (-f + d) & h; + if (d) + __builtin_abort(); + return 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c new file mode 100644 index 0000000..90172b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinx -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + return b; +} + +/* { dg-final { scan-assembler-not "fmv.h" } } */ +/* { dg-final { scan-assembler-times "mv" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c new file mode 100644 index 0000000..26f0119 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-2.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinx -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fadd.h fa" } } */ + /* { dg-final { scan-assembler-times "fadd.h a" 1 } } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c new file mode 100644 index 0000000..5739135 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinx-3.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinx -mabi=lp64 -O" } */ + +int foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fgt.h fa" } } */ + /* { dg-final { scan-assembler-times "fgt.h a" 1 } } */ + return a > b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c new file mode 100644 index 0000000..0070ebf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinxmin -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fmv.h" } } */ + /* { dg-final { scan-assembler-not "fmv.s" } } */ + /* { dg-final { scan-assembler-times "mv" 1 } } */ + return b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c new file mode 100644 index 0000000..17f45a9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64i_zhinxmin -mabi=lp64 -O" } */ + +_Float16 foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fadd.h" } } */ + /* { dg-final { scan-assembler-not "fadd.s fa" } } */ + /* { dg-final { scan-assembler-times "fadd.s a" 1 } } */ + return a + b; +} diff --git a/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c new file mode 100644 index 0000000..7a43641 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/_Float16-zhinxmin-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64if_zfhmin -mabi=lp64f -O" } */ + +int foo1 (_Float16 a, _Float16 b) +{ + /* { dg-final { scan-assembler-not "fgt.h" } } */ + /* { dg-final { scan-assembler-not "fgt.s fa" } } */ + /* { dg-final { scan-assembler-times "fgt.s a" 1 } } */ + return a > b; +} diff --git a/gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 b/gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 new file mode 100644 index 0000000..856cfa9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/illegal_boz_arg_4.f90 @@ -0,0 +1,13 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } +! PR fortran/103413 +! Contributed by G.Steinmetz + +program p + type t + class(*), allocatable :: a + end type + type(t) :: x + allocate (x%a, source=z'1') ! { dg-error "type incompatible" } + allocate (x%a, mold=z'1') ! { dg-error "type incompatible" } +end diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index 925bd7d..996700b 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-match.h" #include "dbgcnt.h" #include "tree-ssa-propagate.h" +#include "tree-ssa-dce.h" static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); static bool two_value_replacement (basic_block, basic_block, edge, gphi *, @@ -74,7 +75,6 @@ static bool cond_store_replacement (basic_block, basic_block, edge, edge, hash_set<tree> *); static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block); static hash_set<tree> * get_non_trapping (); -static void replace_phi_edge_with_variable (basic_block, edge, gphi *, tree); static void hoist_adjacent_loads (basic_block, basic_block, basic_block, basic_block); static bool gate_hoist_loads (void); @@ -402,7 +402,8 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads, bool early_p) static void replace_phi_edge_with_variable (basic_block cond_block, - edge e, gphi *phi, tree new_tree) + edge e, gphi *phi, tree new_tree, + bitmap dce_ssa_names = auto_bitmap()) { basic_block bb = gimple_bb (phi); gimple_stmt_iterator gsi; @@ -477,6 +478,8 @@ replace_phi_edge_with_variable (basic_block cond_block, gimple_cond_make_true (cond); } + simple_dce_from_worklist (dce_ssa_names); + statistics_counter_event (cfun, "Replace PHI with variable", 1); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -986,6 +989,7 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, gimple_seq seq = NULL; tree result; gimple *stmt_to_move = NULL; + auto_bitmap inserted_exprs; /* Special case A ? B : B as this will always simplify to B. */ if (operand_equal_for_phi_arg_p (arg0, arg1)) @@ -1060,14 +1064,22 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, gsi = gsi_last_bb (cond_bb); /* Insert the sequence generated from gimple_simplify_phiopt. */ if (seq) + { + // Mark the lhs of the new statements maybe for dce + gimple_stmt_iterator gsi1 = gsi_start (seq); + for (; !gsi_end_p (gsi1); gsi_next (&gsi1)) + { + gimple *stmt = gsi_stmt (gsi1); + tree name = gimple_get_lhs (stmt); + if (name && TREE_CODE (name) == SSA_NAME) + bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (name)); + } gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } - /* If there was a statement to move and the result of the statement - is going to be used, move it to right before the original - conditional. */ - if (stmt_to_move - && (gimple_assign_lhs (stmt_to_move) == result - || !has_single_use (gimple_assign_lhs (stmt_to_move)))) + /* If there was a statement to move, move it to right before + the original conditional. */ + if (stmt_to_move) { if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -1075,12 +1087,17 @@ match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, print_gimple_stmt (dump_file, stmt_to_move, 0, TDF_VOPS|TDF_MEMSYMS); } + + tree name = gimple_get_lhs (stmt_to_move); + // Mark the name to be renamed if there is one. + if (name && TREE_CODE (name) == SSA_NAME) + bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (name)); gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt_to_move); gsi_move_before (&gsi1, &gsi); reset_flow_sensitive_info (gimple_assign_lhs (stmt_to_move)); } - replace_phi_edge_with_variable (cond_bb, e1, phi, result); + replace_phi_edge_with_variable (cond_bb, e1, phi, result, inserted_exprs); /* Add Statistic here even though replace_phi_edge_with_variable already does it as we want to be able to count when match-simplify happens vs diff --git a/gcc/value-range-storage.cc b/gcc/value-range-storage.cc index 6e05462..462447b 100644 --- a/gcc/value-range-storage.cc +++ b/gcc/value-range-storage.cc @@ -261,17 +261,28 @@ frange_storage_slot::get_frange (frange &r, tree type) const { gcc_checking_assert (r.supports_type_p (type)); - r.set_undefined (); - r.m_kind = m_kind; - r.m_type = type; - r.m_min = m_min; - r.m_max = m_max; - r.m_pos_nan = m_pos_nan; - r.m_neg_nan = m_neg_nan; - r.normalize_kind (); - - if (flag_checking) - r.verify_range (); + // Handle explicit NANs. + if (m_kind == VR_NAN) + { + if (HONOR_NANS (type)) + { + if (m_pos_nan && m_neg_nan) + r.set_nan (type); + else + r.set_nan (type, m_neg_nan); + } + else + r.set_undefined (); + return; + } + + // Use the constructor because it will canonicalize the range. + r = frange (type, m_min, m_max, m_kind); + + // The constructor will set the NAN bits for HONOR_NANS, but we must + // make sure to set the NAN sign if known. + if (HONOR_NANS (type) && (m_pos_nan ^ m_neg_nan) == 1) + r.update_nan (m_neg_nan); } bool diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 77e5a2c..03b3c4b 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -4031,7 +4031,7 @@ range_tests_floats () r0.intersect (r1); ASSERT_TRUE (r0.undefined_p ()); - if (!flag_finite_math_only) + if (HONOR_INFINITIES (float_type_node)) { // Make sure [-Inf, -Inf] doesn't get normalized. r0 = frange_float ("-Inf", "-Inf"); |