[ast-optimizer-patch] More C99 fixes [patch]

Diego Novillo dnovillo@redhat.com
Sat Jun 15 06:04:00 GMT 2002


Enabling simplification by default exposed more bugs in the
simplifier.  This patch:

- Adds a new flag to disable simplification: -fdisable-simple.
  The flag is only useful when debugging the simplification
  functions.  It also disables SSA completely.

- Handles functions with declarations before the opening scope of
  the function (gcc.dg/c99-func-1.c).

- Handles for() loops where the initialization statement contains
  declarations (gcc.dg/c99-complit-1.c).

- Handles cases where the front end generates an ADDR_EXPR of a
  CALL_EXPR (gcc.dg/c99-array-lval-1.c).

- Fixes a bug in the simplification of SAVE_EXPR nodes
  (gcc.dg/c99-bool-1.c).  

	_Bool u;
	u = 0;
	if (u++ != 0)

  Is parsed into

	_Bool u;
	u = 0;
	{
	  if (SAVE_EXPR (u), u = 1, SAVE_EXPR (u) != 0)
	    {
	      abort ();
	    }
	}

  which was causing the simplifier to generate two temporaries
  for storing 'u'.  Now the simplifier correctly converts the
  above into:

	_Bool u;
	_Bool T.1;
	u = 0;
	{
	  T.1 = u;
	  u = 1;
	  if (T.1 != 0)
	    {
	      abort ();
	    }
	}

- Handles array and component references wrapped in
  NON_LVALUE_EXPR nodes (gcc.dg/c99-array-lval-3.c).


Bootstrapped and tested on x86.


	* c-decl.c (c_expand_body): Do not simplify nor optimize the
	function if -fdisable-simple is given.
	* c-simplify.c (simplify_expr): Use is_simple_addr_expr_arg when
	simplifying ADDR_EXPR nodes.
	* flags.h (flag_disable_simple): Declare.
	* toplev.c (flag_disable_simple): Define.
	(f_options): Document -fdisable-simple.
	(process_options): Warn if -fdisable-simple is used with
	optimization enabled.
	* tree-simple.c (is_simple_addr_expr_arg): New function.
        (is_simple_unary_expr): Call it.
	* tree-simple.h (is_simple_addr_expr_arg): Declare.
	* doc/invoke.texi: Document -fdisable-simple.

	* c-pretty-print.c (dump_c_node): Handle DECL_STMT nodes inside
	FOR_INIT_STMT.
	* c-simplify.c (c_simplify_function_tree): Don't do anything if the
	program had errors.
	(simplify_stmt): Skip DECL_STMTs.
	(simplify_for_stmt): Handle DECL_STMT nodes inside FOR_INIT_STMT.
	(simplify_save_expr): New function.
	(simplify_expr): Call it.
	(tree_last_decl): Handle cases where DECL_STMTs are found before
	the body of the function.
	* tree-simple.c (is_simple_stmt): Handle DECL_STMT nodes inside
	FOR_INIT_STMT.
	(is_simple_compound_lval): Handle nodes wrapped in NON_LVALUE_EXPR.

Index: c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.239.2.22
diff -d -p -d -u -p -r1.239.2.22 c-decl.c
--- c-decl.c	11 Jun 2002 13:36:38 -0000	1.239.2.22
+++ c-decl.c	15 Jun 2002 05:07:14 -0000
@@ -6841,9 +6842,15 @@ c_expand_body (fndecl, nested_p, can_def
   if (c_function_varargs)
     mark_varargs ();
 
-  /* Invoke the SSA tree optimizer.  */
-  if (flag_tree_ssa)
-    optimize_function_tree (fndecl);
+  /* Simplify the function.  Don't try to optimize the function if
+     simplification failed.  */
+  if (!flag_disable_simple
+      && (*lang_hooks.simplify_function_tree) (fndecl))
+    {
+      /* Invoke the SSA tree optimizer.  */
+      if (flag_tree_ssa)
+	optimize_function_tree (fndecl);
+    }
 
   /* Set up parameters and prepare for return, for the function.  */
   expand_function_start (fndecl, 0);
Index: c-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-pretty-print.c,v
retrieving revision 1.1.2.17
diff -d -p -d -u -p -r1.1.2.17 c-pretty-print.c
--- c-pretty-print.c	13 Jun 2002 01:42:19 -0000	1.1.2.17
+++ c-pretty-print.c	15 Jun 2002 05:07:14 -0000
@@ -973,9 +978,13 @@ dump_c_node (buffer, node, spc)
     case FOR_STMT:
       INDENT (spc);
       output_add_string (buffer, "for (");
-      if (FOR_INIT_STMT (node))
-	dump_c_node (buffer, EXPR_STMT_EXPR (FOR_INIT_STMT (node)), 0);
-      output_add_character (buffer, ';');
+      if (TREE_CODE (FOR_INIT_STMT (node)) == EXPR_STMT)
+	{
+	  dump_c_node (buffer, EXPR_STMT_EXPR (FOR_INIT_STMT (node)), 0);
+	  output_add_character (buffer, ';');
+	}
+      else
+	dump_c_node (buffer, FOR_INIT_STMT (node), 0);
       output_add_space (buffer);
       dump_c_node (buffer, FOR_COND (node), 0);
       output_add_character (buffer, ';');
Index: c-simplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-simplify.c,v
retrieving revision 1.1.2.34
diff -d -p -d -u -p -r1.1.2.34 c-simplify.c
--- c-simplify.c	12 Jun 2002 23:53:28 -0000	1.1.2.34
+++ c-simplify.c	15 Jun 2002 05:07:15 -0000
@@ -82,6 +86,7 @@ static void simplify_boolean_expr    PAR
 static void simplify_compound_expr   PARAMS ((tree *, tree *, tree *, tree));
 static void simplify_expr_wfl        PARAMS ((tree *, tree *, tree *,
                                               int (*) PARAMS ((tree)), tree));
+static void simplify_save_expr       PARAMS ((tree *, tree *, tree));
 static void make_type_writable       PARAMS ((tree));
 static tree add_tree                 PARAMS ((tree, tree *));
 static tree insert_before_continue   PARAMS ((tree, tree));
@@ -115,6 +120,10 @@ c_simplify_function_tree (fndecl)
 {
   tree fnbody;
 
+  /* Don't bother doing anything if the program has errors.  */
+  if (errorcount || sorrycount)
+    return 0;
+  
   fnbody = COMPOUND_BODY (DECL_SAVED_TREE (fndecl));
   if (fnbody == NULL)
     return 1;
@@ -253,9 +250,12 @@ simplify_stmt (stmt)
 	/* Contrary to the original SIMPLE grammar, we do not convert
 	   declaration initializers into SIMPLE assignments because this
 	   breaks several C semantics (static variables, read-only
-	   initializers, dynamic arrays, etc).  */
+	   initializers, dynamic arrays, etc).
+
+	   FIXME: DECL_STMTs should really be simplified.  Inter weaving
+		  DECL_STMTs with other statements should be OK.  */
 	case DECL_STMT:
-	  break;
+	  /* Fall through.  */
 
 	/* Statements that need no simplification.  */
 	case FILE_STMT:
@@ -387,6 +427,18 @@ simplify_for_stmt (stmt, pre_p)
   /* Make sure that the loop body has a scope.  */
   tree_build_scope (&FOR_BODY (stmt));
 
+  /* If FOR_INIT_STMT is a DECL_STMT (C99), move it outside the loop and
+     replace it with an empty expression statement.
+
+     FIXME: The DECL_STMT should be simplified and the DECL_INITIAL for the
+	    last declared variable should be converted into the EXPR_STMT
+	    of the FOR_INIT_STMT.  */
+  if (TREE_CODE (FOR_INIT_STMT (stmt)) == DECL_STMT)
+    {
+      add_tree (FOR_INIT_STMT (stmt), pre_p);
+      FOR_INIT_STMT (stmt) = build_stmt (EXPR_STMT, NULL_TREE);
+    }
+
   init_s = EXPR_STMT_EXPR (FOR_INIT_STMT (stmt));
   cond_s = FOR_COND (stmt);
   expr_s = FOR_EXPR (stmt);
@@ -943,7 +995,7 @@ simplify_expr (expr_p, pre_p, post_p, si
 
     case ADDR_EXPR:
       simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-		     is_simple_varname, stmt, fb_lvalue);
+		     is_simple_addr_expr_arg, stmt, fb_lvalue);
       break;
 
     /* va_arg expressions should also be left alone to avoid confusing the
@@ -997,9 +1049,7 @@ simplify_expr (expr_p, pre_p, post_p, si
     /* SAVE_EXPR nodes are converted into a SIMPLE identifier and
        eliminated.  */
     case SAVE_EXPR:
-      simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id,
-	             stmt, fb_rvalue);
-      *expr_p = TREE_OPERAND (*expr_p, 0);
+      simplify_save_expr (expr_p, pre_p, stmt);
       break;
 
     case EXPR_WITH_FILE_LOCATION:
@@ -1737,6 +1787,38 @@ simplify_expr_wfl (expr_p, pre_p, post_p
     TREE_VALUE (op) = build_expr_wfl (TREE_VALUE (op), file, line, col);
 }
 
+/** Simplify a SAVE_EXPR node.  EXPR_P points to the expression to
+    simplify.  After simplification, EXPR_P will point to a new temporary
+    that holds the original value of the SAVE_EXPR node.
+
+    PRE_P points to the list where side effects that must happen before
+	*EXPR_P should be stored.
+
+    STMT is the statement tree that contains EXPR.  It's used in cases
+	where simplifying an expression requires creating new statement
+	trees.  */
+
+static void
+simplify_save_expr (expr_p, pre_p, stmt)
+     tree *expr_p;
+     tree *pre_p;
+     tree stmt;
+{
+  if (TREE_CODE (*expr_p) != SAVE_EXPR)
+    abort ();
+
+  /* If the operand is already a SIMPLE temporary, just re-write the
+     SAVE_EXPR node.  */
+  if (is_simple_tmp_var (TREE_OPERAND (*expr_p, 0)))
+    *expr_p = TREE_OPERAND (*expr_p, 0);
+  else
+    {
+      TREE_OPERAND (*expr_p, 0) =
+	get_initialized_tmp_var (TREE_OPERAND (*expr_p, 0), pre_p, stmt);
+      *expr_p = TREE_OPERAND (*expr_p, 0);
+    }
+}
+
 
 /* Code generation.  */
 
@@ -2099,7 +2181,10 @@ tree_last_decl (scope)
   while (TREE_CODE (scope) == FILE_STMT)
     scope = TREE_CHAIN (scope);
 
-  if (!SCOPE_BEGIN_P (scope))
+  /* In C99 mode, we can find DECL_STMT nodes before the body of the
+     function.  In that case, we declare all the temporaries there.  */
+  if (TREE_CODE (scope) != DECL_STMT
+      && !SCOPE_BEGIN_P (scope))
     abort ();
 
   /* Find the last declaration statement in the scope.  */
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.65.4.9
diff -d -p -d -u -p -r1.65.4.9 flags.h
--- flags.h	29 May 2002 15:02:03 -0000	1.65.4.9
+++ flags.h	15 Jun 2002 05:07:15 -0000
@@ -660,6 +660,9 @@ extern int flag_detailed_statistics;
 /* Nonzero means enable synchronous exceptions for non-call instructions.  */
 extern int flag_non_call_exceptions;
 
+/* Disable tree simplification.  */
+extern int flag_disable_simple;
+
 /* Enable the SSA tree optimizer.  */
 extern int flag_tree_ssa;
 
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.494.2.17
diff -d -p -d -u -p -r1.494.2.17 toplev.c
--- toplev.c	11 Jun 2002 13:38:20 -0000	1.494.2.17
+++ toplev.c	15 Jun 2002 05:07:15 -0000
@@ -865,6 +865,9 @@ int flag_merge_constants = 1;
    one, unconditionally renumber instruction UIDs.  */
 int flag_renumber_insns = 1;
 
+/* Disable tree simplification.  */
+int flag_disable_simple = 0;
+
 /* Enable the SSA tree optimizer.  */
 int flag_tree_ssa = 0;
 
@@ -1179,6 +1182,8 @@ static const lang_independent_options f_
    N_("Report on permanent memory allocation at end of run") },
   { "trapv", &flag_trapv, 1,
    N_("Trap for signed overflow in addition / subtraction / multiplication") },
+  { "disable-simple", &flag_disable_simple, 1,
+   N_("Do not re-write trees into SIMPLE form") },
   { "tree-ssa", &flag_tree_ssa, 1,
    N_("Enable SSA optimizations on trees") },
   { "tree-ssa-pre", &flag_tree_ssa_pre, 1,
@@ -5043,6 +5048,11 @@ process_options ()
   if (flag_function_sections && write_symbols != NO_DEBUG)
     warning ("-ffunction-sections may affect debugging on some targets");
 #endif
+
+  /* -ftree-ssa and -fdisable-simple cannot be used together because the
+     tree SSA code can only use SIMPLE trees.  */
+  if (flag_tree_ssa && flag_disable_simple)
+    warning ("-fdisable-simple also disables optimizations on trees");
 }
 

 /* Language-independent initialization, before language-dependent
Index: tree-simple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.c,v
retrieving revision 1.1.2.17
diff -d -p -d -u -p -r1.1.2.17 tree-simple.c
--- tree-simple.c	12 Jun 2002 16:07:09 -0000	1.1.2.17
+++ tree-simple.c	15 Jun 2002 05:07:15 -0000
@@ -269,10 +269,20 @@ is_simple_stmt (t)
 	      && is_simple_stmt (DO_BODY (t)));
 
     case FOR_STMT:
-      return (is_simple_exprseq (EXPR_STMT_EXPR (FOR_INIT_STMT (t)))
-	      && is_simple_condexpr (FOR_COND (t))
-	      && is_simple_exprseq (FOR_EXPR (t))
-	      && is_simple_stmt (FOR_BODY (t)));
+      {
+	int s1, s2, s3, s4;
+
+	if (TREE_CODE (FOR_INIT_STMT (t)) == DECL_STMT)
+	  s1 = is_simple_stmt (FOR_INIT_STMT (t));
+	else
+	  s1 = is_simple_exprseq (EXPR_STMT_EXPR (FOR_INIT_STMT (t)));
+
+	s2 = is_simple_condexpr (FOR_COND (t));
+	s3 = is_simple_exprseq (FOR_EXPR (t));
+	s4 = is_simple_stmt (FOR_BODY (t));
+
+	return (s1 && s2 && s3 && s4);
+      }
 
     /* Note that we can assume that we don't need to special case the body
        of the switch() statement.  If we got to this stage, we can assume
@@ -303,7 +313,10 @@ is_simple_stmt (t)
 
     /* The original SIMPLE grammar converts declaration initializers into
        regular assignments.  This is not possible for things like static
-       variables, read-only variables and dynamic arrays.  */
+       variables, read-only variables and dynamic arrays.
+
+       FIXME: DECL_STMTs should really be simplified.  Inter weaving
+	      DECL_STMTs with other statements should be OK.  */
     case DECL_STMT:
       return 1;
 
@@ -539,7 +552,7 @@ is_simple_unary_expr (t)
     return 1;
 
   if (TREE_CODE (t) == ADDR_EXPR
-      && is_simple_varname (TREE_OPERAND (t, 0)))
+      && is_simple_addr_expr_arg (TREE_OPERAND (t, 0)))
     return 1;
 
   if (is_simple_call_expr (t))
@@ -692,6 +705,10 @@ is_simple_compound_lval (t)
       || TREE_CODE (t) == IMAGPART_EXPR)
     t = TREE_OPERAND (t, 0);
 
+  /* Allow arrays wrapped in NON_LVALUE_EXPR nodes.  */
+  if (TREE_CODE (t) == NON_LVALUE_EXPR)
+    t = TREE_OPERAND (t, 0);
+
   if (TREE_CODE (t) != ARRAY_REF && TREE_CODE (t) != COMPONENT_REF)
     return 0;
 
@@ -704,6 +721,31 @@ is_simple_compound_lval (t)
     }
 
   return is_simple_min_lval (t);
+}
+
+/** Return nonzero if T can be used as the argument for an ADDR_EXPR node.
+    This is not part of the original SIMPLE grammar, but in C99 it is
+    possible to generate an address expression for a function call:
+
+      struct A_s {
+	char a[1];
+      } A;
+
+      extern struct A_s foo ();
+
+      main()
+      {
+	char *t = foo().a;
+      }
+
+    When the above is compiled with -std=iso9899:1999, the front end will
+    generate 't = (char *)(char[1] *)&foo ();'.  */
+
+int
+is_simple_addr_expr_arg (t)
+     tree t;
+{
+  return (is_simple_varname (t) || is_simple_call_expr (t));
 }
 
 /** Return nonzero if T is a constant.  */
Index: tree-simple.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.h,v
retrieving revision 1.1.2.12
diff -d -p -d -u -p -r1.1.2.12 tree-simple.h
--- tree-simple.h	12 Jun 2002 16:07:10 -0000	1.1.2.12
+++ tree-simple.h	15 Jun 2002 05:07:15 -0000
@@ -51,6 +51,7 @@ int is_simple_arglist                  P
 int is_simple_const                    PARAMS ((tree));
 int is_simple_id                       PARAMS ((tree));
 int is_simple_varname                  PARAMS ((tree));
+int is_simple_addr_expr_arg            PARAMS ((tree));
 int is_simple_val                      PARAMS ((tree));
 int is_simple_min_lval                 PARAMS ((tree));
 int is_simple_compound_lval            PARAMS ((tree));
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.39.4.20
diff -d -p -d -u -p -r1.39.4.20 invoke.texi
--- doc/invoke.texi	3 Jun 2002 22:00:36 -0000	1.39.4.20
+++ doc/invoke.texi	15 Jun 2002 05:07:17 -0000
@@ -285,7 +285,7 @@ in the following sections.
 -fschedule-insns  -fschedule-insns2 @gol
 -fsingle-precision-constant  -fssa -fssa-ccp -fssa-dce @gol
 -fstrength-reduce  -fstrict-aliasing  -ftracer  -fthread-jumps  -ftrapv @gol
--ftree-ssa  -funroll-all-loops  -funroll-loops  @gol
+-ftree-ssa  -fdisable-simple  -funroll-all-loops  -funroll-loops  @gol
 --param @var{name}=@var{value}
 -O  -O0  -O1  -O2  -O3  -Os}
 
@@ -3678,6 +3678,11 @@ default.
 Enable optimizations on the tree representation based on the Static
 Single Assignment form (SSA). @emph{Note:} This feature is under
 development and should not be used in this version of GCC.
+
+@item -fdisable-simple
+Do not re-write trees into SIMPLE form.  This switch also disables
+tree-based optimizations (See @option{-ftree-ssa}).  @emph{Note:} This
+option is only useful when debugging the tree simplification pass in GCC.
 
 @item -ftracer
 @opindex ftracer



More information about the Gcc-patches mailing list