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] Fold __builtin_str{n}{case}cmp functions (version 3)


Changes from the previous version:

1) Handle BUILT_IN_STRNCMP with length == -1.
2) Direct gimple stmts creation and usage gsi_replace_with_seq_vops.
(hope using of replace_call_with_value is fine if replacing with a cst?)
3) lhs == NULL cases are handled (Or is it fine to replace with a nop in general?
Can change a semantic as it may touch a memory.)
4) CFN_BUILT_IN_STRNCMP can handle strncmp (x, y, 0).
5) Handling of CFN_BUILT_IN_STRNCASECMP is added.

Testing of the whole series has been running.

Martin
>From 925a998bacf2fffb811f1bb655674c869aa45a32 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 5 Oct 2016 13:18:35 +0200
Subject: [PATCH 3/5] Fold __builtin_str{n}{case}cmp functions

gcc/ChangeLog:

2016-10-06  Martin Liska  <mliska@suse.cz>

	* builtins.c (fold_builtin_strcmp): Remove function.
	(fold_builtin_strncmp): Likewise.
	(fold_builtin_2): Do not call fold_builtin_strcmp.
	(fold_builtin_3): Do not call fold_builtin_strncmp.
	* fold-const-call.c: Make build_cmp_result global fn.
	* fold-const-call.h: Likewise.
	* gimple-fold.c (gimple_fold_builtin_string_compare): New
	function.
	(gimple_fold_builtin): Call the function.
	* fold-const-call.c (fold_const_call): Handle
	CFN_BUILT_IN_STRCASECMP, CFN_BUILT_IN_STRNCMP and
	CFN_BUILT_IN_STRNCASECMP.
---
 gcc/builtins.c        | 138 -------------------------------------
 gcc/fold-const-call.c |  43 +++++++++---
 gcc/fold-const-call.h |   1 +
 gcc/gimple-fold.c     | 187 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 222 insertions(+), 147 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 6c68198..6696f28 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -150,8 +150,6 @@ static rtx expand_builtin_fabs (tree, rtx, rtx);
 static rtx expand_builtin_signbit (tree, rtx);
 static tree fold_builtin_memchr (location_t, tree, tree, tree, tree);
 static tree fold_builtin_memcmp (location_t, tree, tree, tree);
-static tree fold_builtin_strcmp (location_t, tree, tree);
-static tree fold_builtin_strncmp (location_t, tree, tree, tree);
 static tree fold_builtin_isascii (location_t, tree);
 static tree fold_builtin_toascii (location_t, tree);
 static tree fold_builtin_isdigit (location_t, tree);
@@ -7333,136 +7331,6 @@ fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
   return NULL_TREE;
 }
 
-/* Fold function call to builtin strcmp with arguments ARG1 and ARG2.
-   Return NULL_TREE if no simplification can be made.  */
-
-static tree
-fold_builtin_strcmp (location_t loc, tree arg1, tree arg2)
-{
-  if (!validate_arg (arg1, POINTER_TYPE)
-      || !validate_arg (arg2, POINTER_TYPE))
-    return NULL_TREE;
-
-  /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
-  if (operand_equal_p (arg1, arg2, 0))
-    return integer_zero_node;
-
-  /* If the second arg is "", return *(const unsigned char*)arg1.  */
-  const char *p2 = c_getstr (arg2);
-  if (p2 && *p2 == '\0')
-    {
-      tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node
-	= build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
-
-      return fold_convert_loc (loc, integer_type_node,
-			       build1 (INDIRECT_REF, cst_uchar_node,
-				       fold_convert_loc (loc,
-							 cst_uchar_ptr_node,
-							 arg1)));
-    }
-
-  /* If the first arg is "", return -*(const unsigned char*)arg2.  */
-  const char *p1 = c_getstr (arg1);
-  if (p1 && *p1 == '\0')
-    {
-      tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node
-	= build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
-
-      tree temp
-	= fold_convert_loc (loc, integer_type_node,
-			    build1 (INDIRECT_REF, cst_uchar_node,
-				    fold_convert_loc (loc,
-						      cst_uchar_ptr_node,
-						      arg2)));
-      return fold_build1_loc (loc, NEGATE_EXPR, integer_type_node, temp);
-    }
-
-  return NULL_TREE;
-}
-
-/* Fold function call to builtin strncmp with arguments ARG1, ARG2, and LEN.
-   Return NULL_TREE if no simplification can be made.  */
-
-static tree
-fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
-{
-  if (!validate_arg (arg1, POINTER_TYPE)
-      || !validate_arg (arg2, POINTER_TYPE)
-      || !validate_arg (len, INTEGER_TYPE))
-    return NULL_TREE;
-
-  /* If the LEN parameter is zero, return zero.  */
-  if (integer_zerop (len))
-    return omit_two_operands_loc (loc, integer_type_node, integer_zero_node,
-			      arg1, arg2);
-
-  /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
-  if (operand_equal_p (arg1, arg2, 0))
-    return omit_one_operand_loc (loc, integer_type_node, integer_zero_node, len);
-
-  /* If the second arg is "", and the length is greater than zero,
-     return *(const unsigned char*)arg1.  */
-  const char *p2 = c_getstr (arg2);
-  if (p2 && *p2 == '\0'
-      && TREE_CODE (len) == INTEGER_CST
-      && tree_int_cst_sgn (len) == 1)
-    {
-      tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node
-	= build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
-
-      return fold_convert_loc (loc, integer_type_node,
-			       build1 (INDIRECT_REF, cst_uchar_node,
-				       fold_convert_loc (loc,
-							 cst_uchar_ptr_node,
-							 arg1)));
-    }
-
-  /* If the first arg is "", and the length is greater than zero,
-     return -*(const unsigned char*)arg2.  */
-  const char *p1 = c_getstr (arg1);
-  if (p1 && *p1 == '\0'
-      && TREE_CODE (len) == INTEGER_CST
-      && tree_int_cst_sgn (len) == 1)
-    {
-      tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node
-	= build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
-
-      tree temp = fold_convert_loc (loc, integer_type_node,
-				    build1 (INDIRECT_REF, cst_uchar_node,
-					    fold_convert_loc (loc,
-							      cst_uchar_ptr_node,
-							      arg2)));
-      return fold_build1_loc (loc, NEGATE_EXPR, integer_type_node, temp);
-    }
-
-  /* If len parameter is one, return an expression corresponding to
-     (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
-  if (tree_fits_uhwi_p (len) && tree_to_uhwi (len) == 1)
-    {
-      tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node
-	= build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
-
-      tree ind1 = fold_convert_loc (loc, integer_type_node,
-				    build1 (INDIRECT_REF, cst_uchar_node,
-					    fold_convert_loc (loc,
-							      cst_uchar_ptr_node,
-							      arg1)));
-      tree ind2 = fold_convert_loc (loc, integer_type_node,
-				    build1 (INDIRECT_REF, cst_uchar_node,
-					    fold_convert_loc (loc,
-							      cst_uchar_ptr_node,
-							      arg2)));
-      return fold_build2_loc (loc, MINUS_EXPR, integer_type_node, ind1, ind2);
-    }
-
-  return NULL_TREE;
-}
-
 /* Fold a call to builtin isascii with argument ARG.  */
 
 static tree
@@ -8391,9 +8259,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
     case BUILT_IN_STRCSPN:
       return fold_builtin_strcspn (loc, arg0, arg1);
 
-    case BUILT_IN_STRCMP:
-      return fold_builtin_strcmp (loc, arg0, arg1);
-
     case BUILT_IN_STRPBRK:
       return fold_builtin_strpbrk (loc, arg0, arg1, type);
 
@@ -8475,9 +8340,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
 	return do_mpfr_remquo (arg0, arg1, arg2);
     break;
 
-    case BUILT_IN_STRNCMP:
-      return fold_builtin_strncmp (loc, arg0, arg1, arg2);
-
     case BUILT_IN_MEMCHR:
       return fold_builtin_memchr (loc, arg0, arg1, arg2, type);
 
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index 2bbc887..bbec177 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -69,7 +69,7 @@ host_size_t_cst_p (tree t, size_t *size_out)
    "equal" and > 0 means "more".  Canonicalize it to -1, 0 or 1 and
    return it in type TYPE.  */
 
-static inline tree
+tree
 build_cmp_result (tree type, int res)
 {
   return build_int_cst (type, res < 0 ? -1 : res > 0 ? 1 : 0);
@@ -1397,6 +1397,15 @@ fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1)
 	return build_cmp_result (type, strcmp (p0, p1));
       return NULL_TREE;
 
+    case CFN_BUILT_IN_STRCASECMP:
+      if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
+	{
+	  int r = strcmp (p0, p1);
+	  if (r == 0)
+	    return build_cmp_result (type, r);
+	}
+      return NULL_TREE;
+
     default:
       return fold_const_call_1 (fn, type, arg0, arg1);
     }
@@ -1464,16 +1473,34 @@ tree
 fold_const_call (combined_fn fn, tree type, tree arg0, tree arg1, tree arg2)
 {
   const char *p0, *p1;
-  size_t s2;
+  size_t s2 = 0;
   switch (fn)
     {
     case CFN_BUILT_IN_STRNCMP:
-      if ((p0 = c_getstr (arg0))
-	  && (p1 = c_getstr (arg1))
-	  && host_size_t_cst_p (arg2, &s2))
-	return build_int_cst (type, strncmp (p0, p1, s2));
-      return NULL_TREE;
-
+      {
+	bool const_size_p = host_size_t_cst_p (arg2, &s2);
+	if (const_size_p && s2 == 0
+	    && !TREE_SIDE_EFFECTS (arg0)
+	    && !TREE_SIDE_EFFECTS (arg1))
+	  return build_int_cst (type, 0);
+	else if ((p0 = c_getstr (arg0))
+	    && (p1 = c_getstr (arg1))
+	    && const_size_p)
+	  return build_int_cst (type, strncmp (p0, p1, s2));
+	return NULL_TREE;
+      }
+    case CFN_BUILT_IN_STRNCASECMP:
+      {
+	bool const_size_p = host_size_t_cst_p (arg2, &s2);
+	if (const_size_p && s2 == 0)
+	  return build_int_cst (type, 0);
+	else if ((p0 = c_getstr (arg0))
+	    && (p1 = c_getstr (arg1))
+	    && const_size_p
+	    && strncmp (p0, p1, s2) == 0)
+	  return build_int_cst (type, 0);
+	return NULL_TREE;
+      }
     case CFN_BUILT_IN_BCMP:
     case CFN_BUILT_IN_MEMCMP:
       if ((p0 = c_getstr (arg0))
diff --git a/gcc/fold-const-call.h b/gcc/fold-const-call.h
index 324ecbf..7f61f2e 100644
--- a/gcc/fold-const-call.h
+++ b/gcc/fold-const-call.h
@@ -24,5 +24,6 @@ tree fold_const_call (combined_fn, tree, tree);
 tree fold_const_call (combined_fn, tree, tree, tree);
 tree fold_const_call (combined_fn, tree, tree, tree, tree);
 tree fold_fma (location_t, tree, tree, tree, tree);
+tree build_cmp_result (tree type, int res);
 
 #endif
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 348f331..f892d7e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -55,7 +55,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "omp-low.h"
 #include "ipa-chkp.h"
 #include "tree-cfg.h"
-
+#include "fold-const-call.h"
 
 /* Return true if T is a constant and the value cast to a target char
    can be represented by a host char.
@@ -1783,6 +1783,186 @@ gimple_fold_builtin_strncat_chk (gimple_stmt_iterator *gsi)
   return true;
 }
 
+static tree
+gimple_load_first_char (location_t loc, tree str, gimple_seq *stmts)
+{
+  tree var;
+
+  tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+  tree cst_uchar_ptr_node
+    = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+  tree off0 = build_int_cst (cst_uchar_ptr_node, 0);
+
+  tree temp = fold_build2_loc (loc, MEM_REF, cst_uchar_node, str, off0);
+  gassign *stmt = gimple_build_assign (NULL_TREE, temp);
+  var = create_tmp (cst_uchar_node, stmt);
+
+  gimple_assign_set_lhs (stmt, var);
+  gimple_seq_add_stmt_without_update (stmts, stmt);
+
+  return var;
+}
+
+/* Fold a call to the str{n}{case}cmp builtin pointed by GSI iterator.
+   FCODE is the name of the builtin.  */
+
+static bool
+gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree callee = gimple_call_fndecl (stmt);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (callee);
+
+  tree type = integer_type_node;
+  tree str1 = gimple_call_arg (stmt, 0);
+  tree str2 = gimple_call_arg (stmt, 1);
+  tree lhs = gimple_call_lhs (stmt);
+  HOST_WIDE_INT length = -1;
+
+  /* Handle strncmp and strncasecmp functions.  */
+  if (gimple_call_num_args (stmt) == 3)
+    {
+      tree len = gimple_call_arg (stmt, 2);
+      if (tree_fits_uhwi_p (len))
+	length = tree_to_uhwi (len);
+    }
+
+  const char *p1 = c_getstr (str1);
+  const char *p2 = c_getstr (str2);
+
+  /* If the LEN parameter is zero, return zero.  */
+  if (length == 0)
+    {
+      replace_call_with_value (gsi, integer_zero_node);
+      return true;
+    }
+
+  /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
+  if (operand_equal_p (str1, str2, 0))
+    {
+      replace_call_with_value (gsi, integer_zero_node);
+      return true;
+    }
+
+  /* For known strings, return an immediate value.  */
+  if (p1 && p2)
+    {
+      int r = 0;
+      bool known_result = false;
+
+      switch (fcode)
+	{
+	case BUILT_IN_STRCMP:
+	  {
+	    r = strcmp (p1, p2);
+	    known_result = true;
+	    break;
+	  }
+	case BUILT_IN_STRNCMP:
+	  {
+	    if (length == -1)
+	      break;
+	    r = strncmp (p1, p2, length);
+	    known_result = true;
+	    break;
+	  }
+	/* Only handleable situation is where the string are equal (result 0),
+	   which is already handled by operand_equal_p case.  */
+	case BUILT_IN_STRCASECMP:
+	  break;
+	case BUILT_IN_STRNCASECMP:
+	  {
+	    if (length == -1)
+	      break;
+	    r = strncmp (p1, p2, length);
+	    if (r == 0)
+	      known_result = true;
+	    break;;
+	  }
+	default:
+	  gcc_unreachable ();
+	}
+
+      if (known_result)
+	{
+	  replace_call_with_value (gsi, build_cmp_result (type, r));
+	  return true;
+	}
+    }
+
+  bool nonzero_length = length >= 1
+    || fcode == BUILT_IN_STRCMP
+    || fcode == BUILT_IN_STRCASECMP;
+
+  location_t loc = gimple_location (stmt);
+
+  /* If the second arg is "", return *(const unsigned char*)arg1.  */
+  if (p2 && *p2 == '\0' && nonzero_length)
+    {
+      gimple_seq stmts = NULL;
+      tree var = gimple_load_first_char (loc, str1, &stmts);
+      if (lhs)
+	stmt = gimple_build_assign (lhs, NOP_EXPR, var);
+      else
+	stmt = gimple_build_nop ();
+
+      gimple_seq_add_stmt_without_update (&stmts, stmt);
+
+      gsi_replace_with_seq_vops (gsi, stmts);
+      return true;
+    }
+
+  /* If the first arg is "", return -*(const unsigned char*)arg2.  */
+  if (p1 && *p1 == '\0' && nonzero_length)
+    {
+      gimple_seq stmts = NULL;
+      tree var = gimple_load_first_char (loc, str2, &stmts);
+
+      tree c = create_tmp (integer_type_node);
+      stmt = gimple_build_assign (c, NOP_EXPR, var);
+      gimple_seq_add_stmt_without_update (&stmts, stmt);
+
+      if (lhs)
+	stmt = gimple_build_assign (lhs, NEGATE_EXPR, c);
+      else
+	stmt = gimple_build_nop ();
+      gimple_seq_add_stmt_without_update (&stmts, stmt);
+
+      gsi_replace_with_seq_vops (gsi, stmts);
+      return true;
+    }
+
+  /* If len parameter is one, return an expression corresponding to
+     (*(const unsigned char*)arg2 - *(const unsigned char*)arg1).  */
+  if (fcode == BUILT_IN_STRNCMP && length == 1)
+    {
+      gimple_seq stmts = NULL;
+      tree temp1 = gimple_load_first_char (loc, str1, &stmts);
+      tree temp2 = gimple_load_first_char (loc, str2, &stmts);
+
+      tree c1 = create_tmp (integer_type_node);
+      gassign *convert1 = gimple_build_assign (c1, NOP_EXPR, temp1);
+      gimple_seq_add_stmt_without_update (&stmts, convert1);
+
+      tree c2 = create_tmp (integer_type_node);
+      gassign *convert2 = gimple_build_assign (c2, NOP_EXPR, temp2);
+      gimple_seq_add_stmt_without_update (&stmts, convert2);
+
+      if (lhs)
+	stmt = gimple_build_assign (lhs, MINUS_EXPR, c1, c2);
+      else
+	stmt = gimple_build_nop ();
+
+      gimple_seq_add_stmt_without_update (&stmts, stmt);
+
+      gsi_replace_with_seq_vops (gsi, stmts);
+      return true;
+    }
+
+  return false;
+}
+
+
 /* Fold a call to the fputs builtin.  ARG0 and ARG1 are the arguments
    to the call.  IGNORE is true if the value returned
    by the builtin will be ignored.  UNLOCKED is true is true if this
@@ -3004,6 +3184,11 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
     case BUILT_IN_RINDEX:
     case BUILT_IN_STRRCHR:
       return gimple_fold_builtin_strchr (gsi, true);
+    case BUILT_IN_STRCMP:
+    case BUILT_IN_STRCASECMP:
+    case BUILT_IN_STRNCMP:
+    case BUILT_IN_STRNCASECMP:
+      return gimple_fold_builtin_string_compare (gsi);
     case BUILT_IN_FPUTS:
       return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0),
 					gimple_call_arg (stmt, 1), false);
-- 
2.9.2


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