[3.4] PR target/15289

Jan Hubicka jh@suse.cz
Sun Aug 29 15:42:00 GMT 2004


Hi,
the problem is in frontend emitting (on i386, but it is generic problem anyway):


(insn 12 11 13 0 (nil) (set (reg:QI 63)
        (subreg:QI (reg/v:SI 59) 0)) -1 (nil)
    (nil))

(insn 13 12 14 0 (nil) (set (reg:QI 64)
        (subreg:QI (reg/v:SI 59) 1)) -1 (nil)
    (nil))

to move value from (reg:CQI 59) into (concat:CQI (reg 63) (reg 64)).
I know of nothing in the backend that is supposed to deal properly with these
registers.  On old gcc the testcase used to pass IMO by accident as can be seen
on code produced by reload in GCC 3.4:

(insn:HI 12 11 71 0 (nil) (set (reg:QI 1 dl [63])
        (reg:QI 2 cl [59])) 47 {*movqi_1} (insn_list 3 (nil))
    (nil))

(insn 71 12 72 0 (nil) (set (reg:SI 4 esi)
        (reg/v:SI 2 ecx [59])) 38 {*movsi_1} (nil)
    (nil))

(insn 72 71 13 0 (nil) (set (reg:QI 0 al [64])
        (reg:QI 4 sil)) 47 {*movqi_1} (nil)
    (nil))

(insn:HI 13 72 14 0 (nil) (set (reg:QI 0 al [64])
        (reg:QI 0 al [64])) 47 {*movqi_1} (nil)
    (nil))

that is semantically very different - instead of using upper half of 16bit
register 59 (ecx), it is load by lower half again.

expr.c already contains code to avoid these subregs being output for hard
registers.  I believe only proper sollution is to avoid these being output for
pseudos and subregs as well.  The attached patch does exactly that and has been
tested on i686-pc-gnu-linux, x86-64-pc-gnu-linux, ia64-pc-gnu-linux and
ppc64-pc-gnu-linux.

On ia64 it happens to fix following execute/20020227-1.c that has similar
code dealing with float registers.

I am not 100% convinced that this is the best fix as it might penalize complex
values of floats on 64bit machines (but I didn't find obvious testcase as at
least on x86-64 these values are always concats of two registers)

Honza

/* On powerpc-linux -O1, this testcase ICEs on hammer branch, and
   generates wrong code on gcc-3.4.0 and mainline.  */

typedef struct { _Complex char a; _Complex char b; } Scc2;

Scc2 s = { 1+2i, 3+4i };

int checkScc2 (Scc2 s)
{
  return s.a != 1+2i || s.b != 3+4i;
}

int main (void)
{
  return checkScc2 (s);
}
2004-08-29  Jan Hubicka  <jh@suse.cz>
	PR target/15289
	* expr.c (emit_move_insn_1): Always use memory for converting complex
	moves of values smaller than short.
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.615.4.14
diff -c -3 -p -r1.615.4.14 expr.c
*** expr.c	27 May 2004 19:35:17 -0000	1.615.4.14
--- expr.c	28 Aug 2004 14:40:12 -0000
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2975,2984 ****
  	  if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
  	      && (reload_in_progress | reload_completed) == 0)
  	    {
! 	      int packed_dest_p
! 		= (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
! 	      int packed_src_p
! 		= (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
  
  	      if (packed_dest_p || packed_src_p)
  		{
--- 2975,2982 ----
  	  if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
  	      && (reload_in_progress | reload_completed) == 0)
  	    {
! 	      int packed_dest_p = REG_P (x) || GET_CODE (x) == SUBREG;
! 	      int packed_src_p = REG_P (y) || GET_CODE (y) == SUBREG;
  
  	      if (packed_dest_p || packed_src_p)
  		{
*************** emit_move_insn_1 (rtx x, rtx y)
*** 2999,3012 ****
  
  		      if (packed_dest_p)
  			{
! 			  rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
  
  			  emit_move_insn_1 (cmem, y);
  			  return emit_move_insn_1 (sreg, mem);
  			}
  		      else
  			{
! 			  rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
  
  			  emit_move_insn_1 (mem, sreg);
  			  return emit_move_insn_1 (x, cmem);
--- 2997,3012 ----
  
  		      if (packed_dest_p)
  			{
! 			  rtx sreg = simplify_gen_subreg (reg_mode, x,
! 					  		  GET_MODE (x), 0);
  
  			  emit_move_insn_1 (cmem, y);
  			  return emit_move_insn_1 (sreg, mem);
  			}
  		      else
  			{
! 			  rtx sreg = simplify_gen_subreg (reg_mode, y,
! 					  		  GET_MODE (y), 0);
  
  			  emit_move_insn_1 (mem, sreg);
  			  return emit_move_insn_1 (x, cmem);



More information about the Gcc-patches mailing list