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


I'm resending the patch, where I implemented all builtins mentions in subject
in gimp-fold.c.

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

Ready to be installed?
Martin
>From 8a5f823348c132523b40c531b56a1a29dac32097 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 5 Oct 2016 13:18:35 +0200
Subject: [PATCH 1/3] 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.
---
 gcc/builtins.c        | 138 -----------------------------------------------
 gcc/fold-const-call.c |   2 +-
 gcc/fold-const-call.h |   1 +
 gcc/gimple-fold.c     | 147 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 148 insertions(+), 140 deletions(-)

diff --git a/gcc/builtins.c b/gcc/builtins.c
index facecd3..b03d53c 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);
@@ -7335,136 +7333,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
@@ -8393,9 +8261,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);
 
@@ -8477,9 +8342,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..18f1182 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);
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 59c4cb8..67a598c 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.
@@ -1784,6 +1784,143 @@ gimple_fold_builtin_strncat_chk (gimple_stmt_iterator *gsi)
   return true;
 }
 
+/* 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);
+  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_STRNCASECMP:
+	  {
+	    r = strncmp (p1, p2, length);
+	    if (r == 0)
+	      known_result = true;
+	    break;;
+	  }
+	case BUILT_IN_STRCMP:
+	  {
+	    r = strcmp (p1, p2);
+	    known_result = true;
+	    break;
+	  }
+	case BUILT_IN_STRNCMP:
+	  {
+	    r = strncmp (p1, p2, length);
+	    known_result = true;
+	    break;
+	  }
+	default:
+	  break;
+	}
+
+      if (known_result)
+	{
+	  replace_call_with_value (gsi, build_cmp_result (type, r));
+	  return true;
+	}
+    }
+
+  location_t loc = gimple_location (stmt);
+  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);
+
+  /* If the second arg is "", return *(const unsigned char*)arg1.  */
+  if (p2 && *p2 == '\0' && length != 0)
+    {
+      gimple_seq stmts = NULL;
+
+      tree temp = fold_build2_loc (loc, MEM_REF, cst_uchar_node, str1,
+				   off0);
+      temp = gimple_build (&stmts, loc, NOP_EXPR, cst_uchar_node, temp);
+      gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+
+      replace_call_with_value (gsi, fold_convert_loc (loc, type, temp));
+      return true;
+    }
+
+  /* If the first arg is "", return -*(const unsigned char*)arg2.  */
+  if (p1 && *p1 == '\0' && length != 0)
+    {
+      gimple_seq stmts = NULL;
+
+      tree temp = fold_build2_loc (loc, MEM_REF, cst_uchar_node, str2,
+				   off0);
+      temp = gimple_build (&stmts, loc, NOP_EXPR, cst_uchar_node, temp);
+      temp = gimple_convert (&stmts, loc, type, temp);
+      gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+      replace_call_with_value (gsi, fold_build1_loc (loc, NEGATE_EXPR,
+						     type, temp));
+      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 = fold_build2_loc (loc, MEM_REF, cst_uchar_node, str1,
+				    off0);
+      temp1 = gimple_build (&stmts, loc, NOP_EXPR, cst_uchar_node, temp1);
+      temp1 = gimple_convert (&stmts, loc, type, temp1);
+      tree temp2 = fold_build2_loc (loc, MEM_REF, cst_uchar_node, str2,
+				    off0);
+      temp2 = gimple_build (&stmts, loc, NOP_EXPR, cst_uchar_node, temp2);
+      temp2 = gimple_convert (&stmts, loc, type, temp2);
+      tree temp = gimple_build (&stmts, loc, MINUS_EXPR, type, temp1, temp2);
+      gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+      replace_call_with_value (gsi, temp);
+      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
@@ -3005,6 +3142,14 @@ 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:
+      return gimple_fold_builtin_string_compare (gsi);
+    case BUILT_IN_STRCASECMP:
+      return gimple_fold_builtin_string_compare (gsi);
+    case BUILT_IN_STRNCMP:
+      return gimple_fold_builtin_string_compare (gsi);
+    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]