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]

[tree-ssa] Various fixes


Just bug fixes.  Ironically, one of the bug fixes introduces new
regressions in builtins because it prevents a builtin simplification
that we were doing wrong previously.

This patch fixes PR/11373 and these regressions from c-torture:

Fixed regressions in 20030731/gcc.sum.gz:
         FAIL: gcc.c-torture/execute/builtins/string-8.c execution
         FAIL: gcc.c-torture/execute/builtins/string-8.c execution
         FAIL: gcc.c-torture/execute/builtins/string-8.c execution
         FAIL: gcc.c-torture/execute/stdio-opt-1.c execution
         FAIL: gcc.c-torture/execute/stdio-opt-1.c execution
         FAIL: gcc.c-torture/execute/stdio-opt-1.c execution
         FAIL: gcc.c-torture/execute/stdio-opt-1.c execution
         FAIL: gcc.c-torture/execute/string-opt-16.c execution
         FAIL: gcc.c-torture/execute/string-opt-16.c execution
         FAIL: gcc.c-torture/execute/string-opt-17.c execution
         FAIL: gcc.c-torture/execute/string-opt-17.c execution
         FAIL: gcc.c-torture/execute/string-opt-17.c execution
         FAIL: gcc.c-torture/execute/string-opt-17.c execution
         FAIL: gcc.c-torture/execute/string-opt-17.c execution
         FAIL: gcc.c-torture/execute/string-opt-17.c execution

The new regressions that the patch introduces are

New regressions in 20030731/gcc.sum.gz:
         FAIL: gcc.dg/builtins-10.c (test for excess errors)
         FAIL: gcc.dg/builtins-26.c (test for excess errors)
         FAIL: gcc.dg/builtins-7.c (test for excess errors)


The main fixes are:

In validate_arglist() we were not checking for TREE_SIDE_EFFECTS.  This
is important because the simplify_builtin_...() functions are called
before gimplification, so if the arguments have side effects (e.g., i++)
we can't replace the builtin with a different version.  This fixes the
regression of string-opt-17.c.  In that test, we were causing the
gimplifier to emit 'i = i + 1' twice.  The new failures are because we
now refuse to simplify builtins with side-effects in their argument
list.

This leads to the second set of fixes which is now a bit incomplete, but
the initial framework is there.  I will probably come back to finish it
after I'm done fixing must-alias bugs.  Essentially, I think we are
calling simplify_builtin() too early.

Take for instance string-8.c.  One of the tests calls 'strlen (g++ ?
"foo" : "bar")', which the original RTL expanders detect by walking the
COND_EXPR tree in the call to strlen().  But in GIMPLE we emit no such
tree, it is expanded to an if-then-else construct which is then not
detected by the expander.  It also, can't be detected at gimplification
time because we have no dataflow information.

However, all this is trivial to determine in CCP.  I think that since
most/all builtin optimization relies on constant propagation
information, either CCP, the dominator optimizers, or even a final pass
in the SSA->normal phase would be a better place to do these
micro-optimizations.

For now, I've added a get_strlen() function to CCP that it's used when
folding strlen and fputs to take advantage of constant string lengths
(even when the string themselves may be different).

I also added a simplifier for sprintf that fixes string-opt-16.c

The other fixes are for PR/11373 that deals with constants being used as
pointers and doing things like *0xC000 = 3.

Bootstrapped and tested x86, amd64, ppc and ia64.


Diego.

	* Makefile.in (tree-ssa-ccp.o): Depend on $(EXPR_H).
	* builtins.c (c_strlen): Remove static declaration.
	(simplify_builtin_fputs): Remove static declaration.
	(simplify_builtin_sprintf): New local function.
	(expand_builtin_sprintf): Remove by surrounding with #if 0.
	(expand_builtin): Add BUILT_IN_SPRINTF to the list of built-ins
	handed over to simplify_builtin.
	(validate_arglist): Do not allow arguments with TREE_SIDE_EFFECTS.
	(simplify_builtin_fputs): Add new argument KNOWN_LEN.  If it's set,
	use it instead of trying to compute the length of the string.
	Update all callers.
	* expr.h (simplify_builtin_fputs): Declare.
	* tree-flow.h (fold_stmt): Change argument type to tree *.  Update
	all users.
	* tree-ssa-ccp.c: Include expr.h.
	(replace_uses_in): If the statement makes a call to some selected
	built-ins, mark it for folding.
	(get_strlen): New local function.
	(ccp_fold_builtin): New local function.
	(fold_stmt): Call it.
	(set_rhs): Fix if-else-if chaining.  Handle cases where the whole
	statement needs to be replaced.
	* tree.h (c_strlen): Declare.


	Fix PR optimization/11373
	* tree-ssa-dce.c (stmt_useful_p): Get statement operands before
	checking for volatile operands.
	* tree-dfa.c (get_expr_operands): If a constant is dereferenced as a
	pointer, mark the statement as having volatile operands.
	(may_access_global_mem_p): If a non-NULL constant is used as a
	pointer, consider it as pointing to global memory.
	* tree-ssa-dom.c (optimize_stmt): Set addr_expr_propagated_p when
	propagating pointers that are integer constants.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.104
diff -d -u -p -r1.903.2.104 Makefile.in
--- Makefile.in	30 Jul 2003 19:24:07 -0000	1.903.2.104
+++ Makefile.in	31 Jul 2003 15:09:21 -0000
@@ -1737,7 +1737,8 @@ ssa-ccp.o : ssa-ccp.c $(CONFIG_H) $(SYST
     errors.h $(GGC_H) df.h function.h
 tree-ssa-ccp.o : tree-ssa-ccp.c $(CONFIG_H) system.h errors.h $(TREE_H) \
     $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \
-    $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SIMPLE_H)
+    $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SIMPLE_H) \
+    $(EXPR_H)
 tree-ssa-copyprop.o : tree-ssa-copyprop.c $(CONFIG_H) system.h errors.h \
     $(TREE_H) $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h $(TIMEVAR_H) \
     $(TREE_DUMP_H) coretypes.h $(TREE_SIMPLE_H) $(TM_H)
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.152.2.27
diff -d -u -p -r1.152.2.27 builtins.c
--- builtins.c	25 Jul 2003 12:28:23 -0000	1.152.2.27
+++ builtins.c	31 Jul 2003 15:09:22 -0000
@@ -89,7 +89,6 @@ static REAL_VALUE_TYPE dconstpi;
 static REAL_VALUE_TYPE dconste;
 
 static int get_pointer_alignment (tree, unsigned int);
-static tree c_strlen (tree, int);
 static const char *c_getstr (tree);
 static rtx c_readstr (const char *, enum machine_mode);
 static int target_char_cast (tree, char *);
@@ -176,9 +175,9 @@ static tree simplify_builtin_strcat (tre
 static tree simplify_builtin_strncat (tree);
 static tree simplify_builtin_strspn (tree);
 static tree simplify_builtin_strcspn (tree);
-static tree simplify_builtin_fputs (tree, int, int);
 static void simplify_builtin_next_arg (tree);
 static void simplify_builtin_va_start (tree);
+static tree simplify_builtin_sprintf (tree, int);
 
 /* Initialize mathematical constants for constant folding builtins.
    These constants need to be given to at least 160 bits precision.  */
@@ -278,7 +277,7 @@ get_pointer_alignment (tree exp, unsigne
    Unfortunately, string_constant can't access the values of const char
    arrays with initializers, so neither can we do so here.  */
 
-static tree
+tree
 c_strlen (tree src, int only_value)
 {
   tree offset_node;
@@ -4585,6 +4584,7 @@ expand_builtin_cabs (tree arglist, rtx t
   return expand_complex_abs (mode, op0, target, 0);
 }
 
+#if 0
 /* Expand a call to sprintf with argument list ARGLIST.  Return 0 if
    a normal call should be emitted rather than expanding the function
    inline.  If convenient, the result should be placed in TARGET with
@@ -4669,6 +4669,7 @@ expand_builtin_sprintf (tree arglist, rt
 
   return 0;
 }
+#endif
 
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -5132,6 +5133,7 @@ expand_builtin (tree exp, rtx target, rt
     case BUILT_IN_FPUTS:
     case BUILT_IN_FPUTS_UNLOCKED:
     case BUILT_IN_STRCMP:
+    case BUILT_IN_SPRINTF:
       {
 	tree new;
 	new = simplify_builtin (exp, ignore);
@@ -5255,12 +5257,12 @@ expand_builtin (tree exp, rtx target, rt
       if (target)
 	return target;
       break;
-#endif
     case BUILT_IN_SPRINTF:
       target = expand_builtin_sprintf (arglist, target, mode);
       if (target)
 	return target;
       break;
+#endif
 
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
@@ -6283,7 +6285,8 @@ validate_arglist (tree arglist, ...)
 	     match the specified code, return false.  Otherwise continue
 	     checking any remaining arguments.  */
 	  if (arglist == 0
-	      || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
+	      || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist)))
+	      || TREE_SIDE_EFFECTS (TREE_VALUE (arglist)))
 	    goto end;
 	  break;
 	}
@@ -6378,9 +6381,9 @@ simplify_builtin (tree exp, int ignore)
   switch (fcode)
     {
     case BUILT_IN_FPUTS:
-      return simplify_builtin_fputs (arglist, ignore, 0);
+      return simplify_builtin_fputs (arglist, ignore, 0, NULL_TREE);
     case BUILT_IN_FPUTS_UNLOCKED:
-      return simplify_builtin_fputs (arglist, ignore, 1);
+      return simplify_builtin_fputs (arglist, ignore, 1, NULL_TREE);
     case BUILT_IN_STRSTR:
       return simplify_builtin_strstr (arglist);
     case BUILT_IN_STRCAT:
@@ -6413,6 +6416,8 @@ simplify_builtin (tree exp, int ignore)
     case BUILT_IN_VA_START:
       simplify_builtin_va_start (arglist);
       return NULL_TREE;
+    case BUILT_IN_SPRINTF:
+      return simplify_builtin_sprintf (arglist, ignore);
     default:
       return NULL_TREE;
     }
@@ -7270,10 +7275,14 @@ simplify_builtin_strcspn (tree arglist)
    COMPOUND_EXPR will be an argument which must be evaluated.
    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
    COMPOUND_EXPR in the chain will contain the tree for the simplified
-   form of the builtin function call.  */
+   form of the builtin function call.
 
-static tree
-simplify_builtin_fputs (tree arglist, int ignore, int unlocked)
+   If KNOWN_LEN is non-NULL, it represents the known length of the string.
+   This is determined by SSA-CCP in cases where the string itself is not
+   known to be constant but its length is always the same constant.  */
+
+tree
+simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len)
 {
   tree len, fn;
   tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
@@ -7290,9 +7299,11 @@ simplify_builtin_fputs (tree arglist, in
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
 
+  len = (known_len) ? known_len : c_strlen (TREE_VALUE (arglist), 0);
+
   /* Get the length of the string passed to fputs.  If the length
      can't be determined, punt.  */
-  if (!(len = c_strlen (TREE_VALUE (arglist), 0))
+  if (!len
       || TREE_CODE (len) != INTEGER_CST)
     return 0;
 
@@ -7386,4 +7397,85 @@ simplify_builtin_next_arg (tree arglist)
     /* Evidently an out of date version of <stdarg.h>; can't validate
        va_start's second argument, but can still work as intended.  */
     warning ("`__builtin_next_arg' called without an argument");
+}
+
+
+/* Simplify a call to the sprintf builtin.
+
+   Return 0 if no simplification was possible, otherwise return the
+   simplified form of the call as a tree.  If IGNORED is true, it means that
+   the caller does not use the returned value of the function.  */
+
+static tree
+simplify_builtin_sprintf (tree arglist, int ignored)
+{
+  tree call, retval, dest, fmt;
+  const char *fmt_str = NULL;
+
+  /* Verify the required arguments in the original call.  We deal with two
+     types of sprintf() calls: 'sprintf (str, fmt)' and
+     'sprintf (dest, "%s", orig)'.  */
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
+      && !validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE,
+	                    VOID_TYPE))
+    return NULL_TREE;
+
+  /* Get the destination string and the format specifier.  */
+  dest = TREE_VALUE (arglist);
+  fmt = TREE_VALUE (TREE_CHAIN (arglist));
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str == NULL)
+    return NULL_TREE;
+
+  call = NULL_TREE;
+  retval = NULL_TREE;
+
+  /* If the format doesn't contain % args or %%, use strcpy.  */
+  if (strchr (fmt_str, '%') == NULL)
+    {
+      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+      if (!fn)
+	return NULL_TREE;
+
+      /* Convert sprintf (str, fmt) into strcpy (str, fmt) when
+	 'format' is known to contain no % formats.  */
+      arglist = build_tree_list (NULL_TREE, fmt);
+      arglist = tree_cons (NULL_TREE, dest, arglist);
+      call = build_function_call_expr (fn, arglist);
+      if (!ignored)
+	retval = build_int_2 (strlen (fmt_str), 0);
+    }
+
+  /* If the format is "%s", use strcpy if the result isn't used.  */
+  else if (fmt_str && strcmp (fmt_str, "%s") == 0)
+    {
+      tree fn, orig;
+      fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+      if (!fn)
+	return NULL_TREE;
+
+      /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2).  */
+      orig = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      arglist = build_tree_list (NULL_TREE, orig);
+      arglist = tree_cons (NULL_TREE, dest, arglist);
+      if (!ignored)
+	{
+	  retval = c_strlen (orig, 1);
+	  if (!retval || TREE_CODE (retval) != INTEGER_CST)
+	    return NULL_TREE;
+	}
+      call = build_function_call_expr (fn, arglist);
+    }
+
+  if (call && retval)
+    return build (COMPOUND_EXPR,
+	          TREE_TYPE (implicit_built_in_decls[BUILT_IN_SPRINTF]),
+		  call,
+		  retval);
+  else
+    return call;
 }
Index: expr.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.h,v
retrieving revision 1.117.2.15
diff -d -u -p -r1.117.2.15 expr.h
--- expr.h	23 Jul 2003 16:59:43 -0000	1.117.2.15
+++ expr.h	31 Jul 2003 15:09:22 -0000
@@ -367,6 +367,7 @@ extern void record_base_value (unsigned 
 extern void record_alias_subset (HOST_WIDE_INT, HOST_WIDE_INT);
 extern HOST_WIDE_INT new_alias_set (void);
 extern int can_address_p (tree);
+extern tree simplify_builtin_fputs (tree, int, int, tree);
 
 /* Functions from expr.c:  */
 
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.137
diff -d -u -p -r1.1.4.137 tree-dfa.c
--- tree-dfa.c	31 Jul 2003 12:10:46 -0000	1.1.4.137
+++ tree-dfa.c	31 Jul 2003 15:09:23 -0000
@@ -377,6 +377,15 @@ get_expr_operands (tree stmt, tree *expr
 	  add_stmt_operand (&TREE_OPERAND (ptr, 0), stmt, flags, prev_vops);
 	  return;
 	}
+      else if (TREE_CONSTANT (ptr) && !integer_zerop (ptr))
+	{
+	  /* If a constant is used as a pointer, we can't generate a real
+	     operand for it but we mark the statement volatile to prevent
+	     optimizations from messing things up.  */
+	  stmt_ann (stmt)->has_volatile_ops = true;
+	  return;
+	}
+
 
       /* Add a USE operand for the base pointer.  */
       get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_none, prev_vops);
@@ -2110,6 +2119,10 @@ may_access_global_mem_p (tree expr)
 
   /* Call expressions that return pointers may point to global memory.  */
   if (TREE_CODE (expr) == CALL_EXPR)
+    return true;
+
+  /* A non-NULL constant used as a pointer points to global memory.  */
+  if (TREE_CONSTANT (expr) && !integer_zerop (expr))
     return true;
 
   /* Recursively check the expression's operands.  */
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.97
diff -d -u -p -r1.1.4.97 tree-flow.h
--- tree-flow.h	23 Jul 2003 23:48:16 -0000	1.1.4.97
+++ tree-flow.h	31 Jul 2003 15:09:23 -0000
@@ -469,7 +469,7 @@ extern void tree_perform_ssapre (tree);
 
 /* In tree-ssa-ccp.c  */
 void tree_ssa_ccp (tree);
-void fold_stmt (tree);
+void fold_stmt (tree *);
 
 /* In tree-ssa-dom.c  */
 extern bool tree_ssa_dominator_optimize (tree);
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.80
diff -d -u -p -r1.1.2.80 tree-ssa-ccp.c
--- tree-ssa-ccp.c	28 Jul 2003 17:16:20 -0000	1.1.2.80
+++ tree-ssa-ccp.c	31 Jul 2003 15:09:23 -0000
@@ -52,6 +52,7 @@ Software Foundation, 59 Temple Place - S
 #include "tree-simple.h"
 #include "tree-dump.h"
 #include "timevar.h"
+#include "expr.h"
 
 /* Possible lattice values.  */
 typedef enum
@@ -122,11 +123,13 @@ static tree widen_bitfield (tree, tree, 
 static bool replace_uses_in (tree);
 static latticevalue likely_value (tree);
 static tree get_rhs (tree);
-static void set_rhs (tree, tree);
+static void set_rhs (tree *, tree);
 static value *get_value (tree);
 static value get_default_value (tree);
 static hashval_t value_map_hash (const void *);
 static int value_map_eq (const void *, const void *);
+static tree ccp_fold_builtin (tree, tree);
+static tree get_strlen (tree);
 
 
 /* Debugging dumps.  */
@@ -327,7 +330,7 @@ substitute_and_fold (void)
 
 	  if (replace_uses_in (stmt))
 	    {
-	      fold_stmt (stmt);
+	      fold_stmt (bsi_stmt_ptr (i));
 	      modify_stmt (stmt);
 	    }
 
@@ -1178,6 +1181,32 @@ replace_uses_in (tree stmt)
 	}
     }
 
+  /* Some builtins like strlen may evaluate to a constant value even if
+     they have non-constant operands.  For instance,
+     'strlen (g++ ? "foo" : "bar")' will always evaluate to 3.  If the
+     statement contains a call to one of these builtins, pretend that we
+     replaced constant operands in it so that it can be handed to
+     fold_stmt().  */
+  if (!replaced
+      && (TREE_CODE (stmt) == CALL_EXPR
+	  || (TREE_CODE (stmt) == MODIFY_EXPR
+	      && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)))
+
+    {
+      tree rhs = (TREE_CODE (stmt) == MODIFY_EXPR)
+		  ? TREE_OPERAND (stmt, 1)
+		  : stmt;
+      tree callee = get_callee_fndecl (rhs);
+
+      /* For now, we are only interested in handling a few builtins.  */
+      if (callee
+	  && DECL_BUILT_IN (callee)
+	  && DECL_BUILT_IN_CLASS (callee) != BUILT_IN_MD)
+	replaced = (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN
+	            || DECL_FUNCTION_CODE (callee) == BUILT_IN_FPUTS
+		    || DECL_FUNCTION_CODE (callee) == BUILT_IN_FPUTS_UNLOCKED);
+    }
+
   return replaced;
 }
 
@@ -1224,18 +1253,35 @@ likely_value (tree stmt)
 }
 
 
-/* Fold statement STMT.  */
+/* Fold the statement pointed by STMT_P.  In some cases, this function may
+   replace the whole statement with a new one.  */
 
 void
-fold_stmt (tree stmt)
+fold_stmt (tree *stmt_p)
 {
-  tree rhs, result;
+  tree rhs, result, stmt;
 
+  stmt = *stmt_p;
   rhs = get_rhs (stmt);
   if (rhs && !TREE_CONSTANT (rhs))
     {
-      result = fold (rhs);
-      set_rhs (stmt, result);
+      result = NULL_TREE;
+
+      /* Check for builtins that CCP can handle using information not
+	 available in the generic fold routines.  */
+      if (TREE_CODE (rhs) == CALL_EXPR)
+	{
+	  tree callee = get_callee_fndecl (rhs);
+	  if (callee && DECL_BUILT_IN (callee))
+	    result = ccp_fold_builtin (stmt, rhs);
+	}
+
+      /* If we couldn't fold the RHS, hand it over to the generic fold
+	 routines.  */
+      if (result == NULL_TREE)
+	result = fold (rhs);
+
+      set_rhs (stmt_p, result);
     }
 }
 
@@ -1269,16 +1315,17 @@ get_rhs (tree stmt)
 }
 
 
-/* Set the main expression of STMT to EXPR.  */
+/* Set the main expression of *STMT_P to EXPR.  */
 
 static void
-set_rhs (tree stmt, tree expr)
+set_rhs (tree *stmt_p, tree expr)
 {
+  tree stmt = *stmt_p;
   enum tree_code code = TREE_CODE (stmt);
 
   if (code == MODIFY_EXPR)
     TREE_OPERAND (stmt, 1) = expr;
-  if (code == COND_EXPR)
+  else if (code == COND_EXPR)
     COND_EXPR_COND (stmt) = expr;
   else if (code == SWITCH_EXPR)
     SWITCH_COND (stmt) = expr;
@@ -1294,6 +1341,12 @@ set_rhs (tree stmt, tree expr)
     GOTO_DESTINATION (stmt) = expr;
   else if (code == LABEL_EXPR)
     LABEL_EXPR_LABEL (stmt) = expr;
+  else
+    {
+      stmt_ann_t ann = stmt_ann (stmt);
+      *stmt_p = expr;
+      (*stmt_p)->common.ann = (tree_ann) ann;
+    }
 }
 
 
@@ -1389,4 +1442,125 @@ value_map_eq (const void *p1, const void
 {
   return ((const struct value_map_d *)p1)->var
 	 == ((const struct value_map_d *)p2)->var;
+}
+
+
+/* Fold builtin call FN in statement STMT.  If it cannot be folded into a
+   constant, return NULL_TREE.  Otherwise, return its constant value.  */
+
+static tree
+ccp_fold_builtin (tree stmt, tree fn)
+{
+  tree result;
+  tree arglist = TREE_OPERAND (fn, 1);
+  tree callee = get_callee_fndecl (fn);
+
+  /* Ignore MD builtins.  */
+  if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
+    return NULL_TREE;
+
+  /* First try the generic builtin folder.  If that succeeds, return the
+     result directly.  */
+  result = fold_builtin (fn);
+  if (result)
+    return result;
+
+  /* Otherwise, try to use the dataflow information gathered by the CCP
+     process.  */
+  switch (DECL_FUNCTION_CODE (callee))
+    {
+      case BUILT_IN_STRLEN:
+	return get_strlen (TREE_VALUE (arglist));
+
+      case BUILT_IN_FPUTS:
+	return simplify_builtin_fputs (arglist,
+				       TREE_CODE (stmt) != MODIFY_EXPR, 0,
+				       get_strlen (TREE_VALUE (arglist)));
+      case BUILT_IN_FPUTS_UNLOCKED:
+	return simplify_builtin_fputs (arglist,
+				       TREE_CODE (stmt) != MODIFY_EXPR, 1,
+				       get_strlen (TREE_VALUE (arglist)));
+
+      default:
+	break;
+    }
+
+
+  return NULL_TREE;
+}
+
+
+/* Return the string length of ARG.  If ARG is an SSA name variable, follow
+   its use-def chains.  If all the reaching definitions for VAR have the
+   same length L, this function returns L.  Otherwise, it returns NULL_TREE
+   indicating that the length cannot be determined statically.  */
+
+static tree
+get_strlen (tree arg)
+{
+  tree var, def_stmt;
+  
+  if (TREE_CODE (arg) != SSA_NAME)
+    return c_strlen (arg, 1);
+
+  var = arg;
+  def_stmt = SSA_NAME_DEF_STMT (var);
+
+  switch (TREE_CODE (def_stmt))
+    {
+      case MODIFY_EXPR:
+	{
+	  tree len, rhs;
+	  
+	  /* The RHS of the statement defining VAR must either have a
+	     constant length or come from another SSA_NAME with a constant
+	     length.  */
+	  rhs = TREE_OPERAND (def_stmt, 1);
+	  STRIP_NOPS (rhs);
+	  if (TREE_CODE (rhs) == SSA_NAME)
+	    return get_strlen (rhs);
+
+	  /* See if the RHS is a constant length.  */
+	  len = c_strlen (rhs, 1);
+	  if (len)
+	    {
+	      /* Convert from the internal "sizetype" type to "size_t".  */
+	      if (size_type_node)
+		len = convert (size_type_node, len);
+	      return len;
+	    }
+
+	  break;
+	}
+
+      case PHI_NODE:
+	{
+	  /* All the arguments of the PHI node must have the same constant
+	     length.  */
+	  int i;
+	  tree arg_len, prev_arg_len;
+
+	  arg_len = prev_arg_len = NULL_TREE;
+	  for (i = 0; i < PHI_NUM_ARGS (def_stmt); i++)
+	    {
+	      arg_len = get_strlen (PHI_ARG_DEF (def_stmt, i));
+	      if (arg_len == NULL_TREE)
+		return NULL_TREE;
+
+	      if (prev_arg_len
+		  && simple_cst_equal (prev_arg_len, arg_len) != 1)
+		return NULL_TREE;
+
+	      prev_arg_len = arg_len;
+	    }
+
+	  return arg_len;
+	}
+
+      default:
+	break;
+    }
+
+
+  return NULL_TREE;
 }
Index: tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dce.c,v
retrieving revision 1.1.2.48
diff -d -u -p -r1.1.2.48 tree-ssa-dce.c
--- tree-ssa-dce.c	28 Jul 2003 17:16:20 -0000	1.1.2.48
+++ tree-ssa-dce.c	31 Jul 2003 15:09:23 -0000
@@ -283,12 +283,12 @@ stmt_useful_p (tree stmt)
 	    return true;
     }
 
+  /* Examine all the stores in this statement.  */
+  get_stmt_operands (stmt);
+
   /* If the statement has volatile operands, it needs to be preserved.  */
   if (stmt_ann (stmt)->has_volatile_ops)
     return true;
-
-  /* Examine all the stores in this statement.  */
-  get_stmt_operands (stmt);
 
   ops = def_ops (stmt);
   for (i = 0; ops && i < VARRAY_ACTIVE_SIZE (ops); i++)
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.14
diff -d -u -p -r1.1.2.14 tree-ssa-dom.c
--- tree-ssa-dom.c	31 Jul 2003 00:50:49 -0000	1.1.2.14
+++ tree-ssa-dom.c	31 Jul 2003 15:09:23 -0000
@@ -553,10 +553,12 @@ optimize_stmt (block_stmt_iterator si, v
 		fprintf (dump_file, "'\n");
 	      }
 
-	    /* If VAL is an ADDR_EXPR, note that we may need to have a
-	       second SSA pass to rename variables exposed by the folding of
-	       *&VAR expressions.  */
-	    if (TREE_CODE (val) == ADDR_EXPR)
+	    /* If VAL is an ADDR_EXPR or a constant of pointer type, note
+	       that we may need to have a second SSA pass to rename
+	       variables exposed by the folding of *&VAR expressions.  */
+	    if (TREE_CODE (val) == ADDR_EXPR
+		|| (POINTER_TYPE_P (TREE_TYPE (*op_p))
+		    && is_unchanging_value (val)))
 	      addr_expr_propagated_p = true;
 
 	    if (TREE_CODE (val) == SSA_NAME)
@@ -574,7 +576,7 @@ optimize_stmt (block_stmt_iterator si, v
   /* If the statement has been modified with constant replacements,
      fold its RHS before checking for redundant computations.  */
   if (ann->modified)
-    fold_stmt (stmt);
+    fold_stmt (bsi_stmt_ptr (si));
 
   /* Check for redundant computations.  Do this optimization only
      for assignments that make no calls and have no aliased stores
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.85
diff -d -u -p -r1.342.2.85 tree.h
--- tree.h	30 Jul 2003 19:24:13 -0000	1.342.2.85
+++ tree.h	31 Jul 2003 15:09:24 -0000
@@ -3124,6 +3124,7 @@ extern tree build_function_call_expr (tr
 extern tree mathfn_built_in (tree, enum built_in_function fn);
 extern tree strip_float_extensions (tree);
 extern tree simplify_builtin (tree, int);
+extern tree c_strlen (tree, int);
 
 /* In convert.c */
 extern tree strip_float_extensions (tree);




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