diff mbox

fold strlen (s) eq/ne 0 to *s eq/ne 0 on GIMPLE

Message ID CAAgBjM=VAMVeqB=Xey6_Y9Nohcp3nvLWdSNwd0p05yN=L2hiPw@mail.gmail.com
State New
Headers show

Commit Message

Prathamesh Kulkarni Aug. 1, 2016, 7:15 a.m. UTC
Hi Richard,
The attached patch tries to fold strlen (s) eq/ne 0 to *s eq/ne 0 on GIMPLE.
I am not sure where was the ideal place to put this transform in and ended up
adding it to strlen_optimize_stmt().
Does that look OK ?

I needed to add TODO_update_ssa to strlen pass, otherwise we hit the
following assert in execute_todo():
if (flag_checking
      && cfun
      && need_ssa_update_p (cfun))
    gcc_assert (flags & TODO_update_ssa_any);

Bootstrap+test in progress on x86_64-unknown-linux-gnu.

Thanks,
Prathamesh
2016-08-01  Prathamesh Kulkarni  <prathamesh.kulkarni@linaro.org>

	* tree-ssa-strlen.c (strlen_optimize_stmt): Fold strlen (s) eq/ne 0 to
	*s eq/ne 0.
	Change todo_flags_finish for pass_data_strlen from 0 to TODO_update_ssa.

testsuite/
	* gcc.dg/strlenopt-30.c: New test-case.
diff mbox

Patch

diff --git a/gcc/testsuite/gcc.dg/strlenopt-30.c b/gcc/testsuite/gcc.dg/strlenopt-30.c
new file mode 100644
index 0000000..da9732f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-30.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-strlen" } */
+
+__attribute__((noinline, no_icf))
+_Bool f1(const char *s)
+{
+  unsigned long len = __builtin_strlen (s);
+  _Bool ret = (len == 0);
+  return ret;
+}
+
+/* Check CONVERT_EXPR's get properly handled.  */
+__attribute__((noinline, no_icf))
+_Bool f2(const char *s)
+{
+  unsigned len = __builtin_strlen (s);
+  return len == 0; 
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 9d7b4df..54f8109 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -45,6 +45,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "ipa-chkp.h"
 #include "tree-hash-traits.h"
 #include "builtins.h"
+#include "tree-pretty-print.h"
 
 /* A vector indexed by SSA_NAME_VERSION.  0 means unknown, positive value
    is an index into strinfo vector, negative value stands for
@@ -2302,6 +2303,43 @@  strlen_optimize_stmt (gimple_stmt_iterator *gsi)
 	  else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
 	    handle_pointer_plus (gsi);
 	}
+      /* strlen (s) eq/ne 0 -> *s eq/ne 0.  */
+      else if (TREE_CODE (lhs) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
+	{
+	  tree rhs2 = gimple_assign_rhs2 (stmt);
+	  tree_code code = gimple_assign_rhs_code (stmt);
+
+	  if ((code == EQ_EXPR || code == NE_EXPR) && integer_zerop (rhs2))
+	    {
+	      tree rhs1 = gimple_assign_rhs1 (stmt);
+	      if (TREE_CODE (rhs1) == SSA_NAME)
+		{
+		  gimple *def_stmt = SSA_NAME_DEF_STMT (rhs1);
+		  if (is_a<gassign *> (def_stmt)
+		      && (gimple_assign_rhs_code (def_stmt) == CONVERT_EXPR
+			  || gimple_assign_rhs_code (def_stmt) == NOP_EXPR)
+		      && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
+		    def_stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def_stmt));
+
+		  if (gcall *call_stmt = dyn_cast<gcall *> (def_stmt))
+		    {
+		      tree callee = gimple_call_fndecl (call_stmt);
+		      if (valid_builtin_call (call_stmt)
+			  && DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN)
+			{
+			  tree arg = gimple_call_arg (call_stmt, 0);
+			  tree op = build2 (MEM_REF, char_type_node, arg, build_zero_cst (TREE_TYPE (arg)));
+			  tree temp = make_temp_ssa_name (TREE_TYPE (op), NULL, "strlen");
+			  gimple *memref_stmt = gimple_build_assign (temp, op);
+			  gimple_stmt_iterator call_gsi = gsi_for_stmt (call_stmt);
+			  gsi_insert_before (&call_gsi, memref_stmt, GSI_SAME_STMT);
+			  gassign *g = gimple_build_assign (gimple_call_lhs (call_stmt), CONVERT_EXPR, temp);
+			  gsi_replace (&call_gsi, g, true);
+			}
+		    }
+		}
+	    }
+	}
       else if (TREE_CODE (lhs) != SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
 	{
 	  tree type = TREE_TYPE (lhs);
@@ -2505,7 +2543,7 @@  const pass_data pass_data_strlen =
   0, /* properties_provided */
   0, /* properties_destroyed */
   0, /* todo_flags_start */
-  0, /* todo_flags_finish */
+  TODO_update_ssa, /* todo_flags_finish */
 };
 
 class pass_strlen : public gimple_opt_pass