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] c gimplification changes


In the process of working on my statement chaining patch, I discovered
that we were failing to gimplify some expressions.  I have no idea how
we weren't running into that before.

Fixing those instances in the straightforward way revealed that we 
were re-gimplifying statements more than once.  This causes problems
because the main gimplifier creates WITH_CLEANUP_EXPR nodes for C++.
It puts them on the statement's pre-queue expecting never to see 
them again until we return to gimplify_cleanup_point_expr.  And if
it does see them again, it aborts.

I was on the verge of adding a case for WITH_CLEANUP_EXPR to the 
main gimplification loop, so that we just ignore the node there,
and assume it'll be handled later.  But insanity prevailed, and I
rearranged the C gimplifier such that it doesn't do as much 
redundant work.  Long term we probably should ignore WCE, as it
would make the compiler more robust.

There are changes to expected failures:

-FAIL: g++.dg/gcov/gcov-1.C gcov: 4 failures in line counts,\
	 3 in branch percentages, 0 in return percentages
+FAIL: g++.dg/gcov/gcov-1.C gcov: 0 failures in line counts,\
	 1 in branch percentages, 0 in return percentages

	C++ coverage testing improves.  Not completely fixed yet,
	but better.  This is more or less by accident; I didn't
	specifically work on it.  Bonus!

+FAIL: gcc.dg/20020425-1.c (test for excess errors)

	This is a test for 11,000 nested else-ifs.  We blow the stack.

	If we expect to handle this case, we need to restructure things
	a bit.  In particular, we'd need to iterate, rather than recurse,
	else-nested if statements.  I don't think this will be too hard,
	but I think this is out of scope for this patch.

	IMO we passed before by accident rather than design, so I'm
	ignoring this for the moment.

+FAIL: gcc.dg/tree-ssa/20031015-1.c scan-tree-dump-times VUSE  1

	Diego, this is your bug.  You added the test case but didn't
	fix it.  It was passing before by accident.

	  #   T.1_2 = VDEF <T.1_1>;
	  T.1 = {};
	  #   x_4 = VDEF <x_3>;
	  #   VUSE <T.1_2>;
	  x = T.1;
	  __asm__ __volatile__("call ___checkme"::"c" &x:"memory");

	The gimplifier was creating a temporary, for no discernable
	reason, and the VUSE that was scanned was associated with that
	and not the ASM_EXPR, as expected.

	I expect this test would be more robust if we checked for
	the VUSE the end of compilation rather than the beginning,
	and if we make sure it's for X instead of T.1.

Bootstrapped and tested on i686-linux.


r~


        * c-semantics.c (build_stmt): Set TREE_SIDE_EFFECTS.
        * c-simplify.c (c_gimplify_stmt): Return a gimplify_status;
        mind the status from subroutines to avoid re-gimplification.
        (c_build_bind_expr): Do not call gimplify_stmt.
        (gimplify_c_loop): Don't create a loop_expr; fully gimplify.
        (gimplify_block, gimplify_cleanup, gimplify_expr_stmt,
        gimplify_for_stmt, gimplify_while_stmt, gimplify_do_stmt,
        gimplify_if_stmt, gimplify_switch_stmt, gimplify_return_stmt,
        gimplify_decl_stmt, gimplify_compound_literal_expr,
        gimplify_stmt_expr): Return a gimplify_status.  In most cases,
        don't do local gimplification of sub-structures.
        (gimplify_decl_stmt): Use append_to_compound_expr when we care
        about the result value.
        (gimplify_stmt_expr): Use append_to_statement_list_force and
        re-gimplify so that voidify_wrapper_expr can work.
        (finish_bc_block): Don't append to a non-list.
        (c_gimplify_expr): Pass back the gimplify_status of subroutines.
        * c-common.h (c_gimplify_stmt): Update decl.
        * gimplify.c (append_to_statement_list_1): Make sure list_p is
        never null after call.
        (append_to_compound_expr): New.
        * tree-simple.h (append_to_compound_expr): Declare.

Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.141.2.37
diff -c -p -d -r1.141.2.37 c-common.h
*** c-common.h	31 Oct 2003 07:29:42 -0000	1.141.2.37
--- c-common.h	12 Nov 2003 02:36:08 -0000
*************** extern void c_warn_unused_result (tree *
*** 1290,1296 ****
  
  /* In c-simplify.c  */
  extern void c_genericize (tree);
! extern void c_gimplify_stmt (tree *);
  
  extern void pch_init (void);
  extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd);
--- 1290,1296 ----
  
  /* In c-simplify.c  */
  extern void c_genericize (tree);
! extern int c_gimplify_stmt (tree *);
  
  extern void pch_init (void);
  extern int c_common_valid_pch (cpp_reader *pfile, const char *name, int fd);
Index: c-semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-semantics.c,v
retrieving revision 1.43.2.25
diff -c -p -d -r1.43.2.25 c-semantics.c
*** c-semantics.c	30 Oct 2003 02:49:40 -0000	1.43.2.25
--- c-semantics.c	12 Nov 2003 02:36:08 -0000
*************** finish_stmt_tree (tree *t)
*** 190,211 ****
  tree
  build_stmt (enum tree_code code, ...)
  {
!   tree t;
!   int length;
!   int i;
    va_list p;
  
    va_start (p, code);
  
!   t = make_node (code);
    length = TREE_CODE_LENGTH (code);
!   STMT_LINENO (t) = input_line;
  
    for (i = 0; i < length; i++)
!     TREE_OPERAND (t, i) = va_arg (p, tree);
  
    va_end (p);
!   return t;
  }
  
  /* Some statements, like for-statements or if-statements, require a
--- 190,231 ----
  tree
  build_stmt (enum tree_code code, ...)
  {
!   tree ret;
!   int length, i;
    va_list p;
+   bool side_effects;
  
    va_start (p, code);
  
!   ret = make_node (code);
    length = TREE_CODE_LENGTH (code);
!   STMT_LINENO (ret) = input_line;
! 
!   /* Most statements have implicit side effects all on their own, 
!      such as control transfer.  For those that do, we'll compute
!      the real value of TREE_SIDE_EFFECTS from its arguments.  */
!   switch (code)
!     {
!     case EXPR_STMT:
!       side_effects = false;
!       break;
!     default:
!       side_effects = true;
!       break;
!     }
  
    for (i = 0; i < length; i++)
!     {
!       tree t = va_arg (p, tree);
!       if (t)
!         side_effects |= TREE_SIDE_EFFECTS (t);
!       TREE_OPERAND (ret, i) = t;
!     }
! 
!   TREE_SIDE_EFFECTS (ret) = side_effects;
  
    va_end (p);
!   return ret;
  }
  
  /* Some statements, like for-statements or if-statements, require a
Index: c-simplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-simplify.c,v
retrieving revision 1.1.4.80
diff -c -p -d -r1.1.4.80 c-simplify.c
*** c-simplify.c	11 Nov 2003 22:40:25 -0000	1.1.4.80
--- c-simplify.c	12 Nov 2003 02:53:01 -0000
*************** Software Foundation, 59 Temple Place - S
*** 70,92 ****
  
  /* Local declarations.  */
  
! void c_gimplify_stmt (tree *);
! static void gimplify_expr_stmt (tree *);
! static void gimplify_decl_stmt (tree *);
! static void gimplify_for_stmt (tree *, tree *);
! static void gimplify_while_stmt (tree *);
! static void gimplify_do_stmt (tree *);
! static void gimplify_if_stmt (tree *);
! static void gimplify_switch_stmt (tree *);
! static void gimplify_return_stmt (tree *);
! static void gimplify_stmt_expr (tree *);
! static void gimplify_compound_literal_expr (tree *);
  #if defined ENABLE_CHECKING
  static int is_last_stmt_of_scope (tree);
  #endif
! static void gimplify_block (tree *, tree *);
! static void gimplify_cleanup (tree *, tree *);
! static tree gimplify_c_loop (tree, tree, tree, int);
  static void push_context (void);
  static void pop_context (void);
  static tree c_build_bind_expr (tree, tree);
--- 70,91 ----
  
  /* Local declarations.  */
  
! static enum gimplify_status gimplify_expr_stmt (tree *);
! static enum gimplify_status gimplify_decl_stmt (tree *);
! static enum gimplify_status gimplify_for_stmt (tree *, tree *);
! static enum gimplify_status gimplify_while_stmt (tree *);
! static enum gimplify_status gimplify_do_stmt (tree *);
! static enum gimplify_status gimplify_if_stmt (tree *);
! static enum gimplify_status gimplify_switch_stmt (tree *);
! static enum gimplify_status gimplify_return_stmt (tree *);
! static enum gimplify_status gimplify_stmt_expr (tree *);
! static enum gimplify_status gimplify_compound_literal_expr (tree *);
  #if defined ENABLE_CHECKING
  static int is_last_stmt_of_scope (tree);
  #endif
! static enum gimplify_status gimplify_block (tree *, tree *);
! static enum gimplify_status gimplify_cleanup (tree *, tree *);
! static tree gimplify_c_loop (tree, tree, tree, bool);
  static void push_context (void);
  static void pop_context (void);
  static tree c_build_bind_expr (tree, tree);
*************** c_genericize (tree fndecl)
*** 167,173 ****
  /*  Entry point for the tree lowering pass.  Recursively scan
      *STMT_P and convert it to a GIMPLE tree.  */
  
! void
  c_gimplify_stmt (tree *stmt_p)
  {
    tree stmt, next;
--- 166,172 ----
  /*  Entry point for the tree lowering pass.  Recursively scan
      *STMT_P and convert it to a GIMPLE tree.  */
  
! int
  c_gimplify_stmt (tree *stmt_p)
  {
    tree stmt, next;
*************** c_gimplify_stmt (tree *stmt_p)
*** 190,195 ****
--- 189,195 ----
        tree pre, post;
        int saved_stmts_are_full_exprs_p;
        location_t stmt_locus;
+       enum gimplify_status ret;
  
        /* Set up context appropriately for handling this statement.  */
        saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
*************** c_gimplify_stmt (tree *stmt_p)
*** 204,255 ****
        switch (TREE_CODE (stmt))
  	{
  	case COMPOUND_STMT:
- 	  c_gimplify_stmt (&COMPOUND_BODY (stmt));
  	  stmt = COMPOUND_BODY (stmt);
  	  break;
  
  	case SCOPE_STMT:
! 	  gimplify_block (&stmt, &next);
  	  break;
  
  	case FOR_STMT:
! 	  gimplify_for_stmt (&stmt, &pre);
  	  break;
  
  	case WHILE_STMT:
! 	  gimplify_while_stmt (&stmt);
  	  break;
  
  	case DO_STMT:
! 	  gimplify_do_stmt (&stmt);
  	  break;
  
  	case IF_STMT:
! 	  gimplify_if_stmt (&stmt);
  	  break;
  
  	case SWITCH_STMT:
! 	  gimplify_switch_stmt (&stmt);
  	  break;
  
  	case EXPR_STMT:
! 	  gimplify_expr_stmt (&stmt);
  	  break;
  
  	case RETURN_STMT:
! 	  gimplify_return_stmt (&stmt);
  	  break;
  
  	case DECL_STMT:
! 	  gimplify_decl_stmt (&stmt);
  	  break;
  
  	case LABEL_STMT:
  	  stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt));
  	  break;
  
  	case GOTO_STMT:
  	  stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
  	  break;
  
  	case CASE_LABEL:
--- 204,257 ----
        switch (TREE_CODE (stmt))
  	{
  	case COMPOUND_STMT:
  	  stmt = COMPOUND_BODY (stmt);
+ 	  ret = GS_OK;
  	  break;
  
  	case SCOPE_STMT:
! 	  ret = gimplify_block (&stmt, &next);
  	  break;
  
  	case FOR_STMT:
! 	  ret = gimplify_for_stmt (&stmt, &pre);
  	  break;
  
  	case WHILE_STMT:
! 	  ret = gimplify_while_stmt (&stmt);
  	  break;
  
  	case DO_STMT:
! 	  ret = gimplify_do_stmt (&stmt);
  	  break;
  
  	case IF_STMT:
! 	  ret = gimplify_if_stmt (&stmt);
  	  break;
  
  	case SWITCH_STMT:
! 	  ret = gimplify_switch_stmt (&stmt);
  	  break;
  
  	case EXPR_STMT:
! 	  ret = gimplify_expr_stmt (&stmt);
  	  break;
  
  	case RETURN_STMT:
! 	  ret = gimplify_return_stmt (&stmt);
  	  break;
  
  	case DECL_STMT:
! 	  ret = gimplify_decl_stmt (&stmt);
  	  break;
  
  	case LABEL_STMT:
  	  stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt));
+ 	  ret = GS_OK;
  	  break;
  
  	case GOTO_STMT:
  	  stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
+ 	  ret = GS_OK;
  	  break;
  
  	case CASE_LABEL:
*************** c_gimplify_stmt (tree *stmt_p)
*** 257,275 ****
  	    tree label = create_artificial_label ();
  	    stmt = build (CASE_LABEL_EXPR, void_type_node,
  			  CASE_LOW (stmt), CASE_HIGH (stmt), label);
  	  }
  	  break;
  
  	case CONTINUE_STMT:
  	  stmt = build_bc_goto (bc_continue);
  	  break;
  
  	case BREAK_STMT:
  	  stmt = build_bc_goto (bc_break);
  	  break;
  
  	case CLEANUP_STMT:
! 	  gimplify_cleanup (&stmt, &next);
  	  break;
  
  	case ASM_STMT:
--- 259,280 ----
  	    tree label = create_artificial_label ();
  	    stmt = build (CASE_LABEL_EXPR, void_type_node,
  			  CASE_LOW (stmt), CASE_HIGH (stmt), label);
+ 	    ret = GS_OK;
  	  }
  	  break;
  
  	case CONTINUE_STMT:
  	  stmt = build_bc_goto (bc_continue);
+ 	  ret = GS_OK;
  	  break;
  
  	case BREAK_STMT:
  	  stmt = build_bc_goto (bc_break);
+ 	  ret = GS_OK;
  	  break;
  
  	case CLEANUP_STMT:
! 	  ret = gimplify_cleanup (&stmt, &next);
  	  break;
  
  	case ASM_STMT:
*************** c_gimplify_stmt (tree *stmt_p)
*** 280,285 ****
--- 285,291 ----
  	    ASM_INPUT_P (new_stmt) = ASM_INPUT_P (stmt);
  	    ASM_VOLATILE_P (new_stmt) = ASM_VOLATILE_P (stmt);
  	    stmt = new_stmt;
+ 	    ret = GS_OK;
  	  }
  	  break;
  
*************** c_gimplify_stmt (tree *stmt_p)
*** 289,302 ****
  
  	default:
  	  if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt, &next))
! 	    break;
  
! 	  fprintf (stderr, "unhandled statement node in c_gimplify_stmt ():\n");
  	  debug_tree (stmt);
  	  abort ();
  	  break;
  	}
  
        /* PRE and POST now contain a list of statements for all the
  	 side-effects in STMT.  */
  
--- 295,324 ----
  
  	default:
  	  if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt, &next))
! 	    {
! 	      ret = GS_OK;
! 	      break;
! 	    }
  
! 	  fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n");
  	  debug_tree (stmt);
  	  abort ();
  	  break;
  	}
  
+       switch (ret)
+ 	{
+ 	case GS_ERROR:
+ 	  goto cont;
+ 	case GS_OK:
+           gimplify_stmt (&stmt);
+ 	  break;
+ 	case GS_ALL_DONE:
+ 	  break;
+ 	default:
+ 	  abort ();
+ 	}
+ 
        /* PRE and POST now contain a list of statements for all the
  	 side-effects in STMT.  */
  
*************** c_gimplify_stmt (tree *stmt_p)
*** 313,318 ****
--- 335,342 ----
      }
    append_to_statement_list (stmt, &outer_pre);
    *stmt_p = rationalize_compound_expr (outer_pre);
+ 
+   return GS_ALL_DONE;
  }
  
  static void
*************** c_build_bind_expr (tree block, tree body
*** 363,369 ****
  
    bind = build (BIND_EXPR, void_type_node, decls, body, block);
    TREE_SIDE_EFFECTS (bind) = 1;
-   gimplify_stmt (&bind);
  
    return bind;
  }
--- 387,392 ----
*************** c_build_bind_expr (tree block, tree body
*** 373,379 ****
     that matching SCOPE_STMTs will always appear in the same statement
     sequence.  */
  
! static void
  gimplify_block (tree *stmt_p, tree *next_p)
  {
    tree *p;
--- 396,402 ----
     that matching SCOPE_STMTs will always appear in the same statement
     sequence.  */
  
! static enum gimplify_status
  gimplify_block (tree *stmt_p, tree *next_p)
  {
    tree *p;
*************** gimplify_block (tree *stmt_p, tree *next
*** 388,394 ****
        if (!errorcount && !sorrycount)
  	abort ();
        *stmt_p = NULL;
!       return;
      }
  
    block = SCOPE_STMT_BLOCK (*stmt_p);
--- 411,417 ----
        if (!errorcount && !sorrycount)
  	abort ();
        *stmt_p = NULL;
!       return GS_ERROR;
      }
  
    block = SCOPE_STMT_BLOCK (*stmt_p);
*************** gimplify_block (tree *stmt_p, tree *next
*** 427,439 ****
    bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p));
    *stmt_p = bind;
    input_line = stmt_lineno;
  }
  
  /* Genericize a CLEANUP_STMT.  Just wrap everything from here to the end of
     the block in a TRY_FINALLY_EXPR.  Or a TRY_CATCH_EXPR, if it's an
     EH-only cleanup.  */
  
! static void
  gimplify_cleanup (tree *stmt_p, tree *next_p)
  {
    tree stmt = *stmt_p;
--- 450,464 ----
    bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p));
    *stmt_p = bind;
    input_line = stmt_lineno;
+ 
+   return GS_OK;
  }
  
  /* Genericize a CLEANUP_STMT.  Just wrap everything from here to the end of
     the block in a TRY_FINALLY_EXPR.  Or a TRY_CATCH_EXPR, if it's an
     EH-only cleanup.  */
  
! static enum gimplify_status
  gimplify_cleanup (tree *stmt_p, tree *next_p)
  {
    tree stmt = *stmt_p;
*************** gimplify_cleanup (tree *stmt_p, tree *ne
*** 442,451 ****
    enum tree_code code
      = (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR);
  
!   c_gimplify_stmt (&body);
  
    *stmt_p = build (code, void_type_node, body, cleanup);
    *next_p = NULL_TREE;
  }
  
  /*  Gimplify an EXPR_STMT node.
--- 467,481 ----
    enum tree_code code
      = (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR);
  
!   if (!body)
!     body = build_empty_stmt ();
!   if (!cleanup)
!     cleanup = build_empty_stmt ();
  
    *stmt_p = build (code, void_type_node, body, cleanup);
    *next_p = NULL_TREE;
+ 
+   return GS_OK;
  }
  
  /*  Gimplify an EXPR_STMT node.
*************** gimplify_cleanup (tree *stmt_p, tree *ne
*** 458,464 ****
      POST_P points to the list where side effects that must happen after
  	STMT should be stored.  */
  
! static void
  gimplify_expr_stmt (tree *stmt_p)
  {
    tree stmt = EXPR_STMT_EXPR (*stmt_p);
--- 488,494 ----
      POST_P points to the list where side effects that must happen after
  	STMT should be stored.  */
  
! static enum gimplify_status
  gimplify_expr_stmt (tree *stmt_p)
  {
    tree stmt = EXPR_STMT_EXPR (*stmt_p);
*************** gimplify_expr_stmt (tree *stmt_p)
*** 494,499 ****
--- 524,531 ----
      stmt = build1 (CLEANUP_POINT_EXPR, void_type_node, stmt);
  
    *stmt_p = stmt;
+ 
+   return GS_OK;
  }
  
  /* If the condition for a loop (or the like) is a decl, it will be a
*************** finish_bc_block (tree label, tree body)
*** 543,552 ****
  
    if (TREE_USED (label))
      {
!       tree expr = build1 (LABEL_EXPR, void_type_node, label);
        /* Clear the name so flow can delete the label.  */
        DECL_NAME (label) = NULL_TREE;
!       append_to_statement_list (expr, &body);
      }
  
    ctxp->current_bc_label = TREE_CHAIN (label);
--- 575,589 ----
  
    if (TREE_USED (label))
      {
!       tree t, sl = NULL;
! 
        /* Clear the name so flow can delete the label.  */
        DECL_NAME (label) = NULL_TREE;
!       t = build1 (LABEL_EXPR, void_type_node, label);
! 
!       append_to_statement_list (body, &sl);
!       append_to_statement_list (t, &sl);
!       body = sl;
      }
  
    ctxp->current_bc_label = TREE_CHAIN (label);
*************** build_bc_goto (enum bc_t bc)
*** 593,685 ****
     loop body as in do-while loops.  */
  
  static tree
! gimplify_c_loop (tree cond, tree body, tree incr, int cond_is_first)
  {
!   tree exit, cont_block, break_block, loop;
    location_t stmt_locus;
-   tree stuff, entry = NULL_TREE;
  
    stmt_locus = input_location;
  
!   break_block = begin_bc_block (bc_break);
  
!   loop = build (LOOP_EXPR, void_type_node, NULL_TREE);
  
!   if (cond)
      {
!       gimplify_condition (&cond);
!       exit = build_bc_goto (bc_break);
!       exit = build (COND_EXPR, void_type_node, cond, build_empty_stmt (), exit);
!       exit = fold (exit);
      }
    else
      exit = NULL_TREE;
  
    cont_block = begin_bc_block (bc_continue);
  
!   c_gimplify_stmt (&body);
  
    body = finish_bc_block (cont_block, body);
  
!   stuff = NULL_TREE;
!   if (cond_is_first)
!     {
!       if (exit)
! 	{
! 	  entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
! 	  append_to_statement_list (body, &stuff);
! 	  append_to_statement_list (incr, &stuff);
! 	  append_to_statement_list (entry, &stuff);
! 	  append_to_statement_list (exit, &stuff);
! 	}
!       else
! 	{
! 	  append_to_statement_list (body, &stuff);
! 	  append_to_statement_list (incr, &stuff);
! 	}
!     }
!   else
!     {
!       append_to_statement_list (body, &stuff);
!       append_to_statement_list (incr, &stuff);
!       append_to_statement_list (exit, &stuff);
!     }
! 
!   annotate_all_with_locus (&stuff, stmt_locus);
! 
!   LOOP_EXPR_BODY (loop) = rationalize_compound_expr (stuff);
  
!   loop = finish_bc_block (break_block, loop);
!   if (entry)
      {
!       stuff = build_and_jump (&LABEL_EXPR_LABEL (entry));
!       append_to_statement_list (loop, &stuff);
!       loop = stuff;
      }
  
!   /* This catches do ... while (0) loops and eliminates their looping
!      structure.  Conditions for detecting these loops:
  
! 	1. The condition must be last.
! 	2. We must have exit code.
! 	3. The exit code must be an unconditional jump to the 'break'
! 	   label.  The way we construct the exit code above assures that
! 	   if the exit code is an unconditional jump, then it will
! 	   have the 'break' label as its target.
! 	4. The 'continue' label must be unused.  */
!   if (! cond_is_first
!       && exit
!       && TREE_CODE (exit) == GOTO_EXPR
!       && ! TREE_USED (cont_block))
!     TREE_OPERAND (loop, 0) = TREE_OPERAND (TREE_OPERAND (loop, 0), 0);
  
!   return loop;
  }
  
  /* Gimplify a FOR_STMT node.  Move the stuff in the for-init-stmt into the
     prequeue and hand off to gimplify_c_loop.  */
  
! static void
  gimplify_for_stmt (tree *stmt_p, tree *pre_p)
  {
    tree stmt = *stmt_p;
--- 630,707 ----
     loop body as in do-while loops.  */
  
  static tree
! gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first)
  {
!   tree top, entry, exit, cont_block, break_block, stmt_list, t;
    location_t stmt_locus;
  
    stmt_locus = input_location;
  
!   /* Detect do { ... } while (0) and don't generate loop construct.  */
!   if (!cond_is_first && cond && integer_zerop (cond))
!     top = cond = NULL;
!   else
!     {
!       /* If we use a LOOP_EXPR here, we have to feed the whole thing
! 	 back through the main gimplifier to lower it.  Given that we
! 	 have to gimplify the loop body NOW so that we can resolve
! 	 break/continue stmts, seems easier to just expand to gotos.  */
!       top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
!     }
  
!   break_block = begin_bc_block (bc_break);
  
!   if (top)
      {
!       /* If we have an exit condition, then we build an IF with gotos either
! 	 out of the loop, or to the top of it.  If there's no exit condition,
! 	 then we just build a jump back to the top.  */
!       exit = build_and_jump (&LABEL_EXPR_LABEL (top));
!       if (cond)
! 	{
! 	  gimplify_condition (&cond);
! 	  t = build_bc_goto (bc_break);
! 	  exit = build (COND_EXPR, void_type_node, cond, exit, t);
! 	  exit = fold (exit);
! 	  gimplify_stmt (&exit);
! 	}
      }
    else
      exit = NULL_TREE;
  
    cont_block = begin_bc_block (bc_continue);
  
!   gimplify_stmt (&body);
!   gimplify_stmt (&incr);
  
    body = finish_bc_block (cont_block, body);
  
!   stmt_list = NULL;
  
!   if (cond_is_first && cond)
      {
!       entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
!       t = build_and_jump (&LABEL_EXPR_LABEL (entry));
!       append_to_statement_list (t, &stmt_list);
      }
+   else
+     entry = NULL_TREE;
  
!   append_to_statement_list (top, &stmt_list);
!   append_to_statement_list (body, &stmt_list);
!   append_to_statement_list (incr, &stmt_list);
!   append_to_statement_list (entry, &stmt_list);
!   append_to_statement_list (exit, &stmt_list);
  
!   annotate_all_with_locus (&stmt_list, stmt_locus);
  
!   return finish_bc_block (break_block, stmt_list);
  }
  
  /* Gimplify a FOR_STMT node.  Move the stuff in the for-init-stmt into the
     prequeue and hand off to gimplify_c_loop.  */
  
! static enum gimplify_status
  gimplify_for_stmt (tree *stmt_p, tree *pre_p)
  {
    tree stmt = *stmt_p;
*************** gimplify_for_stmt (tree *stmt_p, tree *p
*** 690,737 ****
  
    *stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
  			     FOR_EXPR (stmt), 1);
  }
  
  /* Gimplify a WHILE_STMT node.  */
  
! static void
  gimplify_while_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    *stmt_p = gimplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt),
  			     NULL_TREE, 1);
  }
  
  /* Gimplify a DO_STMT node.  */
  
! static void
  gimplify_do_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    *stmt_p = gimplify_c_loop (DO_COND (stmt), DO_BODY (stmt),
  			     NULL_TREE, 0);
  }
  
  /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
  
! static void
  gimplify_if_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    tree then_ = THEN_CLAUSE (stmt);
    tree else_ = ELSE_CLAUSE (stmt);
-   tree cond = IF_COND (stmt);
  
!   gimplify_condition (&cond);
!   c_gimplify_stmt (&then_);
!   c_gimplify_stmt (&else_);
  
!   *stmt_p = build (COND_EXPR, void_type_node, cond, then_, else_);
  }
  
  /* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR.  */
  
! static void
  gimplify_switch_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
--- 712,767 ----
  
    *stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
  			     FOR_EXPR (stmt), 1);
+ 
+   return GS_ALL_DONE;
  }
  
  /* Gimplify a WHILE_STMT node.  */
  
! static enum gimplify_status
  gimplify_while_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    *stmt_p = gimplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt),
  			     NULL_TREE, 1);
+   return GS_ALL_DONE;
  }
  
  /* Gimplify a DO_STMT node.  */
  
! static enum gimplify_status
  gimplify_do_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    *stmt_p = gimplify_c_loop (DO_COND (stmt), DO_BODY (stmt),
  			     NULL_TREE, 0);
+   return GS_ALL_DONE;
  }
  
  /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
  
! static enum gimplify_status
  gimplify_if_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    tree then_ = THEN_CLAUSE (stmt);
    tree else_ = ELSE_CLAUSE (stmt);
  
!   if (!then_)
!     then_ = build_empty_stmt ();
!   if (!else_)
!     else_ = build_empty_stmt ();
  
!   stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_);
!   gimplify_condition (& TREE_OPERAND (stmt, 0));
! 
!   *stmt_p = stmt;
!   return GS_OK;
  }
  
  /* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR.  */
  
! static enum gimplify_status
  gimplify_switch_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
*************** gimplify_switch_stmt (tree *stmt_p)
*** 752,762 ****
    gimplify_stmt (stmt_p);
  
    *stmt_p = finish_bc_block (break_block, *stmt_p);
  }
  
  /* Genericize a RETURN_STMT by turning it into a RETURN_EXPR.  */
  
! static void
  gimplify_return_stmt (tree *stmt_p)
  {
    tree expr = RETURN_STMT_EXPR (*stmt_p);
--- 782,793 ----
    gimplify_stmt (stmt_p);
  
    *stmt_p = finish_bc_block (break_block, *stmt_p);
+   return GS_ALL_DONE;
  }
  
  /* Genericize a RETURN_STMT by turning it into a RETURN_EXPR.  */
  
! static enum gimplify_status
  gimplify_return_stmt (tree *stmt_p)
  {
    tree expr = RETURN_STMT_EXPR (*stmt_p);
*************** gimplify_return_stmt (tree *stmt_p)
*** 764,769 ****
--- 795,801 ----
    if (stmts_are_full_exprs_p ())
      expr = build1 (CLEANUP_POINT_EXPR, void_type_node, expr);
    *stmt_p = expr;
+   return GS_OK;
  }
  
  /* walk_tree helper function for gimplify_decl_stmt.  */
*************** mark_labels_r (tree *tp, int *walk_subtr
*** 795,801 ****
     Usually these last two will be the same, but they may need to be
     different if the DECL_STMT is somehow embedded in an expression.  */
  
! static void
  gimplify_decl_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
--- 827,833 ----
     Usually these last two will be the same, but they may need to be
     different if the DECL_STMT is somehow embedded in an expression.  */
  
! static enum gimplify_status
  gimplify_decl_stmt (tree *stmt_p)
  {
    tree stmt = *stmt_p;
*************** gimplify_decl_stmt (tree *stmt_p)
*** 806,812 ****
    if (TREE_TYPE (decl) == error_mark_node)
      {
        *stmt_p = NULL;
!       return;
      }
  
    if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
--- 838,844 ----
    if (TREE_TYPE (decl) == error_mark_node)
      {
        *stmt_p = NULL;
!       return GS_ERROR;
      }
  
    if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
*************** gimplify_decl_stmt (tree *stmt_p)
*** 828,834 ****
  	     tree_cons (NULL_TREE,
  			build1 (ADDR_EXPR, pt_type, decl),
  			tree_cons (NULL_TREE, size, NULL_TREE)));
! 	  append_to_statement_list (alloc, &pre);
  	}
  
        if (init && init != error_mark_node)
--- 860,866 ----
  	     tree_cons (NULL_TREE,
  			build1 (ADDR_EXPR, pt_type, decl),
  			tree_cons (NULL_TREE, size, NULL_TREE)));
! 	  append_to_compound_expr (alloc, &pre);
  	}
  
        if (init && init != error_mark_node)
*************** gimplify_decl_stmt (tree *stmt_p)
*** 839,846 ****
  	      init = build (MODIFY_EXPR, void_type_node, decl, init);
  	      if (stmts_are_full_exprs_p ())
  		init = build1 (CLEANUP_POINT_EXPR, void_type_node, init);
! 	      /* FIXME: Shouldn't we gimplify here?  */
! 	      append_to_statement_list (init, &pre);
  	    }
  	  else
  	    {
--- 871,877 ----
  	      init = build (MODIFY_EXPR, void_type_node, decl, init);
  	      if (stmts_are_full_exprs_p ())
  		init = build1 (CLEANUP_POINT_EXPR, void_type_node, init);
! 	      append_to_compound_expr (init, &pre);
  	    }
  	  else
  	    {
*************** gimplify_decl_stmt (tree *stmt_p)
*** 857,864 ****
  	gimple_add_tmp_var (decl);
      }
  
!   append_to_statement_list (post, &pre);
    *stmt_p = pre;
  }
  
  /* Gimplification of expression trees.  */
--- 888,896 ----
  	gimple_add_tmp_var (decl);
      }
  
!   append_to_compound_expr (post, &pre);
    *stmt_p = pre;
+   return GS_OK;
  }
  
  /* Gimplification of expression trees.  */
*************** gimplify_decl_stmt (tree *stmt_p)
*** 867,873 ****
     DECL_STMT before the current EXPR_STMT and using its anonymous decl
     instead.  */
  
! static void
  gimplify_compound_literal_expr (tree *expr_p)
  {
    tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
--- 899,905 ----
     DECL_STMT before the current EXPR_STMT and using its anonymous decl
     instead.  */
  
! static enum gimplify_status
  gimplify_compound_literal_expr (tree *expr_p)
  {
    tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
*************** gimplify_compound_literal_expr (tree *ex
*** 875,880 ****
--- 907,913 ----
  
    gimplify_decl_stmt (&decl_s);
    *expr_p = decl_s ? decl_s : decl;
+   return GS_OK;
  }
  
  /* Do C-specific gimplification.  Args are as for gimplify_expr.  */
*************** c_gimplify_expr (tree *expr_p, tree *pre
*** 886,907 ****
    enum tree_code code = TREE_CODE (*expr_p);
  
    if (STATEMENT_CODE_P (code))
!     c_gimplify_stmt (expr_p);
!   else switch (code)
      {
      case COMPOUND_LITERAL_EXPR:
!       gimplify_compound_literal_expr (expr_p);
!       break;
  
      case STMT_EXPR:
!       gimplify_stmt_expr (expr_p);
!       break;
  
      default:
        return GS_UNHANDLED;
      }
- 
-   return GS_OK;
  }
  
  /* Gimplify a STMT_EXPR.  EXPR_P points to the expression to gimplify.
--- 919,937 ----
    enum tree_code code = TREE_CODE (*expr_p);
  
    if (STATEMENT_CODE_P (code))
!     return c_gimplify_stmt (expr_p);
! 
!   switch (code)
      {
      case COMPOUND_LITERAL_EXPR:
!       return gimplify_compound_literal_expr (expr_p);
  
      case STMT_EXPR:
!       return gimplify_stmt_expr (expr_p);
  
      default:
        return GS_UNHANDLED;
      }
  }
  
  /* Gimplify a STMT_EXPR.  EXPR_P points to the expression to gimplify.
*************** c_gimplify_expr (tree *expr_p, tree *pre
*** 912,928 ****
     PRE_P points to the list where side effects that must happen before
       *EXPR_P should be stored.  */
  
! static void
  gimplify_stmt_expr (tree *expr_p)
  {
    tree body = STMT_EXPR_STMT (*expr_p);
    if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
!     c_gimplify_stmt (&body);
    else
      {
!       tree substmt, last_stmt, last_expr, bind;
! 
!       bind = NULL_TREE;	/* [GIMPLE] Avoid uninitialized use warning.  */
  
        /* Splice the last expression out of the STMT chain.  */
        last_stmt = NULL_TREE;
--- 942,960 ----
     PRE_P points to the list where side effects that must happen before
       *EXPR_P should be stored.  */
  
! static enum gimplify_status
  gimplify_stmt_expr (tree *expr_p)
  {
    tree body = STMT_EXPR_STMT (*expr_p);
+ 
    if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
!     {
!       *expr_p = body;
!       return c_gimplify_stmt (expr_p);
!     }
    else
      {
!       tree last_stmt, last_expr, substmt;
  
        /* Splice the last expression out of the STMT chain.  */
        last_stmt = NULL_TREE;
*************** gimplify_stmt_expr (tree *expr_p)
*** 938,944 ****
  	  location_t loc;
  	  loc.file = input_filename;
  	  loc.line = STMT_LINENO (last_stmt);
! 	  warning ("%Hstatement-expressions should end with a non-void expression", &loc);
  	  last_expr = NULL_TREE;
  	}
        else
--- 970,977 ----
  	  location_t loc;
  	  loc.file = input_filename;
  	  loc.line = STMT_LINENO (last_stmt);
! 	  warning ("%Hstatement-expressions should end with a "
! 		   "non-void expression", &loc);
  	  last_expr = NULL_TREE;
  	}
        else
*************** gimplify_stmt_expr (tree *expr_p)
*** 962,992 ****
        /* Now retrofit that last expression into the BIND_EXPR.  */
        if (last_expr)
  	{
! 	  if (!STMT_EXPR_NO_SCOPE (*expr_p))
! 	    {
! 	      bind = body;
! 	      substmt = BIND_EXPR_BODY (bind);
! 	    }
! 	  else
! 	    substmt = body;
! 
! 	  if (IS_EMPTY_STMT (substmt))
! 	    substmt = last_expr;
! 	  else
! 	    substmt = build (COMPOUND_EXPR, TREE_TYPE (last_expr),
! 			    substmt, last_expr);
  
  	  if (!STMT_EXPR_NO_SCOPE (*expr_p))
  	    {
! 	      BIND_EXPR_BODY (bind) = substmt;
! 	      TREE_TYPE (bind) = TREE_TYPE (body) = TREE_TYPE (last_expr);
  	    }
  	  else
! 	    body = substmt;
  	}
-     }
  
!   *expr_p = body;
  }
  
  /* Code generation.  */
--- 995,1022 ----
        /* Now retrofit that last expression into the BIND_EXPR.  */
        if (last_expr)
  	{
! 	  tree *sub_p;
  
  	  if (!STMT_EXPR_NO_SCOPE (*expr_p))
  	    {
! 	      /* Our BIND_EXPR will always be hidden within
! 		 a STATEMENT_LIST.  Discard that.  */
! 	      body = expr_first (body);
! 	      sub_p = &BIND_EXPR_BODY (body);
! 
! 	      /* Append the last expression to the end of the BIND_EXPR.
! 		 We'll now re-process this, and let voidify_wrapper_expr
! 		 do its job.  */
! 	      append_to_statement_list_force (last_expr, sub_p);
! 	      TREE_TYPE (body) = TREE_TYPE (last_expr);
  	    }
  	  else
! 	    append_to_compound_expr (last_expr, &body);
  	}
  
!       *expr_p = body;
!       return GS_OK;
!     }
  }
  
  /* Code generation.  */
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.109
diff -c -p -d -r1.1.2.109 gimplify.c
*** gimplify.c	12 Nov 2003 02:33:13 -0000	1.1.2.109
--- gimplify.c	12 Nov 2003 02:36:08 -0000
*************** append_to_statement_list_1 (tree stmt, t
*** 184,192 ****
  {
    tree existing = *list_p;
  
!   /* If we previously had nothing, allow an empty statement.  */
!   if (!existing && stmt && IS_EMPTY_STMT (stmt))
!     ;
    /* If side effects say to discard the new statement, do so.  */
    else if (!side_effects)
      return;
--- 184,195 ----
  {
    tree existing = *list_p;
  
!   /* If we previously had nothing, force a statement of some sort.  */
!   if (!existing)
!     {
!       if (!stmt || (!side_effects && !IS_EMPTY_STMT (stmt)))
! 	stmt = build_empty_stmt ();
!     }
    /* If side effects say to discard the new statement, do so.  */
    else if (!side_effects)
      return;
*************** void
*** 212,217 ****
--- 215,234 ----
  append_to_statement_list_force (tree t, tree *list_p)
  {
    append_to_statement_list_1 (t, list_p, t != NULL);
+ }
+ 
+ /* Add T to the end of a COMPOUND_EXPR pointed by LIST_P.  The type
+    of the result is the type of T.  */
+ 
+ void
+ append_to_compound_expr (tree t, tree *list_p)
+ {
+   if (!t)
+     return;
+   if (!*list_p)
+     *list_p = t;
+   else
+     *list_p = build (COMPOUND_EXPR, TREE_TYPE (t), *list_p, t);
  }
  
  /* Strip off a legitimate source ending from the input string NAME of
Index: tree-simple.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.h,v
retrieving revision 1.1.4.38
diff -c -p -d -r1.1.4.38 tree-simple.h
*** tree-simple.h	11 Nov 2003 00:07:18 -0000	1.1.4.38
--- tree-simple.h	12 Nov 2003 02:36:08 -0000
*************** void foreach_stmt (tree *, foreach_stmt_
*** 80,85 ****
--- 80,86 ----
  
  void append_to_statement_list (tree, tree *);
  void append_to_statement_list_force (tree, tree *);
+ void append_to_compound_expr (tree, tree *);
  
  /* FIXME we should deduce this from the predicate.  */
  typedef enum fallback_t {


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