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]

[Committed] Lower C99's unordered comparisons in fold_builtin


The following patch is the last of the middle-end patches to move the
lowering of builtin function calls to tree nodes, from the front-ends
to the middle-end.  This patch lowers the C99 unordered comparison
functions, including "isgreater" and "isunordered".  The implementation
is based on the one in c-common.c's "expand_unordered_cmp", which I plan
to delete in my next patch.

Whilst developing this patch, I noticed that there was a potential bug
in the original C-family expand_unordered_cmp:  When lowering the
function isunordered(x,y) on a target whose "double" can't represent
NaN, we correctly constant folded the comparison to zero,  but we
forgot to expand any side-effects of the evaluations of "x" and "y".

I also noticed that for similar code in builtins.c, we currently generate
poor trees when omitting two operands: When building COMPOUND_EXPRs we
were neither testing the first operand for side effects, nor calling
"fold" on the resulting tree.  This often results in larger trees that can
interfere with further optimization.  To solve both problems, I've created
a new "omit_two_operands" function in fold-const.c, that's based upon the
existing "omit_one_operand", which does the right thing.


The following patch has been tested on i686-pc-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 CVS.


2004-06-12  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (omit_two_operands): New function.
	* tree.h (omit_two_operands): Prototype here.
	* builtins.c (fold_builtin_unordered_cmp): New function to lower
	C99 unordered comparison builtins to the appropriate tree nodes.
	(fold_builtin_1): Use fold_builtin_unordered_cmp to lower
	BUILT_IN_ISGREATER, BUILT_IN_ISGREATEREQUAL, BUILT_IN_ISLESS,
	BUILT_IN_ISLESSEQUAL and BUILT_IN_ISLESSGREATER.  Manually lower
	BUILT_IN_ISUNORDERED comparisons to an UNORDERED_EXPR tree node.
	(simplify_builtin_memcmp, simplify_builtin_strncmp,
	simplify_builtin_strncat, simplify_builtin_strspn): Use the new
	omit_two_operands function to build the required COMPOUND_EXPRs.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.393
diff -c -3 -p -r1.393 fold-const.c
*** fold-const.c	11 Jun 2004 03:22:29 -0000	1.393
--- fold-const.c	12 Jun 2004 19:27:20 -0000
*************** pedantic_omit_one_operand (tree type, tr
*** 2828,2833 ****
--- 2828,2856 ----

    return pedantic_non_lvalue (t);
  }
+
+ /* Return a tree for the case when the result of an expression is RESULT
+    converted to TYPE and OMITTED1 and OMITTED2 were previously operands
+    of the expression but are now not needed.
+
+    If OMITTED1 or OMITTED2 has side effects, they must be evaluated.
+    If both OMITTED1 and OMITTED2 have side effects, OMITTED1 is
+    evaluated before OMITTED2.  Otherwise, if neither has side effects,
+    just do the conversion of RESULT to TYPE.  */
+
+ tree
+ omit_two_operands (tree type, tree result, tree omitted1, tree omitted2)
+ {
+   tree t = fold_convert (type, result);
+
+   if (TREE_SIDE_EFFECTS (omitted2))
+     t = build2 (COMPOUND_EXPR, type, omitted2, t);
+   if (TREE_SIDE_EFFECTS (omitted1))
+     t = build2 (COMPOUND_EXPR, type, omitted1, t);
+
+   return TREE_CODE (t) != COMPOUND_EXPR ? non_lvalue (t) : t;
+ }
+

  /* Return a simplified tree node for the truth-negation of ARG.  This
     never alters ARG itself.  We assume that ARG is an operation that
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.510
diff -c -3 -p -r1.510 tree.h
*** tree.h	10 Jun 2004 13:29:32 -0000	1.510
--- tree.h	12 Jun 2004 19:27:21 -0000
*************** enum operand_equal_flag
*** 3501,3506 ****
--- 3501,3507 ----
  extern int operand_equal_p (tree, tree, unsigned int);

  extern tree omit_one_operand (tree, tree, tree);
+ extern tree omit_two_operands (tree, tree, tree, tree);
  extern tree invert_truthvalue (tree);
  extern tree nondestructive_fold_unary_to_constant (enum tree_code, tree, tree);
  extern tree nondestructive_fold_binary_to_constant (enum tree_code, tree, tree, tree);
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.336
diff -c -3 -p -r1.336 builtins.c
*** builtins.c	10 Jun 2004 19:46:03 -0000	1.336
--- builtins.c	12 Jun 2004 19:27:23 -0000
*************** static tree fold_builtin_toascii (tree);
*** 168,173 ****
--- 168,175 ----
  static tree fold_builtin_isdigit (tree);
  static tree fold_builtin_fabs (tree, tree);
  static tree fold_builtin_abs (tree, tree);
+ static tree fold_builtin_unordered_cmp (tree, tree, enum tree_code,
+ 					enum tree_code);

  static tree simplify_builtin_memcmp (tree);
  static tree simplify_builtin_strcmp (tree);
*************** fold_builtin_abs (tree arglist, tree typ
*** 7608,7613 ****
--- 7610,7642 ----
    return fold (build1 (ABS_EXPR, type, arg));
  }

+ /* Fold a call to an unordered comparison function such as
+    __builtin_isgreater().  ARGLIST is the funtion's argument list
+    and TYPE is the functions return type.  UNORDERED_CODE and
+    ORDERED_CODE are comparison codes that give the opposite of
+    the desired result.  UNORDERED_CODE is used for modes that can
+    hold NaNs and ORDERED_CODE is used for the rest.  */
+
+ static tree
+ fold_builtin_unordered_cmp (tree arglist, tree type,
+ 			    enum tree_code unordered_code,
+ 			    enum tree_code ordered_code)
+ {
+   enum tree_code code;
+   tree arg0, arg1;
+
+   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+     return 0;
+
+   arg0 = TREE_VALUE (arglist);
+   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+   code = MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))) ? unordered_code
+ 						      : ordered_code;
+   return fold (build1 (TRUTH_NOT_EXPR, type,
+ 		       fold (build2 (code, type, arg0, arg1))));
+ }
+
  /* Used by constant folding to eliminate some builtin calls early.  EXP is
     the CALL_EXPR of a call to a builtin function.  */

*************** fold_builtin_1 (tree exp)
*** 8160,8165 ****
--- 8189,8216 ----
      case BUILT_IN_COPYSIGNL:
        return fold_builtin_copysign (arglist, type);

+     case BUILT_IN_ISGREATER:
+       return fold_builtin_unordered_cmp (arglist, type, UNLE_EXPR, LE_EXPR);
+     case BUILT_IN_ISGREATEREQUAL:
+       return fold_builtin_unordered_cmp (arglist, type, UNLT_EXPR, LT_EXPR);
+     case BUILT_IN_ISLESS:
+       return fold_builtin_unordered_cmp (arglist, type, UNGE_EXPR, GE_EXPR);
+     case BUILT_IN_ISLESSEQUAL:
+       return fold_builtin_unordered_cmp (arglist, type, UNGT_EXPR, GT_EXPR);
+     case BUILT_IN_ISLESSGREATER:
+       return fold_builtin_unordered_cmp (arglist, type, UNEQ_EXPR, EQ_EXPR);
+
+     case BUILT_IN_ISUNORDERED:
+       if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+ 	{
+ 	  tree arg0 = TREE_VALUE (arglist);
+ 	  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ 	  if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ 	    return omit_two_operands (type, integer_zero_node, arg0, arg1);
+ 	  return fold (build2 (UNORDERED_EXPR, type, arg0, arg1));
+ 	}
+       break;
+
      default:
        break;
      }
*************** simplify_builtin_memcmp (tree arglist)
*** 8772,8784 ****

    /* If the len parameter is zero, return zero.  */
    if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
!     {
!       /* Evaluate and ignore arg1 and arg2 in case they have
!          side-effects.  */
!       return build2 (COMPOUND_EXPR, integer_type_node, arg1,
! 		     build2 (COMPOUND_EXPR, integer_type_node,
! 			     arg2, integer_zero_node));
!     }

    p1 = c_getstr (arg1);
    p2 = c_getstr (arg2);
--- 8823,8831 ----

    /* If the len parameter is zero, return zero.  */
    if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
!     /* Evaluate and ignore arg1 and arg2 in case they have side-effects.  */
!     return omit_two_operands (integer_type_node, integer_zero_node,
! 			      arg1, arg2);

    p1 = c_getstr (arg1);
    p2 = c_getstr (arg2);
*************** simplify_builtin_strncmp (tree arglist)
*** 8913,8925 ****

    /* If the len parameter is zero, return zero.  */
    if (integer_zerop (arg3))
!     {
!       /* Evaluate and ignore arg1 and arg2 in case they have
! 	 side-effects.  */
!       return build2 (COMPOUND_EXPR, integer_type_node, arg1,
! 		     build2 (COMPOUND_EXPR, integer_type_node,
! 			     arg2, integer_zero_node));
!     }

    /* If arg1 and arg2 are equal (and not volatile), return zero.  */
    if (operand_equal_p (arg1, arg2, 0))
--- 8960,8968 ----

    /* If the len parameter is zero, return zero.  */
    if (integer_zerop (arg3))
!     /* Evaluate and ignore arg1 and arg2 in case they have side-effects.  */
!     return omit_two_operands (integer_type_node, integer_zero_node,
! 			      arg1, arg2);

    /* If arg1 and arg2 are equal (and not volatile), return zero.  */
    if (operand_equal_p (arg1, arg2, 0))
*************** simplify_builtin_strncat (tree arglist)
*** 9030,9037 ****
        /* If the requested length is zero, or the src parameter string
            length is zero, return the dst parameter.  */
        if (integer_zerop (len) || (p && *p == '\0'))
! 	return build2 (COMPOUND_EXPR, TREE_TYPE (dst), src,
! 		       build2 (COMPOUND_EXPR, integer_type_node, len, dst));

        /* If the requested len is greater than or equal to the string
           length, call strcat.  */
--- 9073,9079 ----
        /* If the requested length is zero, or the src parameter string
            length is zero, return the dst parameter.  */
        if (integer_zerop (len) || (p && *p == '\0'))
!         return omit_two_operands (TREE_TYPE (dst), dst, src, len);

        /* If the requested len is greater than or equal to the string
           length, call strcat.  */
*************** simplify_builtin_strspn (tree arglist)
*** 9089,9101 ****

        /* If either argument is "", return 0.  */
        if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
! 	{
! 	  /* Evaluate and ignore both arguments in case either one has
! 	     side-effects.  */
! 	  return build2 (COMPOUND_EXPR, integer_type_node, s1,
! 			 build2 (COMPOUND_EXPR, integer_type_node,
! 				 s2, integer_zero_node));
! 	}
        return 0;
      }
  }
--- 9131,9140 ----

        /* If either argument is "", return 0.  */
        if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
! 	/* Evaluate and ignore both arguments in case either one has
! 	   side-effects.  */
! 	return omit_two_operands (integer_type_node, integer_zero_node,
! 				  s1, s2);
        return 0;
      }
  }


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]