From 2a1448f2763a72c83e2ec496f78243a975b0d44e Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 8 Aug 2022 09:07:23 +0200 Subject: [PATCH 01/16] lto/106540 - fix LTO tree input wrt dwarf2out_register_external_die I've revisited the earlier two workarounds for dwarf2out_register_external_die getting duplicate entries. It turns out that r11-525-g03d90a20a1afcb added dref_queue pruning to lto_input_tree but decl reading uses that to stream in DECL_INITIAL even when in the middle of SCC streaming. When that SCC then gets thrown away we can end up with debug nodes registered which isn't supposed to happen. The following adjusts the DECL_INITIAL streaming to go the in-SCC way, using lto_input_tree_1, since no SCCs are expected at this point, just refs. PR lto/106540 PR lto/106334 * dwarf2out.cc (dwarf2out_register_external_die): Restore original assert. * lto-streamer-in.cc (lto_read_tree_1): Use lto_input_tree_1 to input DECL_INITIAL, avoiding to commit drefs. --- gcc/dwarf2out.cc | 7 +------ gcc/lto-streamer-in.cc | 7 +++++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index cfea9cf6451..e3920c898f5 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -6069,12 +6069,7 @@ dwarf2out_register_external_die (tree decl, const char *sym, if (!external_die_map) external_die_map = hash_map::create_ggc (1000); - /* When we do tree merging during WPA or with -flto-partition=none we - can end up re-using GC memory as there's currently no way to unregister - external DIEs. Ideally we'd register them only after merging finished - but allowing override here is easiest. See PR106334. */ - gcc_checking_assert (!(in_lto_p && !flag_wpa) - || !external_die_map->get (decl)); + gcc_checking_assert (!external_die_map->get (decl)); sym_off_pair p = { IDENTIFIER_POINTER (get_identifier (sym)), off }; external_die_map->put (decl, p); } diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index fe5a4e7fe1d..a7dad70363f 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -1699,11 +1699,14 @@ lto_read_tree_1 (class lto_input_block *ib, class data_in *data_in, tree expr) /* Read all the pointer fields in EXPR. */ streamer_read_tree_body (ib, data_in, expr); - /* Read any LTO-specific data not read by the tree streamer. */ + /* Read any LTO-specific data not read by the tree streamer. Do not use + stream_read_tree here since that flushes the dref_queue in mids of + SCC reading. */ if (DECL_P (expr) && TREE_CODE (expr) != FUNCTION_DECL && TREE_CODE (expr) != TRANSLATION_UNIT_DECL) - DECL_INITIAL (expr) = stream_read_tree (ib, data_in); + DECL_INITIAL (expr) + = lto_input_tree_1 (ib, data_in, streamer_read_record_start (ib), 0); /* Stream references to early generated DIEs. Keep in sync with the trees handled in dwarf2out_register_external_die. */ From e6a8ae900b4141bbce1451da8f173d441662782d Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Mon, 8 Aug 2022 14:37:00 +0100 Subject: [PATCH 02/16] AArch64: Fix 128-bit sequential consistency atomic operations. The AArch64 implementation of 128-bit atomics is broken. For 128-bit atomics we rely on pthread barriers to correct guard the address in the pointer to get correct memory ordering. However for 128-bit atomics the address under the lock is different from the original pointer. This means that one of the values under the atomic operation is not protected properly and so we fail during when the user has requested sequential consistency as there's no barrier to enforce this requirement. As such users have resorted to adding an #ifdef GCC #endif around the use of these atomics. This corrects the issue by issuing a barrier only when __ATOMIC_SEQ_CST was requested. To remedy this performance hit I think we should revisit using a similar approach to out-line-atomics for the 128-bit atomics. Note that I believe I need the empty file due to the include_next chain but I am not entirely sure. I have hand verified that the barriers are inserted for atomic seq cst. libatomic/ChangeLog: PR target/102218 * config/aarch64/aarch64-config.h: New file. * config/aarch64/host-config.h: New file. --- libatomic/config/aarch64/aarch64-config.h | 23 ++++++++++++ libatomic/config/aarch64/host-config.h | 46 +++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 libatomic/config/aarch64/aarch64-config.h create mode 100644 libatomic/config/aarch64/host-config.h diff --git a/libatomic/config/aarch64/aarch64-config.h b/libatomic/config/aarch64/aarch64-config.h new file mode 100644 index 00000000000..d3474fa8ff8 --- /dev/null +++ b/libatomic/config/aarch64/aarch64-config.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of the GNU Atomic Library (libatomic). + + Libatomic is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libatomic 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + diff --git a/libatomic/config/aarch64/host-config.h b/libatomic/config/aarch64/host-config.h new file mode 100644 index 00000000000..f445a47d25e --- /dev/null +++ b/libatomic/config/aarch64/host-config.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of the GNU Atomic Library (libatomic). + + Libatomic is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libatomic 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Avoiding the DMB (or kernel helper) can be a good thing. */ +#define WANT_SPECIALCASE_RELAXED + +/* Glibc, at least, uses acq_rel in its pthread mutex + implementation. If the user is asking for seq_cst, + this is insufficient. */ + +static inline void __attribute__((always_inline, artificial)) +pre_seq_barrier(int model) +{ + if (model == __ATOMIC_SEQ_CST) + __atomic_thread_fence (__ATOMIC_SEQ_CST); +} + +static inline void __attribute__((always_inline, artificial)) +post_seq_barrier(int model) +{ + pre_seq_barrier(model); +} + +#define pre_post_seq_barrier 1 + +#include_next From 5471f55f001af412e1125b04972ebaab9d4f7337 Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Mon, 8 Aug 2022 14:37:42 +0100 Subject: [PATCH 03/16] AArch32: Fix 128-bit sequential consistency atomic operations. Similar to AArch64 the Arm implementation of 128-bit atomics is broken. For 128-bit atomics we rely on pthread barriers to correct guard the address in the pointer to get correct memory ordering. However for 128-bit atomics the address under the lock is different from the original pointer. This means that one of the values under the atomic operation is not protected properly and so we fail during when the user has requested sequential consistency as there's no barrier to enforce this requirement. As such users have resorted to adding an #ifdef GCC #endif around the use of these atomics. This corrects the issue by issuing a barrier only when __ATOMIC_SEQ_CST was requested. I have hand verified that the barriers are inserted for atomic seq cst. libatomic/ChangeLog: PR target/102218 * config/arm/host-config.h (pre_seq_barrier, post_seq_barrier, pre_post_seq_barrier): Require barrier on __ATOMIC_SEQ_CST. --- libatomic/config/arm/host-config.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libatomic/config/arm/host-config.h b/libatomic/config/arm/host-config.h index bbf4a3f84c3..ef16fad2a35 100644 --- a/libatomic/config/arm/host-config.h +++ b/libatomic/config/arm/host-config.h @@ -1,4 +1,23 @@ /* Avoiding the DMB (or kernel helper) can be a good thing. */ #define WANT_SPECIALCASE_RELAXED +/* Glibc, at least, uses acq_rel in its pthread mutex + implementation. If the user is asking for seq_cst, + this is insufficient. */ + +static inline void __attribute__((always_inline, artificial)) +pre_seq_barrier(int model) +{ + if (model == __ATOMIC_SEQ_CST) + __atomic_thread_fence (__ATOMIC_SEQ_CST); +} + +static inline void __attribute__((always_inline, artificial)) +post_seq_barrier(int model) +{ + pre_seq_barrier(model); +} + +#define pre_post_seq_barrier 1 + #include_next From 21c7aab09805d0c8c7695c8a69c8715d673a739a Mon Sep 17 00:00:00 2001 From: Andrew Pinski Date: Mon, 20 Dec 2021 20:27:33 -0800 Subject: [PATCH 04/16] Fix middle-end/103645: empty struct store not removed when using compound literal For compound literals empty struct stores are not removed as they go down a different path of the gimplifier; trying to optimize the init constructor. This fixes the problem by not adding the gimple assignment at the end of gimplify_init_constructor if it was an empty type. Note this updates gcc.dg/pr87052.c where we had: const char d[0] = { }; And was expecting a store to d but after this, there is no store as the decl's type is zero in size. OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions. gcc/ChangeLog: PR middle-end/103645 * gimplify.cc (gimplify_init_constructor): Don't build/add gimple assignment of an empty type. gcc/testsuite/ChangeLog: * gcc.dg/pr87052.c: Update d var to expect nothing. --- gcc/gimplify.cc | 7 +++++-- gcc/testsuite/gcc.dg/pr87052.c | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 2ac7ca0855e..f0fbdb48012 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -5488,8 +5488,11 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, if (ret == GS_ERROR) return GS_ERROR; /* If we have gimplified both sides of the initializer but have - not emitted an assignment, do so now. */ - if (*expr_p) + not emitted an assignment, do so now. */ + if (*expr_p + /* If the type is an empty type, we don't need to emit the + assignment. */ + && !is_empty_type (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))) { tree lhs = TREE_OPERAND (*expr_p, 0); tree rhs = TREE_OPERAND (*expr_p, 1); diff --git a/gcc/testsuite/gcc.dg/pr87052.c b/gcc/testsuite/gcc.dg/pr87052.c index 18e092c4674..796fe6440c1 100644 --- a/gcc/testsuite/gcc.dg/pr87052.c +++ b/gcc/testsuite/gcc.dg/pr87052.c @@ -23,8 +23,7 @@ void test (void) const char d[0] = { }; - /* Expect the following: - d = ""; */ + /* Expect nothing. */ const char e[0] = ""; @@ -36,6 +35,7 @@ void test (void) /* { dg-final { scan-tree-dump-times "a = \"\\\\x00ab\";" 1 "gimple" } } { dg-final { scan-tree-dump-times "b = \"a\\\\x00bc\";" 1 "gimple" } } { dg-final { scan-tree-dump-times "c = \"\";" 1 "gimple" } } - { dg-final { scan-tree-dump-times "d = { *};" 1 "gimple" } } + { dg-final { scan-tree-dump-times "d = " 1 "gimple" } } + { dg-final { scan-tree-dump-times "d = {CLOBBER\\(eol\\)}" 1 "gimple" } } { dg-final { scan-tree-dump-times "e = " 1 "gimple" } } { dg-final { scan-tree-dump-times "e = {CLOBBER\\(eol\\)}" 1 "gimple" } } */ From 01b1afdc35c13cbff5cd3d37f9319285ab84b157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Dumont?= Date: Thu, 28 Jan 2021 22:23:28 +0100 Subject: [PATCH 05/16] libstdc++: [_GLIBCXX_DEBUG] Do not consider detached iterators as value-initialized An attach iterator has its _M_version set to something != 0, the container version. This value shall be preserved when detaching it so that the iterator does not look like a value-initialized one. libstdc++-v3/ChangeLog: * include/debug/formatter.h (__singular_value_init): New _Iterator_state enum entry. (_Parameter<>(const _Safe_iterator<>&, const char*, _Is_iterator)): Check if iterator parameter is value-initialized. (_Parameter<>(const _Safe_local_iterator<>&, const char*, _Is_iterator)): Likewise. * include/debug/safe_iterator.h (_Safe_iterator<>::_M_value_initialized()): New. Adapt checks. * include/debug/safe_local_iterator.h (_Safe_local_iterator<>::_M_value_initialized()): New. Adapt checks. * src/c++11/debug.cc (_Safe_iterator_base::_M_reset): Do not reset _M_version. (print_field(PrintContext&, const _Parameter&, const char*)): Adapt state_names. * testsuite/23_containers/deque/debug/iterator1_neg.cc: New test. * testsuite/23_containers/deque/debug/iterator2_neg.cc: New test. * testsuite/23_containers/forward_list/debug/iterator1_neg.cc: New test. * testsuite/23_containers/forward_list/debug/iterator2_neg.cc: New test. * testsuite/23_containers/forward_list/debug/iterator3_neg.cc: New test. --- libstdc++-v3/include/debug/formatter.h | 15 ++++++- libstdc++-v3/include/debug/safe_iterator.h | 19 +++++--- .../include/debug/safe_local_iterator.h | 19 +++++--- libstdc++-v3/src/c++11/debug.cc | 7 ++- .../deque/debug/iterator1_neg.cc | 37 +++++++++++++++ .../deque/debug/iterator2_neg.cc | 40 +++++++++++++++++ .../forward_list/debug/iterator1_neg.cc | 37 +++++++++++++++ .../forward_list/debug/iterator2_neg.cc | 40 +++++++++++++++++ .../forward_list/debug/iterator3_neg.cc | 45 +++++++++++++++++++ 9 files changed, 241 insertions(+), 18 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/deque/debug/iterator1_neg.cc create mode 100644 libstdc++-v3/testsuite/23_containers/deque/debug/iterator2_neg.cc create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator1_neg.cc create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator2_neg.cc create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator3_neg.cc diff --git a/libstdc++-v3/include/debug/formatter.h b/libstdc++-v3/include/debug/formatter.h index 80e8ba46d1e..748d4fbfea4 100644 --- a/libstdc++-v3/include/debug/formatter.h +++ b/libstdc++-v3/include/debug/formatter.h @@ -185,6 +185,7 @@ namespace __gnu_debug __rbegin, // dereferenceable, and at the reverse-beginning __rmiddle, // reverse-dereferenceable, not at the reverse-beginning __rend, // reverse-past-the-end + __singular_value_init, // singular, value initialized __last_state }; @@ -280,7 +281,12 @@ namespace __gnu_debug _M_variant._M_iterator._M_seq_type = _GLIBCXX_TYPEID(_Sequence); if (__it._M_singular()) - _M_variant._M_iterator._M_state = __singular; + { + if (__it._M_value_initialized()) + _M_variant._M_iterator._M_state = __singular_value_init; + else + _M_variant._M_iterator._M_state = __singular; + } else { if (__it._M_is_before_begin()) @@ -308,7 +314,12 @@ namespace __gnu_debug _M_variant._M_iterator._M_seq_type = _GLIBCXX_TYPEID(_Sequence); if (__it._M_singular()) - _M_variant._M_iterator._M_state = __singular; + { + if (__it._M_value_initialized()) + _M_variant._M_iterator._M_state = __singular_value_init; + else + _M_variant._M_iterator._M_state = __singular; + } else { if (__it._M_is_end()) diff --git a/libstdc++-v3/include/debug/safe_iterator.h b/libstdc++-v3/include/debug/safe_iterator.h index d613933e236..33f7a86478a 100644 --- a/libstdc++-v3/include/debug/safe_iterator.h +++ b/libstdc++-v3/include/debug/safe_iterator.h @@ -41,8 +41,8 @@ #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs, _BadMsgId, _DiffMsgId) \ _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular() \ - || (_Lhs.base() == _Iterator() \ - && _Rhs.base() == _Iterator()), \ + || (_Lhs._M_value_initialized() \ + && _Rhs._M_value_initialized()), \ _M_message(_BadMsgId) \ ._M_iterator(_Lhs, #_Lhs) \ ._M_iterator(_Rhs, #_Rhs)); \ @@ -177,7 +177,7 @@ namespace __gnu_debug // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 408. Is vector > forbidden? _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -193,7 +193,7 @@ namespace __gnu_debug : _Iter_base() { _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -220,7 +220,7 @@ namespace __gnu_debug // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 408. Is vector > forbidden? _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _MutableIterator(), + || __x._M_value_initialized(), _M_message(__msg_init_const_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -236,7 +236,7 @@ namespace __gnu_debug // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 408. Is vector > forbidden? _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -266,7 +266,7 @@ namespace __gnu_debug operator=(_Safe_iterator&& __x) noexcept { _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -405,6 +405,11 @@ namespace __gnu_debug _M_incrementable() const { return !this->_M_singular() && !_M_is_end(); } + /// Is the iterator value-initialized? + bool + _M_value_initialized() const + { return _M_version == 0 && base() == _Iter_base(); } + // Can we advance the iterator @p __n steps (@p __n may be negative) bool _M_can_advance(difference_type __n, bool __strict = false) const; diff --git a/libstdc++-v3/include/debug/safe_local_iterator.h b/libstdc++-v3/include/debug/safe_local_iterator.h index b5318f50b6a..6e3c4eb1505 100644 --- a/libstdc++-v3/include/debug/safe_local_iterator.h +++ b/libstdc++-v3/include/debug/safe_local_iterator.h @@ -33,8 +33,8 @@ #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs) \ _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular() \ - || (_Lhs.base() == _Iterator{} \ - && _Rhs.base() == _Iterator{}), \ + || (_Lhs._M_value_initialized() \ + && _Rhs._M_value_initialized()), \ _M_message(__msg_iter_compare_bad) \ ._M_iterator(_Lhs, "lhs") \ ._M_iterator(_Rhs, "rhs")); \ @@ -127,7 +127,7 @@ namespace __gnu_debug // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 408. Is vector > forbidden? _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -142,7 +142,7 @@ namespace __gnu_debug : _Iter_base() { _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_init_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -167,7 +167,7 @@ namespace __gnu_debug // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 408. Is vector > forbidden? _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _MutableIterator(), + || __x._M_value_initialized(), _M_message(__msg_init_const_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -183,7 +183,7 @@ namespace __gnu_debug // _GLIBCXX_RESOLVE_LIB_DEFECTS // DR 408. Is vector > forbidden? _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -212,7 +212,7 @@ namespace __gnu_debug operator=(_Safe_local_iterator&& __x) noexcept { _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() - || __x.base() == _Iterator(), + || __x._M_value_initialized(), _M_message(__msg_copy_singular) ._M_iterator(*this, "this") ._M_iterator(__x, "other")); @@ -343,6 +343,11 @@ namespace __gnu_debug _M_incrementable() const { return !this->_M_singular() && !_M_is_end(); } + /// Is the iterator value-initialized? + bool + _M_value_initialized() const + { return _M_version == 0 && base() == _Iter_base{}; } + // Is the iterator range [*this, __rhs) valid? bool _M_valid_range(const _Safe_local_iterator& __rhs, diff --git a/libstdc++-v3/src/c++11/debug.cc b/libstdc++-v3/src/c++11/debug.cc index 4706defedf1..8ed61a69913 100644 --- a/libstdc++-v3/src/c++11/debug.cc +++ b/libstdc++-v3/src/c++11/debug.cc @@ -426,7 +426,9 @@ namespace __gnu_debug _M_reset() throw () { __atomic_store_n(&_M_sequence, (_Safe_sequence_base*)0, __ATOMIC_RELEASE); - _M_version = 0; + // Do not reset version, so that a detached iterator does not look like a + // value-initialized one. + // _M_version = 0; _M_prior = 0; _M_next = 0; } @@ -767,7 +769,8 @@ namespace "before-begin", "dereferenceable (start-of-reverse-sequence)", "dereferenceable (reverse)", - "past-the-reverse-end" + "past-the-reverse-end", + "singular (value-initialized)" }; print_word(ctx, state_names[iterator._M_state]); } diff --git a/libstdc++-v3/testsuite/23_containers/deque/debug/iterator1_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/debug/iterator1_neg.cc new file mode 100644 index 00000000000..73f8a044d43 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/debug/iterator1_neg.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. +// +// This library 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 this library; see the file COPYING3. If not see +// . +// +// { dg-do run { xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include + +void test01() +{ + typedef typename std::deque::iterator It; + std::deque dq; + dq.push_back(1); + + It it = It(); + (void)(dq.begin() != it); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/deque/debug/iterator2_neg.cc b/libstdc++-v3/testsuite/23_containers/deque/debug/iterator2_neg.cc new file mode 100644 index 00000000000..0abf5cbd4ec --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/deque/debug/iterator2_neg.cc @@ -0,0 +1,40 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. +// +// This library 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 this library; see the file COPYING3. If not see +// . +// +// { dg-do run { xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include + +void test01() +{ + typedef typename std::deque::iterator It; + It it; + { + std::deque dq; + it = dq.begin(); + } + + It value_init_it = It(); + (void)(it != value_init_it); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator1_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator1_neg.cc new file mode 100644 index 00000000000..8ca44e248ed --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator1_neg.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. +// +// This library 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 this library; see the file COPYING3. If not see +// . +// +// { dg-do run { xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include + +void test01() +{ + typedef typename std::forward_list::iterator It; + std::forward_list fl; + fl.push_front(1); + + It it = It(); + (void)(fl.begin() != it); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator2_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator2_neg.cc new file mode 100644 index 00000000000..92ab059e6b8 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator2_neg.cc @@ -0,0 +1,40 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. +// +// This library 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 this library; see the file COPYING3. If not see +// . +// +// { dg-do run { target c++11 xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include + +void test01() +{ + typedef typename std::forward_list::iterator It; + It it; + { + std::forward_list fl; + it = fl.begin(); + } + + It value_init_it{}; + (void)(it != value_init_it); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator3_neg.cc b/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator3_neg.cc new file mode 100644 index 00000000000..32ae7a5b7a6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/forward_list/debug/iterator3_neg.cc @@ -0,0 +1,45 @@ +// Copyright (C) 2022 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library 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. +// +// This library 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 this library; see the file COPYING3. If not see +// . +// +// { dg-do run { xfail *-*-* } } +// { dg-require-debug-mode "" } + +#include + +#include + +void test01() +{ + typedef typename std::forward_list::iterator It; + It end1, end2; + + { + std::forward_list fl; + fl.push_front(1); + + end1 = end2 = fl.end(); + VERIFY( end1 == end2 ); + } + + (void)(end1 == end2); +} + +int main() +{ + test01(); + return 0; +} From 4b0253b019943abf2cc5f4db0b7ed67caedffe4a Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Mon, 8 Aug 2022 15:17:47 +0200 Subject: [PATCH 06/16] d: Fix ICE in in add_stack_var, at cfgexpand.cc:476 The type that triggers the ICE never got completed by the semantic analysis pass. Checking for size forces it to be done, or issue a compile-time error. PR d/106555 gcc/d/ChangeLog: * d-target.cc (Target::isReturnOnStack): Check for return type size. gcc/testsuite/ChangeLog: * gdc.dg/imports/pr106555.d: New test. * gdc.dg/pr106555.d: New test. --- gcc/d/d-target.cc | 2 ++ gcc/testsuite/gdc.dg/imports/pr106555.d | 10 ++++++++++ gcc/testsuite/gdc.dg/pr106555.d | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 gcc/testsuite/gdc.dg/imports/pr106555.d create mode 100644 gcc/testsuite/gdc.dg/pr106555.d diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 610be74ad48..d4350e593e4 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -464,6 +464,8 @@ Target::isReturnOnStack (TypeFunction *tf, bool) return false; Type *tn = tf->next->toBasetype (); + if (tn->size () == SIZE_INVALID) + return false; return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray); } diff --git a/gcc/testsuite/gdc.dg/imports/pr106555.d b/gcc/testsuite/gdc.dg/imports/pr106555.d new file mode 100644 index 00000000000..0d3ab6bb747 --- /dev/null +++ b/gcc/testsuite/gdc.dg/imports/pr106555.d @@ -0,0 +1,10 @@ +module imports.pr106555; +struct S106555 +{ + int[] f106555; + int max106555; + this(int) + { + f106555.length = max106555; + } +} diff --git a/gcc/testsuite/gdc.dg/pr106555.d b/gcc/testsuite/gdc.dg/pr106555.d new file mode 100644 index 00000000000..7b40f3c097b --- /dev/null +++ b/gcc/testsuite/gdc.dg/pr106555.d @@ -0,0 +1,4 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106555 +// { dg-do compile } +// { dg-additional-options "-O2" } +// { dg-additional-sources "imports/pr106555.d" } From 703837b2cc8ac03c53ac7cc0fb1327055acaebd2 Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Tue, 2 Aug 2022 14:36:01 -0400 Subject: [PATCH 07/16] C: Implement C2X N2653 char8_t and UTF-8 string literal changes This patch implements the core language and compiler dependent library changes adopted for C2X via WG14 N2653. The changes include: - Change of type for UTF-8 string literals from array of const char to array of const char8_t (unsigned char). - A new atomic_char8_t typedef. - A new ATOMIC_CHAR8_T_LOCK_FREE macro defined in terms of the existing __GCC_ATOMIC_CHAR8_T_LOCK_FREE predefined macro. gcc/ChangeLog: * ginclude/stdatomic.h (atomic_char8_t, ATOMIC_CHAR8_T_LOCK_FREE): New typedef and macro. gcc/c/ChangeLog: * c-parser.cc (c_parser_string_literal): Use char8_t as the type of CPP_UTF8STRING when char8_t support is enabled. * c-typeck.cc (digest_init): Allow initialization of an array of character type by a string literal with type array of char8_t. gcc/c-family/ChangeLog: * c-lex.cc (lex_string, lex_charconst): Use char8_t as the type of CPP_UTF8CHAR and CPP_UTF8STRING when char8_t support is enabled. * c-opts.cc (c_common_post_options): Set flag_char8_t if targeting C2x. gcc/testsuite/ChangeLog: * gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c: New test. * gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c: New test. * gcc.dg/c11-utf8str-type.c: New test. * gcc.dg/c17-utf8str-type.c: New test. * gcc.dg/c2x-utf8str-type.c: New test. * gcc.dg/c2x-utf8str.c: New test. * gcc.dg/gnu2x-utf8str-type.c: New test. * gcc.dg/gnu2x-utf8str.c: New test. --- gcc/c-family/c-lex.cc | 13 ++++-- gcc/c-family/c-opts.cc | 4 +- gcc/c/c-parser.cc | 16 ++++++- gcc/c/c-typeck.cc | 2 +- gcc/ginclude/stdatomic.h | 6 +++ .../atomic/c2x-stdatomic-lockfree-char8_t.c | 42 +++++++++++++++++++ .../atomic/gnu2x-stdatomic-lockfree-char8_t.c | 5 +++ gcc/testsuite/gcc.dg/c11-utf8str-type.c | 6 +++ gcc/testsuite/gcc.dg/c17-utf8str-type.c | 6 +++ gcc/testsuite/gcc.dg/c2x-utf8str-type.c | 6 +++ gcc/testsuite/gcc.dg/c2x-utf8str.c | 34 +++++++++++++++ gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c | 5 +++ gcc/testsuite/gcc.dg/gnu2x-utf8str.c | 34 +++++++++++++++ 13 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c create mode 100644 gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c create mode 100644 gcc/testsuite/gcc.dg/c11-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/c17-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/c2x-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/c2x-utf8str.c create mode 100644 gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c create mode 100644 gcc/testsuite/gcc.dg/gnu2x-utf8str.c diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index 8bfa4f4024f..0b6f94e18a8 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -1352,7 +1352,14 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) default: case CPP_STRING: case CPP_UTF8STRING: - value = build_string (1, ""); + if (type == CPP_UTF8STRING && flag_char8_t) + { + value = build_string (TYPE_PRECISION (char8_type_node) + / TYPE_PRECISION (char_type_node), + ""); /* char8_t is 8 bits */ + } + else + value = build_string (1, ""); break; case CPP_STRING16: value = build_string (TYPE_PRECISION (char16_type_node) @@ -1425,9 +1432,7 @@ lex_charconst (const cpp_token *token) type = char16_type_node; else if (token->type == CPP_UTF8CHAR) { - if (!c_dialect_cxx ()) - type = unsigned_char_type_node; - else if (flag_char8_t) + if (flag_char8_t) type = char8_type_node; else type = char_type_node; diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 4e1463689de..1cf119a9bec 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1059,9 +1059,9 @@ c_common_post_options (const char **pfilename) if (flag_sized_deallocation == -1) flag_sized_deallocation = (cxx_dialect >= cxx14); - /* char8_t support is new in C++20. */ + /* char8_t support is implicitly enabled in C++20 and C2X. */ if (flag_char8_t == -1) - flag_char8_t = (cxx_dialect >= cxx20); + flag_char8_t = (cxx_dialect >= cxx20) || flag_isoc2x; if (flag_extern_tls_init) { diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 92049d1a101..fa9395986de 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -7447,7 +7447,14 @@ c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) default: case CPP_STRING: case CPP_UTF8STRING: - value = build_string (1, ""); + if (type == CPP_UTF8STRING && flag_char8_t) + { + value = build_string (TYPE_PRECISION (char8_type_node) + / TYPE_PRECISION (char_type_node), + ""); /* char8_t is 8 bits */ + } + else + value = build_string (1, ""); break; case CPP_STRING16: value = build_string (TYPE_PRECISION (char16_type_node) @@ -7472,9 +7479,14 @@ c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok) { default: case CPP_STRING: - case CPP_UTF8STRING: TREE_TYPE (value) = char_array_type_node; break; + case CPP_UTF8STRING: + if (flag_char8_t) + TREE_TYPE (value) = char8_array_type_node; + else + TREE_TYPE (value) = char_array_type_node; + break; case CPP_STRING16: TREE_TYPE (value) = char16_array_type_node; break; diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 8514488b7a5..d37de2a313b 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -8056,7 +8056,7 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, if (char_array) { - if (typ2 != char_type_node) + if (typ2 != char_type_node && typ2 != char8_type_node) incompat_string_cst = true; } else if (!comptypes (typ1, typ2)) diff --git a/gcc/ginclude/stdatomic.h b/gcc/ginclude/stdatomic.h index bfcfdf664c7..9f2475b739d 100644 --- a/gcc/ginclude/stdatomic.h +++ b/gcc/ginclude/stdatomic.h @@ -49,6 +49,9 @@ typedef _Atomic long atomic_long; typedef _Atomic unsigned long atomic_ulong; typedef _Atomic long long atomic_llong; typedef _Atomic unsigned long long atomic_ullong; +#ifdef __CHAR8_TYPE__ +typedef _Atomic __CHAR8_TYPE__ atomic_char8_t; +#endif typedef _Atomic __CHAR16_TYPE__ atomic_char16_t; typedef _Atomic __CHAR32_TYPE__ atomic_char32_t; typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t; @@ -97,6 +100,9 @@ extern void atomic_signal_fence (memory_order); #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#ifdef __GCC_ATOMIC_CHAR8_T_LOCK_FREE +#define ATOMIC_CHAR8_T_LOCK_FREE __GCC_ATOMIC_CHAR8_T_LOCK_FREE +#endif #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE diff --git a/gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c b/gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c new file mode 100644 index 00000000000..1b692f55ed0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c @@ -0,0 +1,42 @@ +/* Test atomic_is_lock_free for char8_t. */ +/* { dg-do run } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +#include +#include + +extern void abort (void); + +_Atomic __CHAR8_TYPE__ ac8a; +atomic_char8_t ac8t; + +#define CHECK_TYPE(MACRO, V1, V2) \ + do \ + { \ + int r1 = MACRO; \ + int r2 = atomic_is_lock_free (&V1); \ + int r3 = atomic_is_lock_free (&V2); \ + if (r1 != 0 && r1 != 1 && r1 != 2) \ + abort (); \ + if (r2 != 0 && r2 != 1) \ + abort (); \ + if (r3 != 0 && r3 != 1) \ + abort (); \ + if (r1 == 2 && r2 != 1) \ + abort (); \ + if (r1 == 2 && r3 != 1) \ + abort (); \ + if (r1 == 0 && r2 != 0) \ + abort (); \ + if (r1 == 0 && r3 != 0) \ + abort (); \ + } \ + while (0) + +int +main () +{ + CHECK_TYPE (ATOMIC_CHAR8_T_LOCK_FREE, ac8a, ac8t); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c b/gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c new file mode 100644 index 00000000000..27a3cfe3552 --- /dev/null +++ b/gcc/testsuite/gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c @@ -0,0 +1,5 @@ +/* Test atomic_is_lock_free for char8_t with -std=gnu2x. */ +/* { dg-do run } */ +/* { dg-options "-std=gnu2x -pedantic-errors" } */ + +#include "c2x-stdatomic-lockfree-char8_t.c" diff --git a/gcc/testsuite/gcc.dg/c11-utf8str-type.c b/gcc/testsuite/gcc.dg/c11-utf8str-type.c new file mode 100644 index 00000000000..8be9abb9686 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-utf8str-type.c @@ -0,0 +1,6 @@ +/* Test C11 UTF-8 string literal type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c11" } */ + +_Static_assert (_Generic (u8"text", char*: 1, default: 2) == 1, "UTF-8 string literals have an unexpected type"); +_Static_assert (_Generic (u8"x"[0], char: 1, default: 2) == 1, "UTF-8 string literal elements have an unexpected type"); diff --git a/gcc/testsuite/gcc.dg/c17-utf8str-type.c b/gcc/testsuite/gcc.dg/c17-utf8str-type.c new file mode 100644 index 00000000000..515c6db3970 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c17-utf8str-type.c @@ -0,0 +1,6 @@ +/* Test C17 UTF-8 string literal type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c17" } */ + +_Static_assert (_Generic (u8"text", char*: 1, default: 2) == 1, "UTF-8 string literals have an unexpected type"); +_Static_assert (_Generic (u8"x"[0], char: 1, default: 2) == 1, "UTF-8 string literal elements have an unexpected type"); diff --git a/gcc/testsuite/gcc.dg/c2x-utf8str-type.c b/gcc/testsuite/gcc.dg/c2x-utf8str-type.c new file mode 100644 index 00000000000..ebdde97b57a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-utf8str-type.c @@ -0,0 +1,6 @@ +/* Test C2X UTF-8 string literal type. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x" } */ + +_Static_assert (_Generic (u8"text", unsigned char*: 1, default: 2) == 1, "UTF-8 string literals have an unexpected type"); +_Static_assert (_Generic (u8"x"[0], unsigned char: 1, default: 2) == 1, "UTF-8 string literal elements have an unexpected type"); diff --git a/gcc/testsuite/gcc.dg/c2x-utf8str.c b/gcc/testsuite/gcc.dg/c2x-utf8str.c new file mode 100644 index 00000000000..2e4c392da9f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-utf8str.c @@ -0,0 +1,34 @@ +/* Test initialization by UTF-8 string literal in C2X. */ +/* { dg-do compile } */ +/* { dg-require-effective-target wchar } */ +/* { dg-options "-std=c2x" } */ + +typedef __CHAR8_TYPE__ char8_t; +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +typedef __WCHAR_TYPE__ wchar_t; + +/* Test that char, signed char, unsigned char, and char8_t arrays can be + initialized by a UTF-8 string literal. */ +const char cbuf1[] = u8"text"; +const char cbuf2[] = { u8"text" }; +const signed char scbuf1[] = u8"text"; +const signed char scbuf2[] = { u8"text" }; +const unsigned char ucbuf1[] = u8"text"; +const unsigned char ucbuf2[] = { u8"text" }; +const char8_t c8buf1[] = u8"text"; +const char8_t c8buf2[] = { u8"text" }; + +/* Test that a diagnostic is issued for attempted initialization of + other character types by a UTF-8 string literal. */ +const char16_t c16buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char16_t c16buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ + +/* Test that char8_t arrays can be initialized by an ordinary string + literal. */ +const char8_t c8buf3[] = "text"; +const char8_t c8buf4[] = { "text" }; diff --git a/gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c b/gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c new file mode 100644 index 00000000000..efe16ffc28d --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-utf8str-type.c @@ -0,0 +1,5 @@ +/* Test C2X UTF-8 string literal type with -std=gnu2x. */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu2x" } */ + +#include "c2x-utf8str-type.c" diff --git a/gcc/testsuite/gcc.dg/gnu2x-utf8str.c b/gcc/testsuite/gcc.dg/gnu2x-utf8str.c new file mode 100644 index 00000000000..f3719ea8c77 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-utf8str.c @@ -0,0 +1,34 @@ +/* Test initialization by UTF-8 string literal in C2X with -std=gnu2x. */ +/* { dg-do compile } */ +/* { dg-require-effective-target wchar } */ +/* { dg-options "-std=gnu2x" } */ + +typedef __CHAR8_TYPE__ char8_t; +typedef __CHAR16_TYPE__ char16_t; +typedef __CHAR32_TYPE__ char32_t; +typedef __WCHAR_TYPE__ wchar_t; + +/* Test that char, signed char, unsigned char, and char8_t arrays can be + initialized by a UTF-8 string literal. */ +const char cbuf1[] = u8"text"; +const char cbuf2[] = { u8"text" }; +const signed char scbuf1[] = u8"text"; +const signed char scbuf2[] = { u8"text" }; +const unsigned char ucbuf1[] = u8"text"; +const unsigned char ucbuf2[] = { u8"text" }; +const char8_t c8buf1[] = u8"text"; +const char8_t c8buf2[] = { u8"text" }; + +/* Test that a diagnostic is issued for attempted initialization of + other character types by a UTF-8 string literal. */ +const char16_t c16buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char16_t c16buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const char32_t c32buf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf1[] = u8"text"; /* { dg-error "from a string literal with type array of .unsigned char." } */ +const wchar_t wbuf2[] = { u8"text" }; /* { dg-error "from a string literal with type array of .unsigned char." } */ + +/* Test that char8_t arrays can be initialized by an ordinary string + literal. */ +const char8_t c8buf3[] = "text"; +const char8_t c8buf4[] = { "text" }; From 053876cdbe8057210e6f4da4eec2df58f92ccd4c Mon Sep 17 00:00:00 2001 From: Tom Honermann Date: Tue, 2 Aug 2022 14:36:02 -0400 Subject: [PATCH 08/16] preprocessor/106426: Treat u8 character literals as unsigned in char8_t modes. This patch corrects handling of UTF-8 character literals in preprocessing directives so that they are treated as unsigned types in char8_t enabled C++ modes (C++17 with -fchar8_t or C++20 without -fno-char8_t). Previously, UTF-8 character literals were always treated as having the same type as ordinary character literals (signed or unsigned dependent on target or use of the -fsigned-char or -funsigned char options). PR preprocessor/106426 gcc/c-family/ChangeLog: * c-opts.cc (c_common_post_options): Assign cpp_opts->unsigned_utf8char subject to -fchar8_t, -fsigned-char, and/or -funsigned-char. gcc/testsuite/ChangeLog: * g++.dg/ext/char8_t-char-literal-1.C: Check signedness of u8 literals. * g++.dg/ext/char8_t-char-literal-2.C: Check signedness of u8 literals. libcpp/ChangeLog: * charset.cc (narrow_str_to_charconst): Set signedness of CPP_UTF8CHAR literals based on unsigned_utf8char. * include/cpplib.h (cpp_options): Add unsigned_utf8char. * init.cc (cpp_create_reader): Initialize unsigned_utf8char. --- gcc/c-family/c-opts.cc | 1 + gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C | 6 +++++- gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C | 4 ++++ libcpp/charset.cc | 4 ++-- libcpp/include/cpplib.h | 4 ++-- libcpp/init.cc | 1 + 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 1cf119a9bec..9833e509b2d 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1062,6 +1062,7 @@ c_common_post_options (const char **pfilename) /* char8_t support is implicitly enabled in C++20 and C2X. */ if (flag_char8_t == -1) flag_char8_t = (cxx_dialect >= cxx20) || flag_isoc2x; + cpp_opts->unsigned_utf8char = flag_char8_t ? 1 : cpp_opts->unsigned_char; if (flag_extern_tls_init) { diff --git a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C index 8ed85ccfdcd..2994dd38516 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-1.C @@ -1,6 +1,6 @@ // Test that UTF-8 character literals have type char if -fchar8_t is not enabled. // { dg-do compile } -// { dg-options "-std=c++17 -fno-char8_t" } +// { dg-options "-std=c++17 -fsigned-char -fno-char8_t" } template struct is_same @@ -10,3 +10,7 @@ template { static const bool value = true; }; static_assert(is_same::value, "Error"); + +#if u8'\0' - 1 > 0 +#error "UTF-8 character literals not signed in preprocessor" +#endif diff --git a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C index 7861736689c..db4fe70046d 100644 --- a/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C +++ b/gcc/testsuite/g++.dg/ext/char8_t-char-literal-2.C @@ -10,3 +10,7 @@ template { static const bool value = true; }; static_assert(is_same::value, "Error"); + +#if u8'\0' - 1 < 0 +#error "UTF-8 character literals not unsigned in preprocessor" +#endif diff --git a/libcpp/charset.cc b/libcpp/charset.cc index ca8b7cf7aa5..12e31632228 100644 --- a/libcpp/charset.cc +++ b/libcpp/charset.cc @@ -1960,8 +1960,8 @@ narrow_str_to_charconst (cpp_reader *pfile, cpp_string str, /* Multichar constants are of type int and therefore signed. */ if (i > 1) unsigned_p = 0; - else if (type == CPP_UTF8CHAR && !CPP_OPTION (pfile, cplusplus)) - unsigned_p = 1; + else if (type == CPP_UTF8CHAR) + unsigned_p = CPP_OPTION (pfile, unsigned_utf8char); else unsigned_p = CPP_OPTION (pfile, unsigned_char); diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 3eba6f74b57..f9c042db034 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -581,8 +581,8 @@ struct cpp_options ints and target wide characters, respectively. */ size_t precision, char_precision, int_precision, wchar_precision; - /* True means chars (wide chars) are unsigned. */ - bool unsigned_char, unsigned_wchar; + /* True means chars (wide chars, UTF-8 chars) are unsigned. */ + bool unsigned_char, unsigned_wchar, unsigned_utf8char; /* True if the most significant byte in a word has the lowest address in memory. */ diff --git a/libcpp/init.cc b/libcpp/init.cc index f4ab83d2145..0242da5f55c 100644 --- a/libcpp/init.cc +++ b/libcpp/init.cc @@ -231,6 +231,7 @@ cpp_create_reader (enum c_lang lang, cpp_hash_table *table, CPP_OPTION (pfile, int_precision) = CHAR_BIT * sizeof (int); CPP_OPTION (pfile, unsigned_char) = 0; CPP_OPTION (pfile, unsigned_wchar) = 1; + CPP_OPTION (pfile, unsigned_utf8char) = 1; CPP_OPTION (pfile, bytes_big_endian) = 1; /* does not matter */ /* Default to no charset conversion. */ From ef623bb58594958a7959f8f031f65a50eb0e5890 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 8 Aug 2022 15:13:51 -0400 Subject: [PATCH 09/16] Evaluate condition arguments with the correct type. Processing of a cond_expr requires that a range of the correct type for the operands of the cond_expr is passed in. PR tree-optimization/106556 gcc/ * gimple-range-gori.cc (gori_compute::condexpr_adjust): Use the type of the cond_expr operands being evaluted. gcc/testsuite/ * gfortran.dg/pr106556.f90: New. --- gcc/gimple-range-gori.cc | 11 ++++++----- gcc/testsuite/gfortran.dg/pr106556.f90 | 10 ++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/pr106556.f90 diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index a43e44c841e..8879e44cba1 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -1398,16 +1398,17 @@ gori_compute::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond, } // Now solve for SSA1 or SSA2 if they are in the dependency chain. - Value_Range tmp (type); if (ssa1 && in_chain_p (ssa1, cond_name)) { - if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src)) - r1.intersect (tmp); + Value_Range tmp1 (TREE_TYPE (ssa1)); + if (compute_operand_range (tmp1, def_stmt, cond_true, ssa1, src)) + r1.intersect (tmp1); } if (ssa2 && in_chain_p (ssa2, cond_name)) { - if (compute_operand_range (tmp, def_stmt, cond_false, ssa2, src)) - r2.intersect (tmp); + Value_Range tmp2 (TREE_TYPE (ssa2)); + if (compute_operand_range (tmp2, def_stmt, cond_false, ssa2, src)) + r2.intersect (tmp2); } if (idx) { diff --git a/gcc/testsuite/gfortran.dg/pr106556.f90 b/gcc/testsuite/gfortran.dg/pr106556.f90 new file mode 100644 index 00000000000..01b89a8eee2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr106556.f90 @@ -0,0 +1,10 @@ +! { dg-do compile } +! { dg-options "-O1 -fnon-call-exceptions -ftree-loop-if-convert" } + + +program p + real :: a(2) + + a(:) = 1.0 + if (minloc (a, dim = 1).ne.1) STOP 1 +end From 5f17badb648980275ff4c86b0c207dbd751b00f2 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 9 Aug 2022 00:16:47 +0000 Subject: [PATCH 10/16] Daily bump. --- gcc/ChangeLog | 26 ++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 14 ++++++++++++++ gcc/c/ChangeLog | 8 ++++++++ gcc/d/ChangeLog | 5 +++++ gcc/testsuite/ChangeLog | 37 +++++++++++++++++++++++++++++++++++++ libatomic/ChangeLog | 12 ++++++++++++ libcpp/ChangeLog | 8 ++++++++ libstdc++-v3/ChangeLog | 18 ++++++++++++++++++ 9 files changed, 129 insertions(+), 1 deletion(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2d41c22e17e..36879ec4109 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2022-08-08 Andrew MacLeod + + PR tree-optimization/106556 + * gimple-range-gori.cc (gori_compute::condexpr_adjust): Use the + type of the cond_expr operands being evaluted. + +2022-08-08 Tom Honermann + + * ginclude/stdatomic.h (atomic_char8_t, + ATOMIC_CHAR8_T_LOCK_FREE): New typedef and macro. + +2022-08-08 Andrew Pinski + + PR middle-end/103645 + * gimplify.cc (gimplify_init_constructor): Don't build/add + gimple assignment of an empty type. + +2022-08-08 Richard Biener + + PR lto/106540 + PR lto/106334 + * dwarf2out.cc (dwarf2out_register_external_die): Restore + original assert. + * lto-streamer-in.cc (lto_read_tree_1): Use lto_input_tree_1 + to input DECL_INITIAL, avoiding to commit drefs. + 2022-08-07 Roger Sayle * config/i386/i386.md (*cmp_doubleword): Change predicate diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 00f22f5b8c8..8bd1173be90 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20220808 +20220809 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 68fc6e2761e..63277a514eb 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,17 @@ +2022-08-08 Tom Honermann + + PR preprocessor/106426 + * c-opts.cc (c_common_post_options): Assign cpp_opts->unsigned_utf8char + subject to -fchar8_t, -fsigned-char, and/or -funsigned-char. + +2022-08-08 Tom Honermann + + * c-lex.cc (lex_string, lex_charconst): Use char8_t as the type + of CPP_UTF8CHAR and CPP_UTF8STRING when char8_t support is + enabled. + * c-opts.cc (c_common_post_options): Set flag_char8_t if + targeting C2x. + 2022-07-31 Lewis Hyatt PR c++/66290 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index cffb462a1dc..b5ecf9269e6 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,11 @@ +2022-08-08 Tom Honermann + + * c-parser.cc (c_parser_string_literal): Use char8_t as the type + of CPP_UTF8STRING when char8_t support is enabled. + * c-typeck.cc (digest_init): Allow initialization of an array + of character type by a string literal with type array of + char8_t. + 2022-08-01 David Malcolm * c-typeck.cc (build_c_cast): Quote names of address spaces in diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 41e28096646..0bb74b134c5 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,8 @@ +2022-08-08 Iain Buclaw + + PR d/106555 + * d-target.cc (Target::isReturnOnStack): Check for return type size. + 2022-08-03 Iain Buclaw * dmd/MERGE: Merge upstream dmd d7772a2369. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fee24d23d94..19a5303bc1a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,40 @@ +2022-08-08 Andrew MacLeod + + PR tree-optimization/106556 + * gfortran.dg/pr106556.f90: New. + +2022-08-08 Tom Honermann + + PR preprocessor/106426 + * g++.dg/ext/char8_t-char-literal-1.C: Check signedness of u8 literals. + * g++.dg/ext/char8_t-char-literal-2.C: Check signedness of u8 literals. + +2022-08-08 Tom Honermann + + * gcc.dg/atomic/c2x-stdatomic-lockfree-char8_t.c: New test. + * gcc.dg/atomic/gnu2x-stdatomic-lockfree-char8_t.c: New test. + * gcc.dg/c11-utf8str-type.c: New test. + * gcc.dg/c17-utf8str-type.c: New test. + * gcc.dg/c2x-utf8str-type.c: New test. + * gcc.dg/c2x-utf8str.c: New test. + * gcc.dg/gnu2x-utf8str-type.c: New test. + * gcc.dg/gnu2x-utf8str.c: New test. + +2022-08-08 Iain Buclaw + + PR d/106555 + * gdc.dg/imports/pr106555.d: New test. + * gdc.dg/pr106555.d: New test. + +2022-08-08 Andrew Pinski + + * gcc.dg/pr87052.c: Update d var to expect nothing. + +2022-08-08 Andrew Pinski + + * gcc.dg/tree-ssa/pr93776.c: Moved to... + * gcc.c-torture/compile/pr93776.c: ...here. + 2022-08-07 Roger Sayle * gcc.target/i386/cmpti2.c: Add -mno-stv to dg-options. diff --git a/libatomic/ChangeLog b/libatomic/ChangeLog index d34b9a1bdbb..b7cacf796ae 100644 --- a/libatomic/ChangeLog +++ b/libatomic/ChangeLog @@ -1,3 +1,15 @@ +2022-08-08 Tamar Christina + + PR target/102218 + * config/arm/host-config.h (pre_seq_barrier, post_seq_barrier, + pre_post_seq_barrier): Require barrier on __ATOMIC_SEQ_CST. + +2022-08-08 Tamar Christina + + PR target/102218 + * config/aarch64/aarch64-config.h: New file. + * config/aarch64/host-config.h: New file. + 2022-06-02 David Malcolm * testsuite/lib/libatomic.exp: Add load_gcc_lib of scansarif.exp. diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 4905bd57e1b..259adb97e83 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,11 @@ +2022-08-08 Tom Honermann + + PR preprocessor/106426 + * charset.cc (narrow_str_to_charconst): Set signedness of CPP_UTF8CHAR + literals based on unsigned_utf8char. + * include/cpplib.h (cpp_options): Add unsigned_utf8char. + * init.cc (cpp_create_reader): Initialize unsigned_utf8char. + 2022-07-15 Jonathan Wakely * include/line-map.h (label_text::take_or_copy): Remove. diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 35af704d57f..4585e01c3cf 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,21 @@ +2022-08-08 François Dumont + + * include/debug/formatter.h (__singular_value_init): New _Iterator_state enum entry. + (_Parameter<>(const _Safe_iterator<>&, const char*, _Is_iterator)): Check if iterator + parameter is value-initialized. + (_Parameter<>(const _Safe_local_iterator<>&, const char*, _Is_iterator)): Likewise. + * include/debug/safe_iterator.h (_Safe_iterator<>::_M_value_initialized()): New. Adapt + checks. + * include/debug/safe_local_iterator.h (_Safe_local_iterator<>::_M_value_initialized()): New. + Adapt checks. + * src/c++11/debug.cc (_Safe_iterator_base::_M_reset): Do not reset _M_version. + (print_field(PrintContext&, const _Parameter&, const char*)): Adapt state_names. + * testsuite/23_containers/deque/debug/iterator1_neg.cc: New test. + * testsuite/23_containers/deque/debug/iterator2_neg.cc: New test. + * testsuite/23_containers/forward_list/debug/iterator1_neg.cc: New test. + * testsuite/23_containers/forward_list/debug/iterator2_neg.cc: New test. + * testsuite/23_containers/forward_list/debug/iterator3_neg.cc: New test. + 2022-08-05 Jonathan Wakely * include/experimental/scope (__cpp_lib_experimental_scope): From 8a16b9f983824b6b9a25275cd23b6bba8c98b800 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 9 Aug 2022 07:57:40 +0200 Subject: [PATCH 11/16] OpenMP: Fix folding with simd's linear clause [PR106492] gcc/ChangeLog: PR middle-end/106492 * omp-low.cc (lower_rec_input_clauses): Add missing folding to data type of linear-clause list item. gcc/testsuite/ChangeLog: PR middle-end/106492 * g++.dg/gomp/pr106492.C: New test. --- gcc/omp-low.cc | 6 ++-- gcc/testsuite/g++.dg/gomp/pr106492.C | 49 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/pr106492.C diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc index d73c165f029..3c4b8593c8b 100644 --- a/gcc/omp-low.cc +++ b/gcc/omp-low.cc @@ -6241,10 +6241,10 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } if (POINTER_TYPE_P (TREE_TYPE (x))) - x = fold_build2 (POINTER_PLUS_EXPR, - TREE_TYPE (x), x, t); + x = fold_build_pointer_plus (x, t); else - x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, t); + x = fold_build2 (PLUS_EXPR, TREE_TYPE (x), x, + fold_convert (TREE_TYPE (x), t)); } if ((OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR diff --git a/gcc/testsuite/g++.dg/gomp/pr106492.C b/gcc/testsuite/g++.dg/gomp/pr106492.C new file mode 100644 index 00000000000..f263bb42710 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr106492.C @@ -0,0 +1,49 @@ +/* PR middle-end/106492 */ + +template +struct S { + T a : 12; + S () : a(0) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; +struct U { + int a : 12; + U () : a(0) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; + +S s; +U u; + + +template +struct Sptr { + T a; + Sptr (T init) : a(init) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; +struct Uptr { + int *a; + Uptr (int *init) : a(init) + { +#pragma omp for simd linear(a) + for (int k = 0; k < 64; ++k) + a++; + } +}; + +int i[1024]; +Sptr sptr(i); +Uptr uptr(&i[100]); From 409978d58dafa689c5b3f85013e2786526160f2c Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 8 Aug 2022 12:20:04 +0200 Subject: [PATCH 12/16] tree-optimization/106514 - add --param max-jump-thread-paths The following adds a limit for the exponential greedy search of the backwards jump threader. The idea is to limit the search space in a way that the paths considered are the same if the search were in BFS order rather than DFS. In particular it stops considering incoming edges into a block if the product of the in-degrees of blocks on the path exceeds the specified limit. When considering the low stmt copying limit of 7 (or 1 in the size optimize case) this means the degenerate case with maximum search space is a sequence of conditions with no actual code B1 |\ | empty |/ B2 |\ ... Bn |\ GIMPLE_CONDs are costed 2, an equivalent GIMPLE_SWITCH already 4, so we reach 7 already with 3 middle conditions (B1 and Bn do not count). The search space would be 2^4 == 16 to reach this. The FSM threads historically allowed for a thread length of 10 but is really looking for a single multiway branch threaded across the backedge. I've chosen the default of the new parameter to 64 which effectively limits the outdegree of the switch statement (the cases reaching the backedge) to that number (divided by 2 until I add some special pruning for FSM threads due to the loop header indegree). The testcase ssa-dom-thread-7.c requires 56 at the moment (as said, some special FSM thread pruning of considered edges would bring it down to half of that), but we now get one more threading and quite some more in later threadfull. This testcase seems to be difficult to check for expected transforms. The new testcases add the degenerate case we currently thread (without deciding whether that's a good idea ...) plus one with an approripate limit that should prevent the threading. This obsoletes the mentioned --param max-fsm-thread-length but I am not removing it as part of this patch. When the search space is limited the thread stmt size limit effectively provides max-fsm-thread-length. The param with its default does not help PR106514 enough to unleash path searching with the higher FSM stmt count limit. PR tree-optimization/106514 * params.opt (max-jump-thread-paths): New. * doc/invoke.texi (max-jump-thread-paths): Document. * tree-ssa-threadbackward.cc (back_threader::find_paths_to_names): Honor max-jump-thread-paths, take overall_path argument. (back_threader::find_paths): Pass 1 as initial overall_path. * gcc.dg/tree-ssa/ssa-thread-16.c: New testcase. * gcc.dg/tree-ssa/ssa-thread-17.c: Likewise. * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Adjust. --- gcc/doc/invoke.texi | 7 ++++++ gcc/params.opt | 4 ++++ .../gcc.dg/tree-ssa/ssa-dom-thread-7.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c | 24 +++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c | 7 ++++++ gcc/tree-ssa-threadbackward.cc | 20 +++++++++++----- 6 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 92f7aaead74..f01696696bf 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -14754,6 +14754,13 @@ optimizing. Maximum number of statements allowed in a block that needs to be duplicated when threading jumps. +@item max-jump-thread-paths +The maximum number of paths to consider when searching for jump threading +opportunities. When arriving at a block incoming edges are only considered +if the number of paths to be searched sofar multiplied by the incoming +edge degree does not exhaust the specified maximum number of paths to +consider. + @item max-fields-for-field-sensitive Maximum number of fields in a structure treated in a field sensitive manner during pointer analysis. diff --git a/gcc/params.opt b/gcc/params.opt index 2f9c9cf27dd..132987343c6 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -582,6 +582,10 @@ Bound on the number of iterations the brute force # of iterations analysis algor Common Joined UInteger Var(param_max_jump_thread_duplication_stmts) Init(15) Param Optimization Maximum number of statements allowed in a block that needs to be duplicated when threading jumps. +-param=max-jump-thread-paths= +Common Joined UInteger Var(param_max_jump_thread_paths) Init(64) IntegerRange(1, 65536) Param Optimization +Search space limit for the backwards jump threader. + -param=max-last-value-rtl= Common Joined UInteger Var(param_max_last_value_rtl) Init(10000) Param Optimization The maximum number of RTL nodes that can be recorded as combiner's last value. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c index aa06db5e223..47b8fdfa29a 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c @@ -11,7 +11,7 @@ to change decisions in switch expansion which in turn can expose new jump threading opportunities. Skip the later tests on aarch64. */ /* { dg-final { scan-tree-dump-not "Jumps threaded" "dom3" { target { ! aarch64*-*-* } } } } */ -/* { dg-final { scan-tree-dump "Jumps threaded: 8" "thread2" { target { ! aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump "Jumps threaded: 9" "thread2" { target { ! aarch64*-*-* } } } } */ /* { dg-final { scan-tree-dump "Jumps threaded: 18" "thread2" { target { aarch64*-*-* } } } } */ enum STATE { diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c new file mode 100644 index 00000000000..f96170b073d --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-16.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-threadfull1-details" } */ + +int res; +void foo (int a, int b, int c, int d, int e) +{ + if (a > 100) + res = 3; + if (b != 5) + res = 5; + if (c == 29) + res = 7; + if (d < 2) + res = 9; + /* Accounting whoes makes this not catched. */ +#if 0 + if (e != 37) + res = 11; +#endif + if (a < 10) + res = 13; +} + +/* { dg-final { scan-tree-dump "SUCCESS" "threadfull1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c new file mode 100644 index 00000000000..94ee6666788 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-17.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-threadfull1-details --param max-jump-thread-paths=15" } */ + +#include "ssa-thread-16.c" + +/* With limiting the search space we should no longer consider this path. */ +/* { dg-final { scan-tree-dump-not "SUCCESS" "threadfull1" } } */ diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc index 332a1d2a1dd..a5f8f141071 100644 --- a/gcc/tree-ssa-threadbackward.cc +++ b/gcc/tree-ssa-threadbackward.cc @@ -90,7 +90,7 @@ private: bool debug_counter (); edge maybe_register_path (); void maybe_register_path_dump (edge taken_edge); - void find_paths_to_names (basic_block bb, bitmap imports); + void find_paths_to_names (basic_block bb, bitmap imports, unsigned); edge find_taken_edge (const vec &path); edge find_taken_edge_cond (const vec &path, gcond *); edge find_taken_edge_switch (const vec &path, gswitch *); @@ -337,9 +337,12 @@ back_threader::find_taken_edge_cond (const vec &path, // INTERESTING bitmap, and register any such paths. // // BB is the current path being processed. +// +// OVERALL_PATHS is the search space up to this block void -back_threader::find_paths_to_names (basic_block bb, bitmap interesting) +back_threader::find_paths_to_names (basic_block bb, bitmap interesting, + unsigned overall_paths) { if (m_visited_bbs.add (bb)) return; @@ -352,8 +355,10 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) || maybe_register_path ())) ; - // Continue looking for ways to extend the path - else + // Continue looking for ways to extend the path but limit the + // search space along a branch + else if ((overall_paths = overall_paths * EDGE_COUNT (bb->preds)) + <= (unsigned)param_max_jump_thread_paths) { // For further greedy searching we want to remove interesting // names defined in BB but add ones on the PHI edges for the @@ -407,7 +412,7 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) unwind.quick_push (def); } } - find_paths_to_names (e->src, new_interesting); + find_paths_to_names (e->src, new_interesting, overall_paths); // Restore new_interesting. We leave m_imports alone since // we do not prune defs in BB from it and separately keeping // track of which bits to unwind isn't worth the trouble. @@ -417,6 +422,9 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting) } } } + else if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " FAIL: Search space limit %d reached.\n", + param_max_jump_thread_paths); // Reset things to their original state. m_path.pop (); @@ -447,7 +455,7 @@ back_threader::find_paths (basic_block bb, tree name) auto_bitmap interesting; bitmap_copy (interesting, m_imports); - find_paths_to_names (bb, interesting); + find_paths_to_names (bb, interesting, 1); } } From c64ef5cd92c2e340caabc95f4a28c9a125e8b5b8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 8 Aug 2022 14:04:43 +0200 Subject: [PATCH 13/16] Remove --param max-fsm-thread-length This removes max-fsm-thread-length which is obsoleted by max-jump-thread-paths. * doc/invoke.texi (max-fsm-thread-length): Remove. * params.opt (max-fsm-thread-length): Likewise. * tree-ssa-threadbackward.cc (back_threader_profitability::profitable_path_p): Do not check max-fsm-thread-length. --- gcc/doc/invoke.texi | 3 --- gcc/params.opt | 4 ---- gcc/tree-ssa-threadbackward.cc | 9 --------- 3 files changed, 16 deletions(-) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f01696696bf..58e422041e4 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -15262,9 +15262,6 @@ Emit instrumentation calls to __tsan_func_entry() and __tsan_func_exit(). Maximum number of instructions to copy when duplicating blocks on a finite state automaton jump thread path. -@item max-fsm-thread-length -Maximum number of basic blocks on a jump thread path. - @item threader-debug threader-debug=[none|all] Enables verbose dumping of the threader solver. diff --git a/gcc/params.opt b/gcc/params.opt index 132987343c6..201b5c9f56f 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -498,10 +498,6 @@ The maximum number of nested indirect inlining performed by early inliner. Common Joined UInteger Var(param_max_fields_for_field_sensitive) Param Maximum number of fields in a structure before pointer analysis treats the structure as a single variable. --param=max-fsm-thread-length= -Common Joined UInteger Var(param_max_fsm_thread_length) Init(10) IntegerRange(1, 999999) Param Optimization -Maximum number of basic blocks on a jump thread path. - -param=max-fsm-thread-path-insns= Common Joined UInteger Var(param_max_fsm_thread_path_insns) Init(100) IntegerRange(1, 999999) Param Optimization Maximum number of instructions to copy when duplicating blocks on a finite state automaton jump thread path. diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc index a5f8f141071..30047c654fb 100644 --- a/gcc/tree-ssa-threadbackward.cc +++ b/gcc/tree-ssa-threadbackward.cc @@ -569,15 +569,6 @@ back_threader_profitability::profitable_path_p (const vec &m_path, if (m_path.length () <= 1) return false; - if (m_path.length () > (unsigned) param_max_fsm_thread_length) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " FAIL: Jump-thread path not considered: " - "the number of basic blocks on the path " - "exceeds PARAM_MAX_FSM_THREAD_LENGTH.\n"); - return false; - } - int n_insns = 0; gimple_stmt_iterator gsi; loop_p loop = m_path[0]->loop_father; From 9aa08cd48490183382371bff4fd53573b5adabe8 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 2 Aug 2022 13:46:28 +0200 Subject: [PATCH 14/16] autopar TLC The following removes all excessive update_ssa calls from OMP expansion, thereby rewriting the atomic load and store cases to GIMPLE code generation. I don't think autopar ever exercises the atomics code though. There's not much test coverage overall so I've built SPEC 2k17 with -floop-parallelize-all -ftree-parallelize-loops=2 with and without LTO (and otherwise -Ofast plus -march=haswell) without fallout. If there's any fallout it's not OK to update SSA form for each and every OMP stmt lowered. * omp-expand.cc (expand_omp_atomic_load): Emit GIMPLE directly. Avoid update_ssa when in SSA form. (expand_omp_atomic_store): Likewise. (expand_omp_atomic_fetch_op): Avoid update_ssa when in SSA form. (expand_omp_atomic_pipeline): Likewise. (expand_omp_atomic_mutex): Likewise. * tree-parloops.cc (gen_parallel_loop): Use TODO_update_ssa_no_phi after loop_version. --- gcc/omp-expand.cc | 81 +++++++++++++++++++++++++++----------------- gcc/tree-parloops.cc | 2 +- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc index 64e6308fc7b..48fbd157c6e 100644 --- a/gcc/omp-expand.cc +++ b/gcc/omp-expand.cc @@ -8617,7 +8617,7 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, basic_block store_bb; location_t loc; gimple *stmt; - tree decl, call, type, itype; + tree decl, type, itype; gsi = gsi_last_nondebug_bb (load_bb); stmt = gsi_stmt (gsi); @@ -8637,23 +8637,33 @@ expand_omp_atomic_load (basic_block load_bb, tree addr, itype = TREE_TYPE (TREE_TYPE (decl)); enum omp_memory_order omo = gimple_omp_atomic_memory_order (stmt); - tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo)); - call = build_call_expr_loc (loc, decl, 2, addr, mo); + tree mo = build_int_cst (integer_type_node, + omp_memory_order_to_memmodel (omo)); + gcall *call = gimple_build_call (decl, 2, addr, mo); + gimple_set_location (call, loc); + gimple_set_vuse (call, gimple_vuse (stmt)); + gimple *repl; if (!useless_type_conversion_p (type, itype)) - call = fold_build1_loc (loc, VIEW_CONVERT_EXPR, type, call); - call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call); - - force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT); - gsi_remove (&gsi, true); + { + tree lhs = make_ssa_name (itype); + gimple_call_set_lhs (call, lhs); + gsi_insert_before (&gsi, call, GSI_SAME_STMT); + repl = gimple_build_assign (loaded_val, + build1 (VIEW_CONVERT_EXPR, type, lhs)); + gimple_set_location (repl, loc); + } + else + { + gimple_call_set_lhs (call, loaded_val); + repl = call; + } + gsi_replace (&gsi, repl, true); store_bb = single_succ (load_bb); gsi = gsi_last_nondebug_bb (store_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_STORE); gsi_remove (&gsi, true); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); - return true; } @@ -8669,7 +8679,7 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, basic_block store_bb = single_succ (load_bb); location_t loc; gimple *stmt; - tree decl, call, type, itype; + tree decl, type, itype; machine_mode imode; bool exchange; @@ -8710,25 +8720,36 @@ expand_omp_atomic_store (basic_block load_bb, tree addr, if (!useless_type_conversion_p (itype, type)) stored_val = fold_build1_loc (loc, VIEW_CONVERT_EXPR, itype, stored_val); enum omp_memory_order omo = gimple_omp_atomic_memory_order (stmt); - tree mo = build_int_cst (NULL, omp_memory_order_to_memmodel (omo)); - call = build_call_expr_loc (loc, decl, 3, addr, stored_val, mo); + tree mo = build_int_cst (integer_type_node, + omp_memory_order_to_memmodel (omo)); + stored_val = force_gimple_operand_gsi (&gsi, stored_val, true, NULL_TREE, + true, GSI_SAME_STMT); + gcall *call = gimple_build_call (decl, 3, addr, stored_val, mo); + gimple_set_location (call, loc); + gimple_set_vuse (call, gimple_vuse (stmt)); + gimple_set_vdef (call, gimple_vdef (stmt)); + + gimple *repl = call; if (exchange) { if (!useless_type_conversion_p (type, itype)) - call = build1_loc (loc, VIEW_CONVERT_EXPR, type, call); - call = build2_loc (loc, MODIFY_EXPR, void_type_node, loaded_val, call); + { + tree lhs = make_ssa_name (itype); + gimple_call_set_lhs (call, lhs); + gsi_insert_before (&gsi, call, GSI_SAME_STMT); + repl = gimple_build_assign (loaded_val, + build1 (VIEW_CONVERT_EXPR, type, lhs)); + gimple_set_location (repl, loc); + } + else + gimple_call_set_lhs (call, loaded_val); } - - force_gimple_operand_gsi (&gsi, call, true, NULL_TREE, true, GSI_SAME_STMT); - gsi_remove (&gsi, true); + gsi_replace (&gsi, repl, true); /* Remove the GIMPLE_OMP_ATOMIC_LOAD that we verified above. */ gsi = gsi_last_nondebug_bb (load_bb); gsi_remove (&gsi, true); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); - return true; } @@ -8874,10 +8895,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb, gsi_remove (&gsi, true); if (gimple_in_ssa_p (cfun)) - { - release_defs (stmt); - update_ssa (TODO_update_ssa_no_phi); - } + release_defs (stmt); return true; } @@ -9333,16 +9351,16 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb, } /* Remove GIMPLE_OMP_ATOMIC_STORE. */ + stmt = gsi_stmt (si); gsi_remove (&si, true); + if (gimple_in_ssa_p (cfun)) + release_defs (stmt); class loop *loop = alloc_loop (); loop->header = loop_header; loop->latch = store_bb; add_loop (loop, loop_header->loop_father); - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); - return true; } @@ -9399,15 +9417,14 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb, gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE); stmt = gimple_build_assign (unshare_expr (mem), stored_val); + gimple_set_vuse (stmt, gimple_vuse (gsi_stmt (si))); + gimple_set_vdef (stmt, gimple_vdef (gsi_stmt (si))); gsi_insert_before (&si, stmt, GSI_SAME_STMT); t = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END); t = build_call_expr (t, 0); force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT); gsi_remove (&si, true); - - if (gimple_in_ssa_p (cfun)) - update_ssa (TODO_update_ssa_no_phi); return true; } diff --git a/gcc/tree-parloops.cc b/gcc/tree-parloops.cc index 2d3aa78cd24..b070527ee6e 100644 --- a/gcc/tree-parloops.cc +++ b/gcc/tree-parloops.cc @@ -3082,7 +3082,7 @@ gen_parallel_loop (class loop *loop, profile_probability::unlikely (), profile_probability::likely (), profile_probability::unlikely (), true); - update_ssa (TODO_update_ssa); + update_ssa (TODO_update_ssa_no_phi); free_original_copy_tables (); } From 4e1914625dec4aa09a5671c6294e877dbf4518f5 Mon Sep 17 00:00:00 2001 From: Andrew Stubbs Date: Fri, 15 Jul 2022 09:47:36 +0100 Subject: [PATCH 15/16] amdgcn: Vector procedure call ABI Adjust the (unofficial) procedure calling ABI such that vector arguments are passed in vector registers, not on the stack. Scalar arguments continue to be passed in scalar registers, making a total of 12 argument registers. The return value is also moved to a vector register (even for scalars; it would be possible to retain the scalar location, using untyped_call, but there's no obvious advantage in doing so). After this change the ABI is as follows: s0-s13 : Reserved for kernel launch parameters. s14-s15 : Frame pointer. s16-s17 : Stack pointer. s18-s19 : Link register. s20-s21 : Exec Save. s22-s23 : CC Save. s24-s25 : Scalar arguments. NO LONGER RETURN VALUE. s26-s29 : Additional scalar arguments (makes 6 total). s30-s31 : Static Chain. v0 : Prologue/epilogue scratch. v1 : Constant 0, 1, 2, 3, 4, ... 63. v2-v7 : Prologue/epilogue scratch. v8-v9 : Return value & vector arguments. NEW. v10-v13 : Additional vector arguments (makes 6 total). NEW. gcc/ChangeLog: * config/gcn/gcn.cc (gcn_function_value): Allow vector return values. (num_arg_regs): Allow vector arguments. (gcn_function_arg): Likewise. (gcn_function_arg_advance): Likewise. (gcn_arg_partial_bytes): Likewise. (gcn_return_in_memory): Likewise. (gcn_expand_epilogue): Get return value from v8. * config/gcn/gcn.h (RETURN_VALUE_REG): Set to v8. (FIRST_PARM_REG): USE FIRST_SGPR_REG for clarity. (FIRST_VPARM_REG): New. (FUNCTION_ARG_REGNO_P): Allow vector parameters. (struct gcn_args): Add vnum field. (LIBCALL_VALUE): All vector return values. * config/gcn/gcn.md (gcn_call_value): Add vector constraints. (gcn_call_value_indirect): Likewise. --- gcc/config/gcn/gcn.cc | 50 +++++++++++++++++++++++++------------------ gcc/config/gcn/gcn.h | 11 ++++++---- gcc/config/gcn/gcn.md | 12 +++++------ 3 files changed, 42 insertions(+), 31 deletions(-) diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc index 6fc20d3f659..96295e23aad 100644 --- a/gcc/config/gcn/gcn.cc +++ b/gcc/config/gcn/gcn.cc @@ -2284,7 +2284,7 @@ gcn_function_value (const_tree valtype, const_tree, bool) && GET_MODE_SIZE (mode) < 4) mode = SImode; - return gen_rtx_REG (mode, SGPR_REGNO (RETURN_VALUE_REG)); + return gen_rtx_REG (mode, RETURN_VALUE_REG); } /* Implement TARGET_FUNCTION_VALUE_REGNO_P. @@ -2308,7 +2308,9 @@ num_arg_regs (const function_arg_info &arg) return 0; int size = arg.promoted_size_in_bytes (); - return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + int regsize = UNITS_PER_WORD * (VECTOR_MODE_P (arg.mode) + ? GET_MODE_NUNITS (arg.mode) : 1); + return (size + regsize - 1) / regsize; } /* Implement TARGET_STRICT_ARGUMENT_NAMING. @@ -2358,16 +2360,16 @@ gcn_function_arg (cumulative_args_t cum_v, const function_arg_info &arg) if (targetm.calls.must_pass_in_stack (arg)) return 0; - /* Vector parameters are not supported yet. */ - if (VECTOR_MODE_P (arg.mode)) - return 0; - - int reg_num = FIRST_PARM_REG + cum->num; + int first_reg = (VECTOR_MODE_P (arg.mode) + ? FIRST_VPARM_REG : FIRST_PARM_REG); + int cum_num = (VECTOR_MODE_P (arg.mode) + ? cum->vnum : cum->num); + int reg_num = first_reg + cum_num; int num_regs = num_arg_regs (arg); if (num_regs > 0) while (reg_num % num_regs != 0) reg_num++; - if (reg_num + num_regs <= FIRST_PARM_REG + NUM_PARM_REGS) + if (reg_num + num_regs <= first_reg + NUM_PARM_REGS) return gen_rtx_REG (arg.mode, reg_num); } else @@ -2419,11 +2421,15 @@ gcn_function_arg_advance (cumulative_args_t cum_v, if (!arg.named) return; + int first_reg = (VECTOR_MODE_P (arg.mode) + ? FIRST_VPARM_REG : FIRST_PARM_REG); + int *cum_num = (VECTOR_MODE_P (arg.mode) + ? &cum->vnum : &cum->num); int num_regs = num_arg_regs (arg); if (num_regs > 0) - while ((FIRST_PARM_REG + cum->num) % num_regs != 0) - cum->num++; - cum->num += num_regs; + while ((first_reg + *cum_num) % num_regs != 0) + (*cum_num)++; + *cum_num += num_regs; } else { @@ -2454,14 +2460,18 @@ gcn_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg) if (targetm.calls.must_pass_in_stack (arg)) return 0; - if (cum->num >= NUM_PARM_REGS) + int cum_num = (VECTOR_MODE_P (arg.mode) ? cum->vnum : cum->num); + int regsize = UNITS_PER_WORD * (VECTOR_MODE_P (arg.mode) + ? GET_MODE_NUNITS (arg.mode) : 1); + + if (cum_num >= NUM_PARM_REGS) return 0; /* If the argument fits entirely in registers, return 0. */ - if (cum->num + num_arg_regs (arg) <= NUM_PARM_REGS) + if (cum_num + num_arg_regs (arg) <= NUM_PARM_REGS) return 0; - return (NUM_PARM_REGS - cum->num) * UNITS_PER_WORD; + return (NUM_PARM_REGS - cum_num) * regsize; } /* A normal function which takes a pointer argument (to a scalar) may be @@ -2549,14 +2559,11 @@ gcn_return_in_memory (const_tree type, const_tree ARG_UNUSED (fntype)) if (AGGREGATE_TYPE_P (type)) return true; - /* Vector return values are not supported yet. */ - if (VECTOR_TYPE_P (type)) - return true; - if (mode == BLKmode) return true; - if (size > 2 * UNITS_PER_WORD) + if ((!VECTOR_TYPE_P (type) && size > 2 * UNITS_PER_WORD) + || size > 2 * UNITS_PER_WORD * 64) return true; return false; @@ -3199,9 +3206,10 @@ gcn_expand_epilogue (void) emit_move_insn (kernarg_reg, retptr_mem); rtx retval_mem = gen_rtx_MEM (SImode, kernarg_reg); + rtx scalar_retval = gen_rtx_REG (SImode, FIRST_PARM_REG); set_mem_addr_space (retval_mem, ADDR_SPACE_SCALAR_FLAT); - emit_move_insn (retval_mem, - gen_rtx_REG (SImode, SGPR_REGNO (RETURN_VALUE_REG))); + emit_move_insn (scalar_retval, gen_rtx_REG (SImode, RETURN_VALUE_REG)); + emit_move_insn (retval_mem, scalar_retval); } emit_jump_insn (gen_gcn_return ()); diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h index a1297605047..318256c4a7a 100644 --- a/gcc/config/gcn/gcn.h +++ b/gcc/config/gcn/gcn.h @@ -138,7 +138,7 @@ #define LINK_REGNUM 18 #define EXEC_SAVE_REG 20 #define CC_SAVE_REG 22 -#define RETURN_VALUE_REG 24 /* Must be divisible by 4. */ +#define RETURN_VALUE_REG 168 /* Must be divisible by 4. */ #define STATIC_CHAIN_REGNUM 30 #define WORK_ITEM_ID_Z_REG 162 #define SOFT_ARG_REG 416 @@ -146,7 +146,8 @@ #define DWARF_LINK_REGISTER 420 #define FIRST_PSEUDO_REGISTER 421 -#define FIRST_PARM_REG 24 +#define FIRST_PARM_REG (FIRST_SGPR_REG + 24) +#define FIRST_VPARM_REG (FIRST_VGPR_REG + 8) #define NUM_PARM_REGS 6 /* There is no arg pointer. Just choose random fixed register that does @@ -164,7 +165,8 @@ #define CC_REG_P(X) (REG_P (X) && CC_REGNO_P (REGNO (X))) #define CC_REGNO_P(X) ((X) == SCC_REG || (X) == VCC_REG) #define FUNCTION_ARG_REGNO_P(N) \ - ((N) >= FIRST_PARM_REG && (N) < (FIRST_PARM_REG + NUM_PARM_REGS)) + (((N) >= FIRST_PARM_REG && (N) < (FIRST_PARM_REG + NUM_PARM_REGS)) \ + || ((N) >= FIRST_VPARM_REG && (N) < (FIRST_VPARM_REG + NUM_PARM_REGS))) #define FIXED_REGISTERS { \ @@ -550,6 +552,7 @@ typedef struct gcn_args tree fntype; struct gcn_kernel_args args; int num; + int vnum; int offset; int alignment; } CUMULATIVE_ARGS; @@ -653,7 +656,7 @@ enum gcn_builtin_codes } /* This needs to match gcn_function_value. */ -#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, SGPR_REGNO (RETURN_VALUE_REG)) +#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, RETURN_VALUE_REG) /* The s_ff0 and s_flbit instructions return -1 if no input bits are set. */ #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = -1, 2) diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md index 70a769babc4..7805e867901 100644 --- a/gcc/config/gcn/gcn.md +++ b/gcc/config/gcn/gcn.md @@ -908,11 +908,11 @@ {}) (define_insn "gcn_call_value" - [(set (match_operand 0 "register_operand" "=Sg,Sg") - (call (mem (match_operand 1 "immediate_operand" "Y,B")) + [(set (match_operand 0 "register_operand" "=Sgv,Sgv") + (call (mem (match_operand 1 "immediate_operand" " Y, B")) (match_operand 2 "const_int_operand"))) (clobber (reg:DI LR_REGNUM)) - (clobber (match_scratch:DI 3 "=&Sg,X"))] + (clobber (match_scratch:DI 3 "=&Sg, X"))] "" "@ s_getpc_b64\t%3\;s_add_u32\t%L3, %L3, %1@rel32@lo+4\;s_addc_u32\t%H3, %H3, %1@rel32@hi+4\;s_swappc_b64\ts[18:19], %3 @@ -921,11 +921,11 @@ (set_attr "length" "24")]) (define_insn "gcn_call_value_indirect" - [(set (match_operand 0 "register_operand" "=Sg") - (call (mem (match_operand:DI 1 "register_operand" "Sg")) + [(set (match_operand 0 "register_operand" "=Sgv") + (call (mem (match_operand:DI 1 "register_operand" " Sg")) (match_operand 2 "" ""))) (clobber (reg:DI LR_REGNUM)) - (clobber (match_scratch:DI 3 "=X"))] + (clobber (match_scratch:DI 3 "= X"))] "" "s_swappc_b64\ts[18:19], %1" [(set_attr "type" "sop1") From 04284176d549ff2565406406a6d53ab4ba8e507d Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 9 Aug 2022 12:48:14 +0200 Subject: [PATCH 16/16] d: Fix undefined reference to pragma(inline) symbol (PR106563) Functions that are declared `pragma(inline)' should be treated as if they are defined in every translation unit they are referenced from, regardless of visibility protection. Ensure they always get DECL_ONE_ONLY linkage, and start emitting them into other modules that import them. PR d/106563 gcc/d/ChangeLog: * decl.cc (DeclVisitor::visit (FuncDeclaration *)): Set semanticRun before generating its symbol. (function_defined_in_root_p): New function. (function_needs_inline_definition_p): New function. (maybe_build_decl_tree): New function. (get_symbol_decl): Call maybe_build_decl_tree before returning symbol. (start_function): Use function_defined_in_root_p instead of inline test for locally defined symbols. (set_linkage_for_decl): Check for inline functions before private or protected symbols. gcc/testsuite/ChangeLog: * gdc.dg/torture/torture.exp (srcdir): New proc. * gdc.dg/torture/imports/pr106563math.d: New test. * gdc.dg/torture/imports/pr106563regex.d: New test. * gdc.dg/torture/imports/pr106563uni.d: New test. * gdc.dg/torture/pr106563.d: New test. --- gcc/d/decl.cc | 121 +++++++++++++++--- .../gdc.dg/torture/imports/pr106563math.d | 12 ++ .../gdc.dg/torture/imports/pr106563regex.d | 7 + .../gdc.dg/torture/imports/pr106563uni.d | 15 +++ gcc/testsuite/gdc.dg/torture/pr106563.d | 16 +++ gcc/testsuite/gdc.dg/torture/torture.exp | 9 ++ 6 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gdc.dg/torture/imports/pr106563math.d create mode 100644 gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d create mode 100644 gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d create mode 100644 gcc/testsuite/gdc.dg/torture/pr106563.d diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 58cea4dec3f..0131b01dcc9 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -828,6 +828,10 @@ public: if (global.errors) return; + /* Start generating code for this function. */ + gcc_assert (d->semanticRun == PASS::semantic3done); + d->semanticRun = PASS::obj; + /* Duplicated FuncDeclarations map to the same symbol. Check if this is the one declaration which will be emitted. */ tree fndecl = get_symbol_decl (d); @@ -844,10 +848,6 @@ public: if (global.params.verbose) message ("function %s", d->toPrettyChars ()); - /* Start generating code for this function. */ - gcc_assert (d->semanticRun == PASS::semantic3done); - d->semanticRun = PASS::obj; - tree old_context = start_function (d); tree parm_decl = NULL_TREE; @@ -1020,13 +1020,103 @@ build_decl_tree (Dsymbol *d) input_location = saved_location; } +/* Returns true if function FD is defined or instantiated in a root module. */ + +static bool +function_defined_in_root_p (FuncDeclaration *fd) +{ + Module *md = fd->getModule (); + if (md && md->isRoot ()) + return true; + + TemplateInstance *ti = fd->isInstantiated (); + if (ti && ti->minst && ti->minst->isRoot ()) + return true; + + return false; +} + +/* Returns true if function FD always needs to be implicitly defined, such as + it was declared `pragma(inline)'. */ + +static bool +function_needs_inline_definition_p (FuncDeclaration *fd) +{ + /* Function has already been defined. */ + if (!DECL_EXTERNAL (fd->csym)) + return false; + + /* Non-inlineable functions are always external. */ + if (DECL_UNINLINABLE (fd->csym)) + return false; + + /* No function body available for inlining. */ + if (!fd->fbody) + return false; + + /* Ignore functions that aren't decorated with `pragma(inline)'. */ + if (fd->inlining != PINLINE::always) + return false; + + /* These functions are tied to the module they are defined in. */ + if (fd->isFuncLiteralDeclaration () + || fd->isUnitTestDeclaration () + || fd->isFuncAliasDeclaration () + || fd->isInvariantDeclaration ()) + return false; + + /* Check whether function will be regularly defined later in the current + translation unit. */ + if (function_defined_in_root_p (fd)) + return false; + + /* Weak functions cannot be inlined. */ + if (lookup_attribute ("weak", DECL_ATTRIBUTES (fd->csym))) + return false; + + /* Naked functions cannot be inlined. */ + if (lookup_attribute ("naked", DECL_ATTRIBUTES (fd->csym))) + return false; + + return true; +} + +/* If the variable or function declaration in DECL needs to be defined, call + build_decl_tree on it now before returning its back-end symbol. */ + +static tree +maybe_build_decl_tree (Declaration *decl) +{ + gcc_assert (decl->csym != NULL_TREE); + + /* Still running semantic analysis on declaration, or it has already had its + code generated. */ + if (doing_semantic_analysis_p || decl->semanticRun >= PASS::obj) + return decl->csym; + + if (error_operand_p (decl->csym)) + return decl->csym; + + if (FuncDeclaration *fd = decl->isFuncDeclaration ()) + { + /* Externally defined inline functions need to be emitted. */ + if (function_needs_inline_definition_p (fd)) + { + DECL_EXTERNAL (fd->csym) = 0; + build_decl_tree (fd); + } + } + + return decl->csym; +} + /* Return the decl for the symbol, create it if it doesn't already exist. */ tree get_symbol_decl (Declaration *decl) { if (decl->csym) - return decl->csym; + return maybe_build_decl_tree (decl); /* Deal with placeholder symbols immediately: SymbolDeclaration is used as a shell around an initializer symbol. */ @@ -1404,7 +1494,7 @@ get_symbol_decl (Declaration *decl) TREE_USED (decl->csym) = 1; d_keep (decl->csym); - return decl->csym; + return maybe_build_decl_tree (decl); } /* Returns a declaration for a VAR_DECL. Used to create compiler-generated @@ -1895,15 +1985,8 @@ start_function (FuncDeclaration *fd) /* Function has been defined, check now whether we intend to send it to object file, or it really is extern. Such as inlinable functions from modules not in this compilation, or thunk aliases. */ - TemplateInstance *ti = fd->isInstantiated (); - if (ti && ti->needsCodegen ()) + if (function_defined_in_root_p (fd)) DECL_EXTERNAL (fndecl) = 0; - else - { - Module *md = fd->getModule (); - if (md && md->isRoot ()) - DECL_EXTERNAL (fndecl) = 0; - } DECL_INITIAL (fndecl) = error_mark_node; @@ -2422,16 +2505,16 @@ set_linkage_for_decl (tree decl) if (!TREE_PUBLIC (decl)) return; - /* Don't need to give private or protected symbols a special linkage. */ - if ((TREE_PRIVATE (decl) || TREE_PROTECTED (decl)) - && !DECL_INSTANTIATED (decl)) - return; - /* Functions declared as `pragma(inline, true)' can appear in multiple translation units. */ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)) return d_comdat_linkage (decl); + /* Don't need to give private or protected symbols a special linkage. */ + if ((TREE_PRIVATE (decl) || TREE_PROTECTED (decl)) + && !DECL_INSTANTIATED (decl)) + return; + /* If all instantiations must go in COMDAT, give them that linkage. This also applies to other extern declarations, so that it is possible for them to override template declarations. */ diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr106563math.d b/gcc/testsuite/gdc.dg/torture/imports/pr106563math.d new file mode 100644 index 00000000000..b9351ea74e2 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr106563math.d @@ -0,0 +1,12 @@ +module imports.pr106563math; + +T nextPow2(T)(const T val) +{ + return powIntegralImpl(val); +} + +pragma(inline, true) +T powIntegralImpl(T)(T) +{ + return 1; +} diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d b/gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d new file mode 100644 index 00000000000..a2cd90c3d8b --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr106563regex.d @@ -0,0 +1,7 @@ +module imports.pr106563regex; +import imports.pr106563uni; + +struct CharMatcher +{ + typeof(MultiArray!().length) trie; +} diff --git a/gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d b/gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d new file mode 100644 index 00000000000..16e3bc85cc0 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/imports/pr106563uni.d @@ -0,0 +1,15 @@ +module imports.pr106563uni; + +struct MultiArray() +{ + @property length() + { + return spaceFor!0(); + } +} + +size_t spaceFor(size_t bits)() +{ + import imports.pr106563math; + return nextPow2(bits); +} diff --git a/gcc/testsuite/gdc.dg/torture/pr106563.d b/gcc/testsuite/gdc.dg/torture/pr106563.d new file mode 100644 index 00000000000..7e15442c0bb --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/pr106563.d @@ -0,0 +1,16 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106563 +// { dg-do link } +// { dg-additional-files "imports/pr106563math.d imports/pr106563regex.d imports/pr106563uni.d" } +// { dg-additional-options "-I[srcdir] -fno-druntime" } +import imports.pr106563math; +import imports.pr106563regex; + +auto requireSize()(size_t size) +{ + return nextPow2(size); +} + +extern(C) int main() +{ + return cast(int)requireSize(0); +} diff --git a/gcc/testsuite/gdc.dg/torture/torture.exp b/gcc/testsuite/gdc.dg/torture/torture.exp index f7d00b1b052..d9c6a79cfe2 100644 --- a/gcc/testsuite/gdc.dg/torture/torture.exp +++ b/gcc/testsuite/gdc.dg/torture/torture.exp @@ -19,6 +19,15 @@ # Load support procs. load_lib gdc-dg.exp +# Helper function allows adding tests that use imports/*, but don't compile +# the sources in with dg-additional-sources. +global testdir +set testdir $srcdir/$subdir +proc srcdir {} { + global testdir + return $testdir +} + # The default option list can be overridden by # TORTURE_OPTIONS="{ { list1 } ... { listN } }"