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] Promoted variable SUBREG optimizations


The following patch fixes the failure of gcc.dg/uninit-A.c on alpha.
A reduced form of this testcase is shown below

void foo()
{
  int again, name;

  do {
    if (bar())
    {
      again = 1;
      continue;
    }
    name = baz();
    again = 0;
  } while (again);
  return name;
}

In this much reduced example, the failure mode is that -O2 -Wall
generates a variable may be used uninitialized warning for name.
Clearly, GCC can determine that name is always initialized provided
it can rule out that the "continue" in the if-statement that jumps
to the loop exit condition is unable to leave the loop.  On most
platforms this is determined by the jump bypassing pass that realizes
that again is always 1 on the continue, edge so the back edge of
the do-while must always be taken.  i.e. continue should jump back
to bar.

So the problem boils down to why jump bypassing is failing to redirect
the continue edge on the alpha.  The answer is that the "while(again)"
condition generates the following RTL:


(insn 118 257 119 10 uninit-A.c:83 (set (reg:SI 97 [ again ])
        (subreg/s:SI (reg/v:DI 75 [ again ]) 0)) 219 {*movsi_nofix} (nil)
    (nil))

(insn 119 118 120 10 uninit-A.c:83 (set (reg:DI 98 [ again ])
        (sign_extend:DI (reg:SI 97 [ again ]))) 0 {*extendsidi2_nofix} (nil)
    (nil))

(jump_insn 120 119 123 10 uninit-A.c:83 (set (pc)
        (if_then_else (ne (reg:DI 98 [ again ])
                (const_int 0 [0x0]))
            (label_ref 20)
            (pc))) 170 {*bcc_normal} (nil)
    (nil))


Which is to complex a basic block for jump bypassing to handle.  Jump
bypassing requires the conditional jump at the start of the basic block.

So I then investigated where the SUBREG and SIGN_EXTEND came from.
It turns out they are generated during RTL expansion by the following
code in expr.c, line 6837 onwards in expand_expr.


>      /* If the mode of DECL_RTL does not match that of the decl, it
>         must be a promoted value.  We return a SUBREG of the wanted mode,
>         but mark it so that we know that it was already extended.  */
>
>      if (GET_CODE (DECL_RTL (exp)) == REG
>          && GET_MODE (DECL_RTL (exp)) != DECL_MODE (exp))
>        {
>          /* Get the signedness used for this variable.  Ensure we get the
>             same mode we got when the variable was declared.  */
>          if (GET_MODE (DECL_RTL (exp))
>              != promote_mode (type, DECL_MODE (exp), &unsignedp,
>                               (TREE_CODE (exp) == RESULT_DECL ? 1 : 0)))
>            abort ();
>
>          temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
>          SUBREG_PROMOTED_VAR_P (temp) = 1;
>          SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
>          return temp;
>        }


Promoted variables.  Cool!.  It turns out that the alpha being a
64-bit processor keeps SImode variables in DImode registers.  But
most importantly, when generating the SUBREG it records the fact
that source register already contains the sign or zero extended
DImode representation of the value for the RTL optimizers to use.

A quick grep of the source code reveals that unfortunately the RTL
optimizers don't currently make use of this helpful information.

My first strategy was to improve simplify_rtx so that sign or
zero extending a promoted variable subreg back to its stored
representation just used the holding register.  This resulted in
the hunks to simplify_unary_operation below.  The code does fire
during combine, optimizing the subreg away, but for uninit-A.c
this is too late (bypass to redirect edges and life which generates
the warning both get run much earlier).

The next strategy was to avoid the extension of promoted variable
subregs during RTL expansion.  The reason we have this sequence is
that the variable is held in a word_mode register where we extract
the SImode value and then extend it back to word_mode to perform
the comparison against zero.  Clearly, we can directly compare the
DImode register against zero, inplace of the SImode comparison.
Much like dojump optimizes for NOP_EXPRs, this transformation is
safe independent of whether the extension is signed or not.

One approach I consider was just adding a VAR_DECL case to do_jump.
I ruled this out as expand_expr on a VAR_DECL does a huge amount
of processing, laying out incomplete types, setting used flags etc...
that I didn't want to duplicate.  Instead if turned out that there
was a perfect place to test for promoted variable SUBREGs in the
default patch, which produce the change to dojump.c below which
indeed fixes uninit-A.c on alphaev67-dec-osf5.1.

The following patch has been tested on both i686-pc-linux-gnu and
alphaev67-dec-osf5.1 with a complete "make bootstrap", all languages
except treelang (on both) and Ada (on Tru64), and regression tested
with a top-level "make -k check" with no new failures.

Ok for mainline?


2003-08-09  Roger Sayle  <roger@eyesopen.com>

	* dojump.c (do_jump): If the expression being compared against
	zero, is the subreg of a promoted variable, perform the comparison
	in the promoted mode.
	* simplify-rtx.c (simplify_unary_operation): Optimize sign and
	zero-extensions of subregs of promoted variables where the
	extension is identical to that used to promote the variable.


Index: dojump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dojump.c,v
retrieving revision 1.5
diff -c -3 -p -r1.5 dojump.c
*** dojump.c	22 Jul 2003 23:15:26 -0000	1.5
--- dojump.c	9 Aug 2003 03:25:11 -0000
*************** do_jump (tree exp, rtx if_false_label, r
*** 585,591 ****
  	{
  	  /* The RTL optimizers prefer comparisons against pseudos.  */
  	  if (GET_CODE (temp) == SUBREG)
! 	    temp = copy_to_reg (temp);
  	  do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
  				   NE, TREE_UNSIGNED (TREE_TYPE (exp)),
  				   GET_MODE (temp), NULL_RTX,
--- 585,598 ----
  	{
  	  /* The RTL optimizers prefer comparisons against pseudos.  */
  	  if (GET_CODE (temp) == SUBREG)
! 	    {
! 	      /* Compare promoted variables in their promoted mode.  */
! 	      if (SUBREG_PROMOTED_VAR_P (temp)
! 		  && GET_CODE (XEXP (temp, 0)) == REG)
! 		temp = XEXP (temp, 0);
! 	      else
! 		temp = copy_to_reg (temp);
! 	    }
  	  do_compare_rtx_and_jump (temp, CONST0_RTX (GET_MODE (temp)),
  				   NE, TREE_UNSIGNED (TREE_TYPE (exp)),
  				   GET_MODE (temp), NULL_RTX,
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.151
diff -c -3 -p -r1.151 simplify-rtx.c
*** simplify-rtx.c	19 Jul 2003 14:47:13 -0000	1.151
--- simplify-rtx.c	9 Aug 2003 03:25:14 -0000
*************** simplify_unary_operation (enum rtx_code
*** 821,826 ****
--- 821,835 ----
  	      && GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
  	    return XEXP (op, 0);

+ 	  /* Check for a sign extension of a subreg of a promoted
+ 	     variable, where the promotion is sign-extended, and the
+ 	     target mode is the same as the variable's promotion.  */
+ 	  if (GET_CODE (op) == SUBREG
+ 	      && SUBREG_PROMOTED_VAR_P (op)
+ 	      && ! SUBREG_PROMOTED_UNSIGNED_P (op)
+ 	      && GET_MODE (XEXP (op, 0)) == mode)
+ 	    return XEXP (op, 0);
+
  #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
  	  if (! POINTERS_EXTEND_UNSIGNED
  	      && mode == Pmode && GET_MODE (op) == ptr_mode
*************** simplify_unary_operation (enum rtx_code
*** 833,840 ****
  #endif
  	  break;

- #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
  	case ZERO_EXTEND:
  	  if (POINTERS_EXTEND_UNSIGNED > 0
  	      && mode == Pmode && GET_MODE (op) == ptr_mode
  	      && (CONSTANT_P (op)
--- 842,858 ----
  #endif
  	  break;

  	case ZERO_EXTEND:
+ 	  /* Check for a zero extension of a subreg of a promoted
+ 	     variable, where the promotion is zero-extended, and the
+ 	     target mode is the same as the variable's promotion.  */
+ 	  if (GET_CODE (op) == SUBREG
+ 	      && SUBREG_PROMOTED_VAR_P (op)
+ 	      && SUBREG_PROMOTED_UNSIGNED_P (op)
+ 	      && GET_MODE (XEXP (op, 0)) == mode)
+ 	    return XEXP (op, 0);
+
+ #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
  	  if (POINTERS_EXTEND_UNSIGNED > 0
  	      && mode == Pmode && GET_MODE (op) == ptr_mode
  	      && (CONSTANT_P (op)
*************** simplify_unary_operation (enum rtx_code
*** 843,850 ****
  		      && REG_POINTER (SUBREG_REG (op))
  		      && GET_MODE (SUBREG_REG (op)) == Pmode)))
  	    return convert_memory_address (Pmode, op);
- 	  break;
  #endif

  	default:
  	  break;
--- 861,868 ----
  		      && REG_POINTER (SUBREG_REG (op))
  		      && GET_MODE (SUBREG_REG (op)) == Pmode)))
  	    return convert_memory_address (Pmode, op);
  #endif
+ 	  break;

  	default:
  	  break;

Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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