OSDN Git Service

2003-06-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / c-semantics.c
index e19e73e..374e9f1 100644 (file)
@@ -39,6 +39,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "output.h"
 #include "timevar.h"
 #include "predict.h"
+#include "tree-inline.h"
 
 /* If non-NULL, the address of a language-specific function for
    expanding statements.  */
@@ -51,6 +52,12 @@ void (*lang_expand_stmt) PARAMS ((tree));
    variables and labels do not require any RTL generation.  */
 void (*lang_expand_decl_stmt) PARAMS ((tree));
 
+static tree find_reachable_label_1     PARAMS ((tree *, int *, void *));
+static tree find_reachable_label       PARAMS ((tree));
+static bool expand_unreachable_if_stmt PARAMS ((tree));
+static tree expand_unreachable_stmt    PARAMS ((tree, int));
+static void genrtl_do_stmt_1           PARAMS ((tree, tree));
+
 /* Create an empty statement tree rooted at T.  */
 
 void
@@ -175,7 +182,7 @@ finish_stmt_tree (t)
     {
       /* The line-number recorded in the outermost statement in a function
         is the line number of the end of the function.  */
-      STMT_LINENO (stmt) = lineno;
+      STMT_LINENO (stmt) = input_line;
       STMT_LINENO_FOR_FN_P (stmt) = 1;
     }
 }
@@ -187,23 +194,23 @@ finish_stmt_tree (t)
    in the grammar.  */
 
 tree
-build_stmt VPARAMS ((enum tree_code code, ...))
+build_stmt (enum tree_code code, ...)
 {
   tree t;
   int length;
   int i;
-
-  VA_OPEN (p, code);
-  VA_FIXEDARG (p, enum tree_code, code);
+  va_list p;
+  
+  va_start (p, code);
 
   t = make_node (code);
   length = TREE_CODE_LENGTH (code);
-  STMT_LINENO (t) = lineno;
+  STMT_LINENO (t) = input_line;
 
   for (i = 0; i < length; i++)
     TREE_OPERAND (t, i) = va_arg (p, tree);
 
-  VA_CLOSE (p);
+  va_end (p);
   return t;
 }
 
@@ -280,14 +287,17 @@ emit_local_var (decl)
        expand_decl (decl);
     }
 
-  /* Actually do the initialization.  */
-  if (stmts_are_full_exprs_p ())
-    expand_start_target_temps ();
+  if (DECL_INITIAL (decl))
+    {
+      /* Actually do the initialization.  */
+      if (stmts_are_full_exprs_p ())
+       expand_start_target_temps ();
 
-  expand_decl_init (decl);
+      expand_decl_init (decl);
 
-  if (stmts_are_full_exprs_p ())
-    expand_end_target_temps ();
+      if (stmts_are_full_exprs_p ())
+       expand_end_target_temps ();
+    }
 }
 
 /* Helper for generating the RTL at the beginning of a scope.  */
@@ -295,7 +305,7 @@ emit_local_var (decl)
 void
 genrtl_do_pushlevel ()
 {
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   clear_last_expr ();
 }
 
@@ -313,7 +323,7 @@ genrtl_goto_stmt (destination)
   if (TREE_CODE (destination) == LABEL_DECL)
     TREE_USED (destination) = 1;
   
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   
   if (TREE_CODE (destination) == LABEL_DECL)
     {
@@ -349,7 +359,7 @@ genrtl_expr_stmt_value (expr, want_value, maybe_last)
 {
   if (expr != NULL_TREE)
     {
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       
       if (stmts_are_full_exprs_p ())
        expand_start_target_temps ();
@@ -369,7 +379,7 @@ genrtl_decl_stmt (t)
      tree t;
 {
   tree decl;
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   decl = DECL_STMT_DECL (t);
   /* If this is a declaration for an automatic local
      variable, initialize it.  Note that we might also see a
@@ -406,14 +416,24 @@ genrtl_if_stmt (t)
   tree cond;
   genrtl_do_pushlevel ();
   cond = expand_cond (IF_COND (t));
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   expand_start_cond (cond, 0);
   if (THEN_CLAUSE (t))
-    expand_stmt (THEN_CLAUSE (t));
+    {
+      tree nextt = THEN_CLAUSE (t);
+      
+      if (cond && integer_zerop (cond))
+       nextt = expand_unreachable_stmt (nextt, warn_notreached);
+      expand_stmt (nextt);
+    }
+
   if (ELSE_CLAUSE (t))
     {
+      tree nextt = ELSE_CLAUSE (t);
       expand_start_else ();
-      expand_stmt (ELSE_CLAUSE (t));
+      if (cond && integer_nonzerop (cond))
+       nextt = expand_unreachable_stmt (nextt, warn_notreached);
+      expand_stmt (nextt);
     }
   expand_end_cond ();
 }
@@ -427,14 +447,14 @@ genrtl_while_stmt (t)
   tree cond = WHILE_COND (t);
 
   emit_nop ();
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   expand_start_loop (1); 
   genrtl_do_pushlevel ();
 
   if (cond && !integer_nonzerop (cond))
     {
       cond = expand_cond (cond);
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       expand_exit_loop_top_cond (0, cond);
       genrtl_do_pushlevel ();
     }
@@ -444,14 +464,13 @@ genrtl_while_stmt (t)
   expand_end_loop ();
 }
 
-/* Generate the RTL for T, which is a DO_STMT.  */
+/* Generate the RTL for a DO_STMT with condition COND and loop BODY
+   body.  This is reused for expanding unreachable WHILE_STMTS.  */
 
-void
-genrtl_do_stmt (t)
-     tree t;
+static void
+genrtl_do_stmt_1 (cond, body)
+     tree cond, body;
 {
-  tree cond = DO_COND (t);
-
   /* Recognize the common special-case of do { ... } while (0) and do
      not emit the loop widgetry in this case.  In particular this
      avoids cluttering the rtl with dummy loop notes, which can affect
@@ -460,36 +479,45 @@ genrtl_do_stmt (t)
   if (!cond || integer_zerop (cond))
     {
       expand_start_null_loop ();
-      expand_stmt (DO_BODY (t));
+      expand_stmt (body);
       expand_end_null_loop ();
     }
   else if (integer_nonzerop (cond))
     {
       emit_nop ();
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       expand_start_loop (1);
 
-      expand_stmt (DO_BODY (t));
+      expand_stmt (body);
 
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       expand_end_loop ();
     }
   else
     {
       emit_nop ();
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       expand_start_loop_continue_elsewhere (1);
 
-      expand_stmt (DO_BODY (t));
+      expand_stmt (body);
 
       expand_loop_continue_here ();
       cond = expand_cond (cond);
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       expand_exit_loop_if_false (0, cond);
       expand_end_loop ();
     }
 }
 
+/* Generate the RTL for T, which is a DO_STMT.  */
+
+void
+genrtl_do_stmt (t)
+     tree t;
+{
+  genrtl_do_stmt_1 (DO_COND (t), DO_BODY (t));
+}
+
 /* Build the node for a return statement and return it.  */
 
 tree
@@ -509,7 +537,7 @@ genrtl_return_stmt (stmt)
 
   expr = RETURN_STMT_EXPR (stmt);
 
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   if (!expr)
     expand_null_return ();
   else
@@ -527,8 +555,7 @@ genrtl_for_stmt (t)
      tree t;
 {
   tree cond = FOR_COND (t);
-  const char *saved_filename;
-  int saved_lineno;
+  location_t saved_loc;
 
   if (NEW_FOR_SCOPE_P (t))
     genrtl_do_pushlevel ();
@@ -537,7 +564,7 @@ genrtl_for_stmt (t)
 
   /* Expand the initialization.  */
   emit_nop ();
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   if (FOR_EXPR (t))
     expand_start_loop_continue_elsewhere (1); 
   else
@@ -546,14 +573,13 @@ genrtl_for_stmt (t)
 
   /* Save the filename and line number so that we expand the FOR_EXPR
      we can reset them back to the saved values.  */
-  saved_filename = input_filename;
-  saved_lineno = lineno;
+  saved_loc = input_location;
 
   /* Expand the condition.  */
   if (cond && !integer_nonzerop (cond))
     {
       cond = expand_cond (cond);
-      emit_line_note (input_filename, lineno);
+      emit_line_note (input_filename, input_line);
       expand_exit_loop_top_cond (0, cond);
       genrtl_do_pushlevel ();
     }
@@ -562,9 +588,8 @@ genrtl_for_stmt (t)
   expand_stmt (FOR_BODY (t));
 
   /* Expand the increment expression.  */
-  input_filename = saved_filename;
-  lineno = saved_lineno;
-  emit_line_note (input_filename, lineno);
+  input_location = saved_loc;
+  emit_line_note (input_filename, input_line);
   if (FOR_EXPR (t))
     {
       expand_loop_continue_here ();
@@ -586,7 +611,7 @@ build_break_stmt ()
 void
 genrtl_break_stmt ()
 {
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   if ( ! expand_exit_something ())
     error ("break statement not within loop or switch");
 }
@@ -604,7 +629,7 @@ build_continue_stmt ()
 void
 genrtl_continue_stmt ()
 {
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   if (! expand_continue_loop (0))
     error ("continue statement not within a loop");   
 }
@@ -670,9 +695,9 @@ genrtl_switch_stmt (t)
        crash.  */
     cond = boolean_false_node;
 
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   expand_start_case (1, cond, TREE_TYPE (cond), "switch statement");
-  expand_stmt (SWITCH_BODY (t));
+  expand_stmt (expand_unreachable_stmt (SWITCH_BODY (t), warn_notreached));
   expand_end_case_type (cond, SWITCH_TYPE (t));
 }
 
@@ -753,19 +778,19 @@ genrtl_asm_stmt (cv_qualifier, string, output_operands,
       cv_qualifier = NULL_TREE;
     }
 
-  emit_line_note (input_filename, lineno);
+  emit_line_note (input_filename, input_line);
   if (asm_input_p)
     expand_asm (string, cv_qualifier != NULL_TREE);
   else
     c_expand_asm_operands (string, output_operands, input_operands, 
                           clobbers, cv_qualifier != NULL_TREE,
-                          input_filename, lineno);
+                          input_filename, input_line);
 }
 
-/* Generate the RTL for a DECL_CLEANUP.  */
+/* Generate the RTL for a CLEANUP_STMT.  */
 
 void 
-genrtl_decl_cleanup (t)
+genrtl_cleanup_stmt (t)
      tree t;
 {
   tree decl = CLEANUP_DECL (t);
@@ -781,7 +806,7 @@ prep_stmt (t)
      tree t;
 {
   if (!STMT_LINENO_FOR_FN_P (t))
-    lineno = STMT_LINENO (t);
+    input_line = STMT_LINENO (t);
   current_stmt_tree ()->stmts_are_full_exprs_p = STMT_IS_FULL_EXPR_P (t);
 }
 
@@ -808,7 +833,8 @@ expand_stmt (t)
 
        case RETURN_STMT:
          genrtl_return_stmt (t);
-         break;
+         t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached);
+         goto process_t;
 
        case EXPR_STMT:
          genrtl_expr_stmt_value (EXPR_STMT_EXPR (t), TREE_ADDRESSABLE (t),
@@ -843,11 +869,13 @@ expand_stmt (t)
 
        case BREAK_STMT:
          genrtl_break_stmt ();
-         break;
+         t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached);
+         goto process_t;
 
        case CONTINUE_STMT:
          genrtl_continue_stmt ();
-         break;
+         t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached);
+         goto process_t;
 
        case SWITCH_STMT:
          genrtl_switch_stmt (t);
@@ -864,14 +892,16 @@ expand_stmt (t)
        case GOTO_STMT:
          /* Emit information for branch prediction.  */
          if (!GOTO_FAKE_P (t)
-             && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL)
+             && TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL
+             && flag_guess_branch_prob)
            {
              rtx note = emit_note (NULL, NOTE_INSN_PREDICTION);
 
              NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN);
            }
          genrtl_goto_stmt (GOTO_DESTINATION (t));
-         break;
+         t = expand_unreachable_stmt (TREE_CHAIN (t), warn_notreached);
+         goto process_t;
 
        case ASM_STMT:
          genrtl_asm_stmt (ASM_CV_QUAL (t), ASM_STRING (t),
@@ -884,7 +914,7 @@ expand_stmt (t)
          break;
 
        case CLEANUP_STMT:
-         genrtl_decl_cleanup (t);
+         genrtl_cleanup_stmt (t);
          break;
 
        default:
@@ -895,11 +925,181 @@ expand_stmt (t)
          break;
        }
 
+      /* Go on to the next statement in this scope.  */
+      t = TREE_CHAIN (t);
+
+    process_t:
       /* Restore saved state.  */
       current_stmt_tree ()->stmts_are_full_exprs_p
        = saved_stmts_are_full_exprs_p;
+    }
+}
+\f
+/* If *TP is a potentially reachable label, return nonzero.  */
+
+static tree
+find_reachable_label_1 (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data ATTRIBUTE_UNUSED;
+{
+  switch (TREE_CODE (*tp))
+    {
+    case LABEL_STMT:
+    case CASE_LABEL:
+      return *tp;
 
-      /* Go on to the next statement in this scope.  */
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
+
+/* Determine whether expression EXP contains a potentially
+   reachable label.  */
+static tree
+find_reachable_label (exp)
+     tree exp;
+{
+  location_t saved_loc = input_location;
+  tree ret = walk_tree (&exp, find_reachable_label_1, NULL, NULL);
+  input_location = saved_loc;
+  return ret;
+}
+
+/* Expand an unreachable if statement, T.  This function returns
+   true if the IF_STMT contains a potentially reachable code_label.  */
+static bool
+expand_unreachable_if_stmt (t)
+     tree t;
+{
+  tree n;
+  
+  if (find_reachable_label (IF_COND (t)) != NULL_TREE)
+    {
+      genrtl_if_stmt (t);
+      return true;
+    }
+
+  if (THEN_CLAUSE (t) && ELSE_CLAUSE (t))
+    {
+      n = expand_unreachable_stmt (THEN_CLAUSE (t), 0);
+      
+      if (n != NULL_TREE)
+       {
+         rtx label;
+         expand_stmt (n);
+         label = gen_label_rtx ();
+         emit_jump (label);
+         expand_stmt (expand_unreachable_stmt (ELSE_CLAUSE (t), 0));
+         emit_label (label);
+         return true;
+       }
+      else
+       n = expand_unreachable_stmt (ELSE_CLAUSE (t), 0);
+    }
+  else if (THEN_CLAUSE (t))
+    n = expand_unreachable_stmt (THEN_CLAUSE (t), 0);
+  else if (ELSE_CLAUSE (t))
+    n = expand_unreachable_stmt (ELSE_CLAUSE (t), 0);
+  else
+    n = NULL_TREE;
+  
+  expand_stmt (n);
+  
+  return n != NULL_TREE;
+}
+
+/* Expand an unreachable statement list.  This function skips all
+   statements preceding the first potentially reachable label and
+   then returns the label (or, in same cases, the statement after
+   one containing the label).  */
+static tree
+expand_unreachable_stmt (t, warn)
+     tree t;
+     int warn;
+{
+  int saved;
+
+  while (t && t != error_mark_node)
+    {
+      if (warn)
+       switch (TREE_CODE (t))
+         {
+         case BREAK_STMT:
+         case CONTINUE_STMT:
+         case EXPR_STMT:
+         case GOTO_STMT:
+         case IF_STMT:
+         case RETURN_STMT:
+           if (!STMT_LINENO_FOR_FN_P (t))
+             input_line = STMT_LINENO (t);
+           warning("will never be executed");
+           warn = false;
+           break;
+
+         default:
+           break;
+         }
+
+      switch (TREE_CODE (t))
+       {
+       case GOTO_STMT:
+       case CONTINUE_STMT:
+       case BREAK_STMT:
+         break;
+
+       case FILE_STMT:
+         input_filename = FILE_STMT_FILENAME (t);
+         break;
+
+       case RETURN_STMT:
+         if (find_reachable_label (RETURN_STMT_EXPR (t)) != NULL_TREE)
+           return t;
+         break;
+
+       case EXPR_STMT:
+         if (find_reachable_label (EXPR_STMT_EXPR (t)) != NULL_TREE)
+           return t;
+         break;
+
+       case IF_STMT:
+         if (expand_unreachable_if_stmt (t))
+           return TREE_CHAIN (t);
+         break;
+
+       case WHILE_STMT:
+         /* If the start of a while statement is unreachable, there is
+            no need to rotate the loop, instead the WHILE_STMT can be
+            expanded like a DO_STMT.  */
+         genrtl_do_stmt_1 (WHILE_COND (t), WHILE_BODY (t));
+         return TREE_CHAIN (t);
+
+       case COMPOUND_STMT:
+         {
+           tree n;
+           n = expand_unreachable_stmt (COMPOUND_BODY (t), warn);
+           if (n != NULL_TREE)
+             {
+               expand_stmt (n);
+               return TREE_CHAIN (t);
+             }
+           warn = false;
+           break;
+         }
+
+       case SCOPE_STMT:
+         saved = stmts_are_full_exprs_p ();
+         prep_stmt (t);
+         genrtl_scope_stmt (t);
+         current_stmt_tree ()->stmts_are_full_exprs_p = saved;
+         break;
+
+       default:
+         return t;
+       }
       t = TREE_CHAIN (t);
     }
+  return NULL_TREE;
 }
+