LRA does elimination but not always checks insn constraints in this case.
This results in LRA failure for PDP11 target whose addition is only 2-op insn.
The same might happen for other analogous targets. The patch fixes this problem.
PR rtl-optimization/108388
gcc/ChangeLog:
* lra-constraints.cc (get_hard_regno): Remove final_p arg. Always
do elimination but only for hard register.
(operands_match_p, uses_hard_regs_p, process_alt_operands): Adjust
calls of get_hard_regno.
gcc/testsuite/ChangeLog:
* gcc.target/pdp11/pdp11.exp: New.
* gcc.target/pdp11/pr108388.c: New.
return ira_class_hard_regs[rclass][0];
}
-/* Return the hard regno of X after removing its subreg. If X is not
- a register or a subreg of a register, return -1. If X is a pseudo,
- use its assignment. If FINAL_P return the final hard regno which will
- be after elimination. */
+/* Return the hard regno of X after removing its subreg. If X is not a
+ register or a subreg of a register, return -1. If X is a pseudo, use its
+ assignment. If X is a hard regno, return the final hard regno which will be
+ after elimination. */
static int
-get_hard_regno (rtx x, bool final_p)
+get_hard_regno (rtx x)
{
rtx reg;
int hard_regno;
hard_regno = lra_get_regno_hard_regno (hard_regno);
if (hard_regno < 0)
return -1;
- if (final_p)
+ if (HARD_REGISTER_NUM_P (REGNO (reg)))
hard_regno = lra_get_elimination_hard_regno (hard_regno);
if (SUBREG_P (x))
hard_regno += subreg_regno_offset (hard_regno, GET_MODE (reg),
{
int j;
- i = get_hard_regno (x, false);
+ i = get_hard_regno (x);
if (i < 0)
goto slow;
if (REG_P (x) || SUBREG_P (x))
{
- x_hard_regno = get_hard_regno (x, true);
+ x_hard_regno = get_hard_regno (x);
return (x_hard_regno >= 0
&& overlaps_hard_reg_set_p (set, mode, x_hard_regno));
}
op = no_subreg_reg_operand[nop] = *curr_id->operand_loc[nop];
/* The real hard regno of the operand after the allocation. */
- hard_regno[nop] = get_hard_regno (op, true);
+ hard_regno[nop] = get_hard_regno (op);
operand_reg[nop] = reg = op;
biggest_mode[nop] = GET_MODE (op);
&& curr_operand_mode[m] != curr_operand_mode[nop])
break;
- m_hregno = get_hard_regno (*curr_id->operand_loc[m], false);
+ m_hregno = get_hard_regno (*curr_id->operand_loc[m]);
/* We are supposed to match a previous operand.
If we do, we win if that one did. If we do
not, count both of the operands as losers.
--- /dev/null
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't an pdp11 target.
+if ![istarget pdp11*-*-*] then {
+ return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
+ "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2 -mlra" } */
+
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+extern DItype __mulvdi3 (DItype, DItype);
+struct DWstruct {SItype high, low;};
+
+typedef union {
+ struct DWstruct s;
+ DItype ll;
+} DWunion;
+
+DItype __mulvdi3 (DItype u, DItype v) {
+ const DWunion uu = {.ll = u};
+ const DWunion vv = {.ll = v};
+
+ if (__builtin_expect (uu.s.high == uu.s.low >> ((4 * 8) - 1), 1)) {
+ if (__builtin_expect (vv.s.high == vv.s.low >> ((4 * 8) - 1), 1)) {
+ return (DItype) uu.s.low * (DItype) vv.s.low;
+ } else {
+ DWunion w0 = {.ll = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.low};
+ DWunion w1 = {.ll = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.high};
+
+ if (vv.s.high < 0)
+ w1.s.high -= uu.s.low;
+ if (uu.s.low < 0)
+ w1.ll -= vv.ll;
+ w1.ll += (USItype) w0.s.high;
+ if (__builtin_expect (w1.s.high == w1.s.low >> ((4 * 8) - 1), 1)) {
+ w0.s.high = w1.s.low;
+ return w0.ll;
+ }
+ }
+ } else {
+ if (__builtin_expect (vv.s.high == vv.s.low >> ((4 * 8) - 1), 1)) {
+ DWunion w0 = {.ll = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.low};
+ DWunion w1 = {.ll = (UDItype) (USItype) uu.s.high * (UDItype) (USItype) vv.s.low};
+
+ if (uu.s.high < 0)
+ w1.s.high -= vv.s.low;
+ if (vv.s.low < 0)
+ w1.ll -= uu.ll;
+ w1.ll += (USItype) w0.s.high;
+ if (__builtin_expect (w1.s.high == w1.s.low >> ((4 * 8) - 1), 1)) {
+ w0.s.high = w1.s.low;
+ return w0.ll;
+ }
+ } else {
+ if (uu.s.high >= 0) {
+ if (vv.s.high >= 0) {
+ if (uu.s.high == 0 && vv.s.high == 0) {
+ const DItype w = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.low;
+ if (__builtin_expect (w >= 0, 1))
+ return w;
+ }
+ } else {
+ if (uu.s.high == 0 && vv.s.high == (SItype) -1) {
+ DWunion ww = {.ll = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.low};
+ ww.s.high -= uu.s.low;
+ if (__builtin_expect (ww.s.high < 0, 1))
+ return ww.ll;
+ }
+ }
+ } else {
+ if (vv.s.high >= 0) {
+ if (uu.s.high == (SItype) -1 && vv.s.high == 0) {
+ DWunion ww = {.ll = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.low};
+
+ ww.s.high -= vv.s.low;
+ if (__builtin_expect (ww.s.high < 0, 1))
+ return ww.ll;
+ }
+ } else {
+ if ((uu.s.high & vv.s.high) == (SItype) -1 && (uu.s.low | vv.s.low) != 0) {
+ DWunion ww = {.ll = (UDItype) (USItype) uu.s.low * (UDItype) (USItype) vv.s.low};
+
+ ww.s.high -= uu.s.low;
+ ww.s.high -= vv.s.low;
+ if (__builtin_expect (ww.s.high >= 0, 1))
+ return ww.ll;
+ }
+ }
+ }
+ }
+ }
+ __builtin_trap ();
+}