This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] lreg: multiword registers and endianess
- From: Andreas Krebbel <krebbel1 at de dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 6 Apr 2005 16:48:36 +0200
- Subject: [PATCH] lreg: multiword registers and endianess
- Organization: IBM Deutschland Entwicklung GmbH
Hi,
the divmod pattern on S/390 has DImode inputs and produces a TImode output.
The inputs are coupled with the output via a matching constraint. So
local-alloc:combine_regs assigns the registers to the same quantity.
e.g. If we have a (reg:TI 80) as output and a (reg:DI 84) as input both get the
same register in local alloc:
21.lreg:
;; Register 80 in 2.
;; Register 84 in 2.
But thats wrong on machines with WORDS_BIG_ENDIAN as reload notices using
operands_match_p in find_reloads. Hence reload tries to fix this adding
insns which need an additional hard reg.
With the attached patch reg_offset for pseudo 80 is set to 1 so that 80
gets hard reg 3 assigned which is what reload expects.
The patch checks whether two regs of different mode sizes are about to be
combined. On a machine with WORDS_BIG_ENDIAN the local variable offset is
modified which will later be used to calculate the new reg_offset entries
for the registers of that quantity.
Additionally I've replaced the checks whether the input fits into the output
and vice versa. That circumvented registers of different modes to be tied
together. Instead I think combining should be avoided when the input and
output registers are overlapping.
Bootstrapped and regtested on mainline for s390, s390x and i686.
OK for mainline?
Bye,
-Andreas-
2005-04-05 Andreas Krebbel <krebbel1@de.ibm.com>
* local-alloc.c (combine_regs): Adjust reg_offset if regs with different mode
sizes are combined on big endian machines.
Index: gcc/local-alloc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/local-alloc.c,v
retrieving revision 1.144
diff -p -c -r1.144 local-alloc.c
*** gcc/local-alloc.c 16 Dec 2004 16:48:23 -0000 1.144
--- gcc/local-alloc.c 5 Apr 2005 08:13:28 -0000
*************** combine_regs (rtx usedreg, rtx setreg, i
*** 1749,1754 ****
--- 1749,1778 ----
int usize, ssize;
int sqty;
+ if (WORDS_BIG_ENDIAN
+ && SCALAR_INT_MODE_P (GET_MODE (setreg))
+ && SCALAR_INT_MODE_P (GET_MODE (usedreg))
+ && GET_MODE_SIZE (GET_MODE (setreg)) != GET_MODE_SIZE (GET_MODE (usedreg))
+ && (GET_MODE_SIZE (GET_MODE (setreg)) > UNITS_PER_WORD
+ || GET_MODE_SIZE (GET_MODE (usedreg)) > UNITS_PER_WORD))
+ {
+ if (REG_P (setreg) && REGNO (setreg) < FIRST_PSEUDO_REGISTER)
+ ssize = hard_regno_nregs[REGNO (setreg)][GET_MODE (setreg)];
+ else
+ ssize = ((GET_MODE_SIZE (GET_MODE (setreg))
+ + (REGMODE_NATURAL_SIZE (GET_MODE (setreg)) - 1))
+ / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
+
+ if (REG_P (usedreg) && REGNO (usedreg) < FIRST_PSEUDO_REGISTER)
+ usize = hard_regno_nregs[REGNO (usedreg)][GET_MODE (usedreg)];
+ else
+ usize = ((GET_MODE_SIZE (GET_MODE (usedreg))
+ + (REGMODE_NATURAL_SIZE (GET_MODE (usedreg)) - 1))
+ / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
+
+ offset = usize - ssize;
+ }
+
/* Determine the numbers and sizes of registers being used. If a subreg
is present that does not change the entire register, don't consider
this a copy insn. */
*************** combine_regs (rtx usedreg, rtx setreg, i
*** 1823,1831 ****
quantity number, it means that it is not local to this block or dies
more than once. In either event, we can't do anything with it. */
if ((ureg >= FIRST_PSEUDO_REGISTER && reg_qty[ureg] < 0)
! /* Do not combine registers unless one fits within the other. */
! || (offset > 0 && usize + offset > ssize)
! || (offset < 0 && usize + offset < ssize)
/* Do not combine with a smaller already-assigned object
if that smaller object is already combined with something bigger. */
|| (ssize > usize && ureg >= FIRST_PSEUDO_REGISTER
--- 1847,1855 ----
quantity number, it means that it is not local to this block or dies
more than once. In either event, we can't do anything with it. */
if ((ureg >= FIRST_PSEUDO_REGISTER && reg_qty[ureg] < 0)
! /* Do not combine registers if they overlap. */
! || (ureg - offset <= sreg && ureg + usize > sreg + MIN (offset, 0))
! || (ureg - offset >= sreg && ureg - MAX (offset, 0) < sreg + ssize)
/* Do not combine with a smaller already-assigned object
if that smaller object is already combined with something bigger. */
|| (ssize > usize && ureg >= FIRST_PSEUDO_REGISTER