[Commited] PR26961: Type safety when folding COND_EXPR

Roger Sayle roger@eyesopen.com
Mon Apr 17 02:40:00 GMT 2006


The following patch fixes PR target/26961 which is an ICE on valid
regression for 4.0, 4.1 and 4.2.  The source of the problem turns
out to be fold-const.c's fold_ternary which introduces poorly typed
trees that later confuse RTL expansion.

The oversight is that in expressions of the form "A ? B : C", the
types of B and C should both match the type of the COND_EXPR,
however there is no constraint that the type of "A" needs to have
this same type, even if B and/or C are truth_value_p.

The obvious solution below is to add the necessary calls to fold_convert
to the four affected transformations to ensure that the potentially
problematic operand is guaranteed the correct type.


The following patch has been tested on x86_64-unknown-linux-gnu with
a full "make bootstrap", all default languages, and regression tested
with a top-level "make -k check" with no new failures.

Committed to mainline as revision 113001.   I'll check this fix into
both gcc-4_0-branch and gcc-4_1-branch after a few days on mainline,
and fresh bootstraps and regression tests as appropriate.



2006-04-16  Roger Sayle  <roger@eyesopen.com>

	PR target/26961
	* fold-const.c (fold_ternary): When converting "A ? B : C" into either
	"A op B" or "A op C", we may need to convert A to the type of B and C.

	* gcc.dg/fold-cond-1.c: New test case.
	* gcc.dg/pr26961-1.c: Likewise.


Index: fold-const.c
===================================================================
*** fold-const.c	(revision 112982)
--- fold-const.c	(working copy)
*************** fold_ternary (enum tree_code code, tree
*** 11073,11079 ****
        if (integer_zerop (op2)
  	  && truth_value_p (TREE_CODE (arg0))
  	  && truth_value_p (TREE_CODE (arg1)))
! 	return fold_build2 (TRUTH_ANDIF_EXPR, type, arg0, arg1);

        /* Convert A ? B : 1 into !A || B if A and B are truth values.  */
        if (integer_onep (op2)
--- 11073,11081 ----
        if (integer_zerop (op2)
  	  && truth_value_p (TREE_CODE (arg0))
  	  && truth_value_p (TREE_CODE (arg1)))
! 	return fold_build2 (TRUTH_ANDIF_EXPR, type,
! 			    fold_convert (type, arg0),
! 			    arg1);

        /* Convert A ? B : 1 into !A || B if A and B are truth values.  */
        if (integer_onep (op2)
*************** fold_ternary (enum tree_code code, tree
*** 11083,11089 ****
  	  /* Only perform transformation if ARG0 is easily inverted.  */
  	  tem = invert_truthvalue (arg0);
  	  if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
! 	    return fold_build2 (TRUTH_ORIF_EXPR, type, tem, arg1);
  	}

        /* Convert A ? 0 : B into !A && B if A and B are truth values.  */
--- 11085,11093 ----
  	  /* Only perform transformation if ARG0 is easily inverted.  */
  	  tem = invert_truthvalue (arg0);
  	  if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
! 	    return fold_build2 (TRUTH_ORIF_EXPR, type,
! 				fold_convert (type, tem),
! 				arg1);
  	}

        /* Convert A ? 0 : B into !A && B if A and B are truth values.  */
*************** fold_ternary (enum tree_code code, tree
*** 11094,11107 ****
  	  /* Only perform transformation if ARG0 is easily inverted.  */
  	  tem = invert_truthvalue (arg0);
  	  if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
! 	    return fold_build2 (TRUTH_ANDIF_EXPR, type, tem, op2);
  	}

        /* Convert A ? 1 : B into A || B if A and B are truth values.  */
        if (integer_onep (arg1)
  	  && truth_value_p (TREE_CODE (arg0))
  	  && truth_value_p (TREE_CODE (op2)))
! 	return fold_build2 (TRUTH_ORIF_EXPR, type, arg0, op2);

        return NULL_TREE;

--- 11098,11115 ----
  	  /* Only perform transformation if ARG0 is easily inverted.  */
  	  tem = invert_truthvalue (arg0);
  	  if (TREE_CODE (tem) != TRUTH_NOT_EXPR)
! 	    return fold_build2 (TRUTH_ANDIF_EXPR, type,
! 				fold_convert (type, tem),
! 				op2);
  	}

        /* Convert A ? 1 : B into A || B if A and B are truth values.  */
        if (integer_onep (arg1)
  	  && truth_value_p (TREE_CODE (arg0))
  	  && truth_value_p (TREE_CODE (op2)))
! 	return fold_build2 (TRUTH_ORIF_EXPR, type,
! 			    fold_convert (type, arg0),
! 			    op2);

        return NULL_TREE;



/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-original" } */

_Bool test1(int a, int b)
{
  return a ? b : 0;
}

_Bool test2(int c, int d)
{
  return c ? d : 1;
}

_Bool test3(int e, int f)
{
  return e ? 0 : f;
}

_Bool test4(int g, int h)
{
  return g ? 1 : h;
}

/* { dg-final { scan-tree-dump-times "a != 0 \&\& b != 0" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "c == 0 \\|\\| d != 0" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "e == 0 \&\& f != 0" 1 "original" } } */
/* { dg-final { scan-tree-dump-times "\\(g \\| h\\) != 0" 1 "original" } } */
/* { dg-final { cleanup-tree-dump "original" } } */


/* { dg-do compile } */
/* { dg-options "-O2" } */

long long foo(int i, int j)
{
  return i ? (long long)(!j) : 0;
}


Roger
--



More information about the Gcc-patches mailing list