[RFC,PATCH] combine: Don't simplify subregs of promoted types

Andreas Krebbel krebbel1@de.ibm.com
Mon Sep 4 11:24:00 GMT 2006


Hello,

gcc currently fails to make use of the information that the
result of a function is already promoted to a wider type.

This is especially annoying on 64bit where an int type is often
used to indicate the error condition. E.g. the following code contains
a pointless sign extend instruction in function g (when sibling call 
optimization is disabled):

int f () { return 1; }
int g () { return f (); }

The DI result of f is accessed by a subreg with the /s flag which
states that this is a subreg of a promoted type value. combine could
optimize this when combining insn 9 with 10. The code in simplify-rtx.c:818
(simplify_unary_operation_1) would then remove the sign_extend.

(insn 8 7 9 2 (set (reg:DI 45)
        (reg:DI 2 %r2)) 51 {*movdi_64} (insn_list:REG_DEP_TRUE 7 (nil))
    (expr_list:REG_DEAD (reg:DI 2 %r2)
        (nil)))

(insn 9 8 10 2 (set (reg:SI 43 [ D.1515 ])
        (subreg/s:SI (reg:DI 45) 4)) 55 {*movsi_zarch} (insn_list:REG_DEP_TRUE 8 (nil))
    (expr_list:REG_DEAD (reg:DI 45)
        (nil)))

(insn 10 9 14 2 (set (reg:DI 47 [ D.1515 ])
        (sign_extend:DI (reg:SI 43 [ D.1515 ]))) 113 {*extendsidi2} (insn_list:REG_DEP_TRUE 9 (nil))
    (expr_list:REG_DEAD (reg:SI 43 [ D.1515 ])
        (nil)))

Unfortunately combine optimizes insn 8 and 9 first to (set (reg:SI 43) (reg:SI 2)).
In this step we lose the subreg and with it the information that the value is
already sign extended.

The attached patch prevents combine from optimizing subregs with the /s flag set since
this is a valueable information. With the patch applied I get a 890 byte smaller cc1
executable on s390x -0.003%). The number of lgfr (32 -> 64bit sign extend) instructions goes 
down from 21399 to 21083 by 316 (-1.48%).

The same occurs on i386 and s390 (31bit) when using return types smaller than int.

Another point is that combine doesn't draw the promotion of return types into account when
doing its nonzero_bits analysis. I see that the information for incoming arguments is used
but not for the return type - is there a special reason for this?

Bootstrapped on s390x - s390 and i686 still running.
No testsuite regressions so far.

OK for 4.3?

Bye,

-Andreas-

Index: gcc/combine.c
===================================================================
*** gcc/combine.c.orig	2006-09-01 11:09:16.000000000 +0200
--- gcc/combine.c	2006-09-01 11:11:38.000000000 +0200
*************** combine_simplify_rtx (rtx x, enum machin
*** 4377,4389 ****
  
        if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
  	break;
!       {
! 	rtx temp;
! 	temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
! 				SUBREG_BYTE (x));
! 	if (temp)
! 	  return temp;
!       }
  
        /* Don't change the mode of the MEM if that would change the meaning
  	 of the address.  */
--- 4377,4391 ----
  
        if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
  	break;
! 
!       if (!SUBREG_PROMOTED_VAR_P (x))
! 	{
! 	  rtx temp;
! 	  temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
! 				  SUBREG_BYTE (x));
! 	  if (temp)
! 	    return temp;
! 	}
  
        /* Don't change the mode of the MEM if that would change the meaning
  	 of the address.  */
*************** simplify_set (rtx x)
*** 5167,5173 ****
       low-order bits.  */
  
    if (GET_MODE_CLASS (mode) == MODE_INT
!       && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
      {
        src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, 0);
        SUBST (SET_SRC (x), src);
--- 5169,5176 ----
       low-order bits.  */
  
    if (GET_MODE_CLASS (mode) == MODE_INT
!       && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
!       && (GET_CODE (src) != SUBREG || !SUBREG_PROMOTED_VAR_P (src)))
      {
        src = force_to_mode (src, mode, ~(HOST_WIDE_INT) 0, 0);
        SUBST (SET_SRC (x), src);
*************** make_compound_operation (rtx x, enum rtx
*** 6597,6628 ****
  
        tem = make_compound_operation (SUBREG_REG (x), in_code);
  
!       {
! 	rtx simplified;
! 	simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
! 				      SUBREG_BYTE (x));
! 
! 	if (simplified)
! 	  tem = simplified;
! 
! 	if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
! 	    && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
! 	    && subreg_lowpart_p (x))
! 	  {
! 	    rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
! 				       0);
! 
! 	    /* If we have something other than a SUBREG, we might have
  	       done an expansion, so rerun ourselves.  */
! 	    if (GET_CODE (newer) != SUBREG)
! 	      newer = make_compound_operation (newer, in_code);
  
! 	    return newer;
! 	  }
! 
! 	if (simplified)
! 	  return tem;
!       }
        break;
  
      default:
--- 6600,6638 ----
  
        tem = make_compound_operation (SUBREG_REG (x), in_code);
  
!       if (SUBREG_PROMOTED_VAR_P (x))
! 	{
! 	  SUBST (SUBREG_REG (x), tem);
! 	  return x;
! 	}
!       else
! 	{
! 	  rtx simplified;
! 	  simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
! 					SUBREG_BYTE (x));
! 
! 	  if (simplified)
! 	    tem = simplified;
! 	  
! 	  if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
! 	      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
! 	      && subreg_lowpart_p (x))
! 	    {
! 	      rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
! 					 0);
! 	      
! 	      /* If we have something other than a SUBREG, we might have
  	       done an expansion, so rerun ourselves.  */
! 	      if (GET_CODE (newer) != SUBREG)
! 		newer = make_compound_operation (newer, in_code);
  
! 	      return newer;
! 	    }
! 	  
! 	  if (simplified)
! 	    return tem;
! 	  
! 	}
        break;
  
      default:



More information about the Gcc-patches mailing list