This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] lreg: multiword registers and endianess


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]