This is the mail archive of the gcc@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]

Register allocation and paradoxical subregs on SPARC64


Hi,

This is PR optimization/10904. GCC 3.3 and mainline generate illegal assembly

	fdtox	%f10, %f7   (illegal, odd-numbered FP reg)

at -O2 for

	int a = (long)(b * ((double) 0.1));

under certain circumstances on SPARC64. Note that this is a progression from 
GCC 3.2.x which silently generates wrong code in the same situation.


Here's the chain of events: the combiner turns

(insn 30 29 31 0 0x40182fc0 (set (reg:DI 118)
        (fix:DI (fix:DF (reg:DF 117)))) 167 {fix_truncdfdi2} (insn_list 29 
(nil))
    (expr_list:REG_DEAD (reg:DF 117)
        (nil)))

(insn 31 30 33 0 0x40182fc0 (set (reg/v:SI 112)
        (subreg:SI (reg:DI 118) 4)) 51 {*movsi_insn} (insn_list 30 (nil))
    (expr_list:REG_DEAD (reg:DI 118)
        (nil)))

into

(insn 31 30 33 0 0x40182fc0 (set (subreg:DI (reg/v:SI 112) 0)
        (fix:DI (fix:DF (reg:DF 117)))) 167 {fix_truncdfdi2} (insn_list 29 
(nil))
    (expr_list:REG_DEAD (reg:DF 117)
        (nil)))

which I think is correct on big-endian targets.

Then the (global) register allocator allocates %f8 to (reg/v:SI 112) because 
it doesn't know that the pseudo has been paradoxically subreged. So 
(subreg:DI (reg/v:SI 112) 0) ends up being assigned %f7-%f8.


How is this supposed to work? I think that the register allocator must be 
taught to consider the constraints introduced by the subreg-ization. I see 
that the machinery (subregs_of_mode, cannot_change_mode_set_regs in 
regclass.c) has already been added by Aldy Hernandez. However,

(1) Even if I define CANNOT_CHANGE_MODE_CLASS for Sparc, it won't be 
sufficient since the register classes of the Sparc port don't differentiate 
between odd- and even-numbered regs. That information is only contained in 
the HARD_REGNO_MODE_OK macro.

(2) cannot_change_mode_set_regs can't handle paradoxical subregs on 
big-endian targets.


I think (1) can be fixed by instructing REG_CANNOT_CHANGE_MODE_P

/* Given a hard REGN a FROM mode and a TO mode, return nonzero if
   REGN cannot change modes between the specified modes.  */
#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, TO)                          \
         CANNOT_CHANGE_MODE_CLASS (FROM, TO, REGNO_REG_CLASS (REGN))

to additionally check whether HARD_REGNO_MODE_OK(REGN, TO) is true.

(2) could be fixed by adding explicit code to cannot_change_mode_set_regs in 
order to check that the first register overlapped by the paradoxical subreg, 
and not the base register, can be used in the 'to' mode. In the present 
situation, it would mark all even-numbered FP regs as used so that the 
pseudo (reg/v:SI 112) gets an odd-numbered FP reg.


Does it seem like a sensible solution?

-- 
Eric Botcazou


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