From: Jeff Law Date: Fri, 7 Feb 2025 16:10:59 +0000 (-0700) Subject: [rtl-optimization/116244] Don't create bogus regs in alter_subreg X-Git-Tag: basepoints/gcc-16~2125 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=388910144a3f11ba61208fc80afb2fa78d657163;p=thirdparty%2Fgcc.git [rtl-optimization/116244] Don't create bogus regs in alter_subreg > Jeff Law writes: >> So pulling on this thread leads me into the code that sets up >> ALLOCNO_WMODE in create_insn_allocnos: >> >>> if ((a = ira_curr_regno_allocno_map[regno]) == NULL) >>> { >>> a = ira_create_allocno (regno, false, ira_curr_loop_tree_node); >>> if (outer != NULL && GET_CODE (outer) == SUBREG) >>> { >>> machine_mode wmode = GET_MODE (outer); >>> if (partial_subreg_p (ALLOCNO_WMODE (a), wmode)) >>> ALLOCNO_WMODE (a) = wmode; >>> } >>> } >> Note how we only set ALLOCNO_MODE only at allocno creation, so it'll >> work as intended if and only if the first reference is via a SUBREG. > > Huh, yeah, I agree that that looks wrong. > >> ISTM the fix here is to always do the check and set ALLOCNO_WMODE. >>[ Snipped discussion on a non-issue. ] > > So ISTM that moving the code out of the "if (... == NULL)" should be > enough on its own. > >> And it all makes sense that you caught this. You and another colleague >> at ARM were trying to address this exact problem ~11 years ago ;-) > > Heh, thought it sounded familiar :) So attached is the updated patch that adjusts IRA to avoid this problem. Georg-Johann, this may explain an issue you were running into as well where you got an invalid allocation. I think yours was at the higher end of the register file, but the core issue is potentially the same (looking at the first use rather than all of them for paradoxical subregs). I've had this in my tester about a week. So it's been through the crosses as well as various native bootstraps, including but not limited to m68k, ppc, s390, hppa, sh4, etc. And just for good measure I bootstrapped & regression tested it on x86_64 a few minutes ago. Pushing to the trunk. PR rtl-optimization/116244 gcc/ * ira-build.cc (create_insn_allocnos): Do not restrict the check for subreg uses to allocno creation time. Do it for all uses. gcc/testsuite/ * g++.target/m68k/m68k.exp: New test driver. * g++.target/m68k/pr116244.C: New test. --- diff --git a/gcc/ira-build.cc b/gcc/ira-build.cc index ac84f512460b..991dfbb3da3c 100644 --- a/gcc/ira-build.cc +++ b/gcc/ira-build.cc @@ -1851,14 +1851,15 @@ create_insn_allocnos (rtx x, rtx outer, bool output_p) ira_allocno_t a; if ((a = ira_curr_regno_allocno_map[regno]) == NULL) + a = ira_create_allocno (regno, false, ira_curr_loop_tree_node); + + /* This used to only trigger at allocno creation which seems + wrong. We care about the WMODE propery across all the uses. */ + if (outer != NULL && GET_CODE (outer) == SUBREG) { - a = ira_create_allocno (regno, false, ira_curr_loop_tree_node); - if (outer != NULL && GET_CODE (outer) == SUBREG) - { - machine_mode wmode = GET_MODE (outer); - if (partial_subreg_p (ALLOCNO_WMODE (a), wmode)) - ALLOCNO_WMODE (a) = wmode; - } + machine_mode wmode = GET_MODE (outer); + if (partial_subreg_p (ALLOCNO_WMODE (a), wmode)) + ALLOCNO_WMODE (a) = wmode; } ALLOCNO_NREFS (a)++; diff --git a/gcc/testsuite/g++.target/m68k/m68k.exp b/gcc/testsuite/g++.target/m68k/m68k.exp new file mode 100644 index 000000000000..8f6416e9fdfc --- /dev/null +++ b/gcc/testsuite/g++.target/m68k/m68k.exp @@ -0,0 +1,34 @@ +# Copyright (C) 2019-2024 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a m68k target. +if ![istarget m68k*-*-*] then { + return +} + +# Load support procs. +load_lib g++-dg.exp + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" "" + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.target/m68k/pr116244.C b/gcc/testsuite/g++.target/m68k/pr116244.C new file mode 100644 index 000000000000..2e78832efbb5 --- /dev/null +++ b/gcc/testsuite/g++.target/m68k/pr116244.C @@ -0,0 +1,226 @@ +// { dg-do compile } +// { dg-additional-options "-std=gnu++20 -O2 -w -march=isaa" } +namespace std { +struct __conditional { + template using type = _Tp; +}; +template +using __conditional_t = __conditional::type<_If, _Else>; +template constexpr bool is_lvalue_reference_v = true; +template bool is_same_v; +template +constexpr bool is_convertible_v = __is_convertible(_From, _To); +template bool is_invocable_v; +template using common_reference_t = int; +template struct iterator_traits : _Iterator {}; +namespace __detail { +template +concept __same_as = is_same_v<_Up>; +} +template +concept same_as = __detail::__same_as<_Up, _Tp>; +template +concept derived_from = is_convertible_v<_Derived, _Base>; +template +concept common_reference_with = + same_as, common_reference_t<>>; +namespace __detail { +template +concept __boolean_testable = requires(_Tp __t) { __t; }; +template +concept __weakly_eq_cmp_with = requires(_Tp __t) { __t; }; +} // namespace __detail +template +concept invocable = is_invocable_v<_Args...>; +template +concept regular_invocable = invocable<>; +template +concept predicate = __detail::__boolean_testable<_Fn>; +template +concept relation = predicate<_Rel>; +template +concept strict_weak_order = relation<_Rel, _Tp, _Up>; +namespace { +struct duration { + duration() = default; + template duration(_Rep2 __rep) : __r(__rep) {} + long long count() { return __r; } + long long __r; +}; +long long operator+(duration __lhs, duration __rhs) { + long __trans_tmp_1 = __lhs.count(); + return __trans_tmp_1 + __rhs.count(); +} +struct time_point { + time_point(); + time_point(duration __dur) : __d(__dur) {} + duration time_since_epoch() { return __d; } + duration __d; +}; +time_point operator+(time_point __lhs, duration __rhs) { + duration __trans_tmp_2 = __lhs.time_since_epoch(); + return time_point(__trans_tmp_2 + __rhs); +} +template using sys_time = time_point; +} // namespace +template class allocator; +namespace { +struct less {}; +} // namespace +struct forward_iterator_tag {}; +namespace __detail { +template struct __iter_traits_impl { + using type = iterator_traits<_Iter>; +}; +template using __iter_traits = __iter_traits_impl<_Iter>::type; +template struct __iter_concept_impl; +template + requires requires { typename _Iter; } +struct __iter_concept_impl<_Iter> { + using type = __iter_traits<_Iter>::iterator_concept; +}; +template +using __iter_concept = __iter_concept_impl<_Iter>::type; +template +concept __indirectly_readable_impl = common_reference_with<_In, _In>; +} // namespace __detail +template +concept indirectly_readable = __detail::__indirectly_readable_impl<_In>; +template +concept input_or_output_iterator = requires(_Iter __i) { __i; }; +template +concept sentinel_for = __detail::__weakly_eq_cmp_with<_Sent, _Iter>; +template +concept forward_iterator = + derived_from<__detail::__iter_concept<_Iter>, forward_iterator_tag>; +template +concept indirectly_regular_unary_invocable = regular_invocable<_Fn>; +template +concept indirect_strict_weak_order = strict_weak_order<_Fn, _I1, _I2>; +namespace __detail { +template struct __projected; +} +template _Proj> +using projected = __detail::__projected<_Iter, _Proj>; +namespace ranges::__access { +template auto __begin(_Tp __t) { return __t.begin(); } +} // namespace ranges::__access +namespace __detail { +template +using __range_iter_t = decltype(ranges::__access::__begin(_Tp())); +} +template struct iterator_traits<_Tp *> { + typedef forward_iterator_tag iterator_concept; + using reference = _Tp; +}; +} // namespace std +template struct __normal_iterator { + using iterator_concept = std::__detail::__iter_concept<_Iterator>; + std::iterator_traits<_Iterator>::reference operator*(); + void operator++(); +}; +template +bool operator==(__normal_iterator<_IteratorL, _Container>, + __normal_iterator<_IteratorR, _Container>); +int _M_get_sys_info_ri; +namespace std { +template struct allocator_traits; +template struct allocator_traits> { + using pointer = _Tp *; +}; +namespace { +namespace __detail { +template +concept __maybe_borrowed_range = is_lvalue_reference_v<_Tp>; +} +int end; +template +concept range = requires { end; }; +template +concept borrowed_range = __detail::__maybe_borrowed_range<_Tp>; +template using iterator_t = std::__detail::__range_iter_t<_Tp>; +template +concept forward_range = forward_iterator>; +struct dangling; +template _Sent = _It> +struct subrange { + _It begin(); + _Sent end(); +}; +template +using borrowed_subrange_t = + __conditional_t, subrange>, + dangling>; +} // namespace +template struct _Vector_base { + typedef allocator_traits<_Alloc>::pointer pointer; +}; +template > struct vector { + __normal_iterator::pointer, int> begin(); +}; +template struct __shared_ptr_access { + _Tp *operator->(); +}; +namespace chrono { +struct weekday { + char _M_wd; + weekday _S_from_days() { + long __trans_tmp_3; + return 7 > __trans_tmp_3; + } + weekday(unsigned __wd) : _M_wd(__wd == 7 ?: __wd) {} + weekday() : weekday{_S_from_days()} {} + unsigned c_encoding() { return _M_wd; } + friend duration operator-(weekday __x, weekday __y) { + auto __n = __x.c_encoding() - __y.c_encoding(); + return int(__n) >= 0 ? __n : duration{}; + } +}; +struct year_month_day { + year_month_day _S_from_days(duration __dp) { + auto __r0 = int(__dp.count()), __u2 = 5 * __r0; + year_month_day{__u2}; + } + year_month_day(); + year_month_day(int); + year_month_day(sys_time __dp) + : year_month_day(_S_from_days(__dp.time_since_epoch())) {} +}; +struct time_zone { + void _M_get_sys_info() const; +}; +} // namespace chrono +namespace ranges { +struct { + template < + forward_range _Range, typename _Tp, typename _Proj, + indirect_strict_weak_order<_Tp, projected<_Range, _Proj>> _Comp = less> + borrowed_subrange_t<_Range> operator()(_Range, _Tp, _Comp, _Proj); +} equal_range; +} // namespace ranges +} // namespace std +namespace std::chrono { +struct Rule; +unsigned day_of_week; +struct _Node { + vector rules; +}; +char name; +struct Rule { + int from; + void start_time(int, long) { + year_month_day ymd; + sys_time date; + duration diff = day_of_week - weekday{}; + ymd = date + diff; + } +}; +__shared_ptr_access<_Node> __trans_tmp_5; +void time_zone::_M_get_sys_info() const { + auto node = __trans_tmp_5; + auto rules = ranges::equal_range(node->rules, _M_get_sys_info_ri, {}, name); + for (auto rule : rules) + rule.start_time(rule.from, {}); +} +} // namespace std::chrono