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] PR fortran/7388: VOID_TYPE_P in COND_EXPRs


This patch fixes the remaining g77 testsuite failures on
GNU/Linux/x86.

The COND_EXPR tree node in GCC supports an extension whereby the
the true or false child can have void type, to indicate that it
doesn't return, or throws an exception.  This semantics is useful
for array bounds checking code, where "i" may be replaced with the
equivalent "((i>=0 && i<10)? i : abort())".  The causes of PR 7388
were that the g77 front-end wasn't using this extension and that
constant folding in GCC's middle-end wasn't honoring it.  The code
in expand_expr handling COND_EXPR specifically checks for void types
and generates RTL appropriately.  Its because this code wasn't
firing, that 7388.f produced RTL with barriers that were immediately
followed by instructions, that then lead to the miscompilation.

The easiest part, of the patch below, to comprehend is the change to
ffecom_subscript_check_ that casts the "die" function call to void
before using it to build a COND_EXPR.  I've contacted Toon about
getting the return type fixed in libf2c, but casting the CALL_EXPR
to void produces the appropriate tree.

The remaining changes are to ensure that constant folding transformations
on COND_EXPR preserve the noreturn properties of children.  No longer
is "(int)(c ? x : abort())" converted into "c ? (int)x : (int)abort()"
[which destroys the void=noreturn semantics], but this now becomes
"c ? (int)x : abort()".

The most complicated hunk is in "fold_binary_op_with_conditional_arg".
Although this had code to check for the void type semantics, it failed
to always preserve the void type of a noreturn child.  The fixes below
ensure that if a child tree was noreturn before it remain no return
afterwards.

There are two cases.  "(c ? x : abort()) + p" is now constant folded
to "c ? x+p : abort()", i.e. when cond_first_p, the void child is left
unmodified.  The abort() is assumed to occur before p is evaluated.
In the second case, !cond_first_p, "q + (c ? x : abort())" is transformed
into "c ? q+x : (void)(q, abort())".  Here a compound expression is
used, q is allowed to side-effect, and the abort() occurs afterwards.

This enabled/required one further change, in the first case above, when
lhs != 0 or rhs !=0, "p" is only evaluated once so there's no need to
test whether it needs to be protected by a SAVE_EXPR.

I've checked all other constant folding optimizations that mention
COND_EXPR, and they all look fine. Most importantly these changes
fix g77.dg/execute/7388.f.


This patch has been tested with a complete "make bootstrap" and a
"make -k check", all languages except Ada and treelang, on
i686-pc-linux-gnu with no new regressions, and no more fortran
failures.


Ok for mainline?



2002-10-14  Roger Sayle  <roger@eyesopen.com>

	PR target/7388
	* fold-const.c (fold_binary_op_with_conditional_arg):  Improve
	handling of cases where one or both branches of the conditional
	have void type, i.e. throw an exception or don't return.
	(fold): Only apply (and undo) type conversion to the non-void
	branches of a COND_EXPR.

	* f/com.c (ffecom_subscript_check_): Cast the failure branch
	of the bounds check COND_EXPR to void, to indicate noreturn.
	(ffe_truthvalue_conversion): Only apply truth value conversion
	to the non-void branches of a COND_EXPR.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.223
diff -c -3 -p -r1.223 fold-const.c
*** fold-const.c	11 Oct 2002 01:28:24 -0000	1.223
--- fold-const.c	14 Oct 2002 04:13:49 -0000
*************** fold_binary_op_with_conditional_arg (cod
*** 4455,4469 ****
  	 we simply build `a, throw 3'.  */
        if (VOID_TYPE_P (TREE_TYPE (true_value)))
  	{
! 	  lhs_code = COMPOUND_EXPR;
! 	  if (!cond_first_p)
! 	    lhs_type = void_type_node;
  	}
        if (VOID_TYPE_P (TREE_TYPE (false_value)))
  	{
! 	  rhs_code = COMPOUND_EXPR;
! 	  if (!cond_first_p)
! 	    rhs_type = void_type_node;
  	}
      }
    else
--- 4455,4477 ----
  	 we simply build `a, throw 3'.  */
        if (VOID_TYPE_P (TREE_TYPE (true_value)))
  	{
! 	  if (! cond_first_p)
! 	    {
! 	      lhs_code = COMPOUND_EXPR;
! 	      lhs_type = void_type_node;
! 	    }
! 	  else
! 	    lhs = true_value;
  	}
        if (VOID_TYPE_P (TREE_TYPE (false_value)))
  	{
! 	  if (! cond_first_p)
! 	    {
! 	      rhs_code = COMPOUND_EXPR;
! 	      rhs_type = void_type_node;
! 	    }
! 	  else
! 	    rhs = false_value;
  	}
      }
    else
*************** fold_binary_op_with_conditional_arg (cod
*** 4488,4494 ****
       if an arm is a COND_EXPR since we get exponential behavior
       in that case.  */

!   if (TREE_CODE (arg) != SAVE_EXPR && ! TREE_CONSTANT (arg)
        && (*lang_hooks.decls.global_bindings_p) () == 0
        && ((TREE_CODE (arg) != VAR_DECL
  	   && TREE_CODE (arg) != PARM_DECL)
--- 4496,4503 ----
       if an arm is a COND_EXPR since we get exponential behavior
       in that case.  */

!   if (lhs == 0 && rhs == 0
!       && TREE_CODE (arg) != SAVE_EXPR && ! TREE_CONSTANT (arg)
        && (*lang_hooks.decls.global_bindings_p) () == 0
        && ((TREE_CODE (arg) != VAR_DECL
  	   && TREE_CODE (arg) != PARM_DECL)
*************** fold (expr)
*** 4720,4728 ****
  		      fold (build1 (code, type, TREE_OPERAND (arg0, 1))));
        else if (TREE_CODE (arg0) == COND_EXPR)
  	{
  	  t = fold (build (COND_EXPR, type, TREE_OPERAND (arg0, 0),
! 			   fold (build1 (code, type, TREE_OPERAND (arg0, 1))),
! 			   fold (build1 (code, type, TREE_OPERAND (arg0, 2)))));

  	  /* If this was a conversion, and all we did was to move into
  	     inside the COND_EXPR, bring it back out.  But leave it if
--- 4729,4742 ----
  		      fold (build1 (code, type, TREE_OPERAND (arg0, 1))));
        else if (TREE_CODE (arg0) == COND_EXPR)
  	{
+ 	  tree arg01 = TREE_OPERAND (arg0, 1);
+ 	  tree arg02 = TREE_OPERAND (arg0, 2);
+ 	  if (! VOID_TYPE_P (TREE_TYPE (arg01)))
+ 	    arg01 = fold (build1 (code, type, arg01));
+ 	  if (! VOID_TYPE_P (TREE_TYPE (arg02)))
+ 	    arg02 = fold (build1 (code, type, arg02));
  	  t = fold (build (COND_EXPR, type, TREE_OPERAND (arg0, 0),
! 			   arg01, arg02));

  	  /* If this was a conversion, and all we did was to move into
  	     inside the COND_EXPR, bring it back out.  But leave it if
*************** fold (expr)
*** 4738,4743 ****
--- 4752,4759 ----
  	      && TREE_CODE (t) == COND_EXPR
  	      && TREE_CODE (TREE_OPERAND (t, 1)) == code
  	      && TREE_CODE (TREE_OPERAND (t, 2)) == code
+ 	      && ! VOID_TYPE_P (TREE_OPERAND (t, 1))
+ 	      && ! VOID_TYPE_P (TREE_OPERAND (t, 2))
  	      && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 1), 0))
  		  == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 2), 0)))
  	      && ! (INTEGRAL_TYPE_P (TREE_TYPE (t))
Index: f/com.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/f/com.c,v
retrieving revision 1.181
diff -c -3 -p -r1.181 com.c
*** f/com.c	24 Sep 2002 03:44:33 -0000	1.181
--- f/com.c	14 Oct 2002 04:14:06 -0000
*************** ffecom_subscript_check_ (tree array, tre
*** 806,811 ****
--- 806,812 ----
    die = ffecom_call_gfrt (FFECOM_gfrtRANGE,
  			  args, NULL_TREE);
    TREE_SIDE_EFFECTS (die) = 1;
+   die = convert (void_type_node, die);

    element = ffecom_3 (COND_EXPR,
  		      TREE_TYPE (element),
*************** ffe_truthvalue_conversion (expr)
*** 14772,14781 ****
  	return ffe_truthvalue_conversion (TREE_OPERAND (expr, 0));

      case COND_EXPR:
!       /* Distribute the conversion into the arms of a COND_EXPR.  */
!       return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
! 			  ffe_truthvalue_conversion (TREE_OPERAND (expr, 1)),
! 			  ffe_truthvalue_conversion (TREE_OPERAND (expr, 2))));

      case CONVERT_EXPR:
        /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
--- 14773,14789 ----
  	return ffe_truthvalue_conversion (TREE_OPERAND (expr, 0));

      case COND_EXPR:
!       {
! 	/* Distribute the conversion into the arms of a COND_EXPR.  */
! 	tree arg1 = TREE_OPERAND (expr, 1);
! 	tree arg2 = TREE_OPERAND (expr, 2);
! 	if (! VOID_TYPE_P (TREE_TYPE (arg1)))
! 	  arg1 = ffe_truthvalue_conversion (arg1);
! 	if (! VOID_TYPE_P (TREE_TYPE (arg2)))
! 	  arg2 = ffe_truthvalue_conversion (arg2);
! 	return fold (build (COND_EXPR, integer_type_node,
! 			    TREE_OPERAND (expr, 0), arg1, arg2));
!       }

      case CONVERT_EXPR:
        /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,

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]