]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/gimplify.c
Merge in trunk.
[thirdparty/gcc.git] / gcc / gimplify.c
index 21861d244eafcf904abfb38a54a124f9c61dfd3a..21dc7cad156918de572526e58f8cd98081247892 100644 (file)
@@ -30,8 +30,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-inline.h"
 #include "tree-pretty-print.h"
 #include "langhooks.h"
-#include "tree-ssa.h"
+#include "bitmap.h"
+#include "gimple-ssa.h"
 #include "cgraph.h"
+#include "tree-cfg.h"
+#include "tree-ssanames.h"
+#include "tree-ssa.h"
 #include "timevar.h"
 #include "hashtab.h"
 #include "flags.h"
@@ -44,10 +48,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "vec.h"
 #include "omp-low.h"
 #include "gimple-low.h"
+#include "cilk.h"
 
 #include "langhooks-def.h"     /* FIXME: for lhd_set_decl_assembler_name */
 #include "tree-pass.h"         /* FIXME: only for PROP_gimple_any */
-#include "tree-mudflap.h"
 #include "expr.h"
 #include "tm_p.h"
 
@@ -974,7 +978,7 @@ unshare_body (tree fndecl)
 
   if (cgn)
     for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
-      unshare_body (cgn->symbol.decl);
+      unshare_body (cgn->decl);
 }
 
 /* Callback for walk_tree to unmark the visited trees rooted at *TP.
@@ -1017,7 +1021,7 @@ unvisit_body (tree fndecl)
 
   if (cgn)
     for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
-      unvisit_body (cgn->symbol.decl);
+      unvisit_body (cgn->decl);
 }
 
 /* Unconditionally make an unshared copy of EXPR.  This is used when using
@@ -1232,8 +1236,7 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
       gimple stack_restore;
 
       /* Save stack on entry and restore it on exit.  Add a try_finally
-        block to achieve this.  Note that mudflap depends on the
-        format of the emitted code: see mx_register_decls().  */
+        block to achieve this.  */
       build_stack_save_restore (&stack_save, &stack_restore);
 
       gimplify_seq_add_stmt (&cleanup, stack_restore);
@@ -1307,6 +1310,15 @@ gimplify_return_expr (tree stmt, gimple_seq *pre_p)
   if (ret_expr == error_mark_node)
     return GS_ERROR;
 
+  /* Implicit _Cilk_sync must be inserted right before any return statement 
+     if there is a _Cilk_spawn in the function.  If the user has provided a 
+     _Cilk_sync, the optimizer should remove this duplicate one.  */
+  if (fn_contains_cilk_spawn_p (cfun))
+    {
+      tree impl_sync = build0 (CILK_SYNC_STMT, void_type_node);
+      gimplify_and_add (impl_sync, pre_p);
+    }
+
   if (!ret_expr
       || TREE_CODE (ret_expr) == RESULT_DECL
       || ret_expr == error_mark_node)
@@ -1391,8 +1403,7 @@ static void
 gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 {
   /* This is a variable-sized decl.  Simplify its size and mark it
-     for deferred expansion.  Note that mudflap depends on the format
-     of the emitted code: see mx_register_decls().  */
+     for deferred expansion.  */
   tree t, addr, ptr_type;
 
   gimplify_one_sizepos (&DECL_SIZE (decl), seq_p);
@@ -2127,7 +2138,6 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                        fallback_t fallback)
 {
   tree *p;
-  vec<tree> expr_stack;
   enum gimplify_status ret = GS_ALL_DONE, tret;
   int i;
   location_t loc = EXPR_LOCATION (*expr_p);
@@ -2135,7 +2145,7 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
   /* Create a stack of the subexpressions so later we can walk them in
      order from inner to outer.  */
-  expr_stack.create (10);
+  stack_vec<tree, 10> expr_stack;
 
   /* We can handle anything that get_inner_reference can deal with.  */
   for (p = expr_p; ; p = &TREE_OPERAND (*p, 0))
@@ -2493,6 +2503,12 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
   if (! EXPR_HAS_LOCATION (*expr_p))
     SET_EXPR_LOCATION (*expr_p, input_location);
 
+  if (fn_contains_cilk_spawn_p (cfun)
+      && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p) 
+      && !seen_error ())
+    return (enum gimplify_status) 
+      lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p, NULL);
+
   /* This may be a call to a builtin function.
 
      Builtin function calls may be transformed into different
@@ -3068,6 +3084,17 @@ gimple_boolify (tree expr)
        TREE_TYPE (expr) = boolean_type_node;
       return expr;
 
+    case ANNOTATE_EXPR:
+      if ((enum annot_expr_kind) tree_to_uhwi (TREE_OPERAND (expr, 1))
+         == annot_expr_ivdep_kind)
+       {
+         TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+         if (TREE_CODE (type) != BOOLEAN_TYPE)
+           TREE_TYPE (expr) = boolean_type_node;
+         return expr;
+       }
+      /* FALLTHRU */
+
     default:
       if (COMPARISON_CLASS_P (expr))
        {
@@ -4048,10 +4075,19 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
           individual element initialization.  Also don't do this for small
           all-zero initializers (which aren't big enough to merit
           clearing), and don't try to make bitwise copies of
-          TREE_ADDRESSABLE types.  */
+          TREE_ADDRESSABLE types.
+
+          We cannot apply such transformation when compiling chkp static
+          initializer because creation of initializer image in the memory
+          will require static initialization of bounds for it.  It should
+          result in another gimplification of similar initializer and we
+          may fall into infinite loop.  */
        if (valid_const_initializer
            && !(cleared || num_nonzero_elements == 0)
-           && !TREE_ADDRESSABLE (type))
+           && !TREE_ADDRESSABLE (type)
+           && (!current_function_decl
+               || !lookup_attribute ("chkp ctor",
+                                     DECL_ATTRIBUTES (current_function_decl))))
          {
            HOST_WIDE_INT size = int_size_in_bytes (type);
            unsigned int align;
@@ -4698,6 +4734,12 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 
   gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
              || TREE_CODE (*expr_p) == INIT_EXPR);
+  
+  if (fn_contains_cilk_spawn_p (cfun)
+      && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p) 
+      && !seen_error ())
+    return (enum gimplify_status) 
+      lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p, post_p);
 
   /* Trying to simplify a clobber using normal logic doesn't work,
      so handle it here.  */
@@ -7644,6 +7686,19 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            }
          break;
 
+       case CILK_SPAWN_STMT:
+         gcc_assert 
+           (fn_contains_cilk_spawn_p (cfun) 
+            && lang_hooks.cilkplus.cilk_detect_spawn_and_unwrap (expr_p));
+         if (!seen_error ())
+           {
+             ret = (enum gimplify_status)
+               lang_hooks.cilkplus.gimplify_cilk_spawn (expr_p, pre_p,
+                                                        post_p);
+             break;
+           }
+         /* If errors are seen, then just process it as a CALL_EXPR.  */
+
        case CALL_EXPR:
          ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
 
@@ -7723,6 +7778,21 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          ret = gimplify_addr_expr (expr_p, pre_p, post_p);
          break;
 
+       case ANNOTATE_EXPR:
+         {
+           tree cond = TREE_OPERAND (*expr_p, 0);
+           tree id = TREE_OPERAND (*expr_p, 1);
+           tree tmp = create_tmp_var_raw (TREE_TYPE(cond), NULL);
+           gimplify_arg (&cond, pre_p, EXPR_LOCATION (*expr_p));
+           gimple call = gimple_build_call_internal (IFN_ANNOTATE, 2,
+                                                     cond, id);
+           gimple_call_set_lhs (call, tmp);
+           gimplify_seq_add_stmt (pre_p, call);
+           *expr_p = tmp;
+           ret = GS_ALL_DONE;
+           break;
+         }
+
        case VA_ARG_EXPR:
          ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
          break;
@@ -8264,6 +8334,22 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
            break;
          }
 
+       case CILK_SYNC_STMT:
+         {
+           if (!fn_contains_cilk_spawn_p (cfun))
+             {
+               error_at (EXPR_LOCATION (*expr_p),
+                         "expected %<_Cilk_spawn%> before %<_Cilk_sync%>");
+               ret = GS_ERROR;
+             }
+           else
+             {
+               gimplify_cilk_sync (expr_p, pre_p);
+               ret = GS_ALL_DONE;
+             }
+           break;
+         }
+       
        default:
          switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
            {
@@ -9224,118 +9310,107 @@ force_gimple_operand_gsi (gimple_stmt_iterator *gsi, tree expr,
                                     var, before, m);
 }
 
-#ifndef PAD_VARARGS_DOWN
-#define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
-#endif
+/* Return a dummy expression of type TYPE in order to keep going after an
+   error.  */
 
-/* Build an indirect-ref expression over the given TREE, which represents a
-   piece of a va_arg() expansion.  */
-tree
-build_va_arg_indirect_ref (tree addr)
+static tree
+dummy_object (tree type)
 {
-  addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
-
-  if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF.  */
-    mf_mark (addr);
-
-  return addr;
+  tree t = build_int_cst (build_pointer_type (type), 0);
+  return build2 (MEM_REF, type, t, t);
 }
 
-/* The "standard" implementation of va_arg: read the value from the
-   current (padded) address and increment by the (padded) size.  */
+/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
+   builtin function, but a very special sort of operator.  */
 
-tree
-std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
-                         gimple_seq *post_p)
-{
-  tree addr, t, type_size, rounded_size, valist_tmp;
-  unsigned HOST_WIDE_INT align, boundary;
-  bool indirect;
-
-#ifdef ARGS_GROW_DOWNWARD
-  /* All of the alignment and movement below is for args-grow-up machines.
-     As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
-     implement their own specialized gimplify_va_arg_expr routines.  */
-  gcc_unreachable ();
-#endif
-
-  indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
-  if (indirect)
-    type = build_pointer_type (type);
+enum gimplify_status
+gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
+{
+  tree promoted_type, have_va_type;
+  tree valist = TREE_OPERAND (*expr_p, 0);
+  tree type = TREE_TYPE (*expr_p);
+  tree t;
+  location_t loc = EXPR_LOCATION (*expr_p);
 
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  boundary = targetm.calls.function_arg_boundary (TYPE_MODE (type), type);
+  /* Verify that valist is of the proper type.  */
+  have_va_type = TREE_TYPE (valist);
+  if (have_va_type == error_mark_node)
+    return GS_ERROR;
+  have_va_type = targetm.canonical_va_list_type (have_va_type);
 
-  /* When we align parameter on stack for caller, if the parameter
-     alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
-     aligned at MAX_SUPPORTED_STACK_ALIGNMENT.  We will match callee
-     here with caller.  */
-  if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
-    boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+  if (have_va_type == NULL_TREE)
+    {
+      error_at (loc, "first argument to %<va_arg%> not of type %<va_list%>");
+      return GS_ERROR;
+    }
 
-  boundary /= BITS_PER_UNIT;
+  /* Generate a diagnostic for requesting data of a type that cannot
+     be passed through `...' due to type promotion at the call site.  */
+  if ((promoted_type = lang_hooks.types.type_promotes_to (type))
+          != type)
+    {
+      static bool gave_help;
+      bool warned;
 
-  /* Hoist the valist value into a temporary for the moment.  */
-  valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
+      /* Unfortunately, this is merely undefined, rather than a constraint
+        violation, so we cannot make this an error.  If this call is never
+        executed, the program is still strictly conforming.  */
+      warned = warning_at (loc, 0,
+                          "%qT is promoted to %qT when passed through %<...%>",
+                          type, promoted_type);
+      if (!gave_help && warned)
+       {
+         gave_help = true;
+         inform (loc, "(so you should pass %qT not %qT to %<va_arg%>)",
+                 promoted_type, type);
+       }
 
-  /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
-     requires greater alignment, we must perform dynamic alignment.  */
-  if (boundary > align
-      && !integer_zerop (TYPE_SIZE (type)))
-    {
-      t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
+      /* We can, however, treat "undefined" any way we please.
+        Call abort to encourage the user to fix the program.  */
+      if (warned)
+       inform (loc, "if this code is reached, the program will abort");
+      /* Before the abort, allow the evaluation of the va_list
+        expression to exit or longjmp.  */
+      gimplify_and_add (valist, pre_p);
+      t = build_call_expr_loc (loc,
+                              builtin_decl_implicit (BUILT_IN_TRAP), 0);
       gimplify_and_add (t, pre_p);
 
-      t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
-                              valist_tmp,
-                              build_int_cst (TREE_TYPE (valist), -boundary)));
-      gimplify_and_add (t, pre_p);
+      /* This is dead code, but go ahead and finish so that the
+        mode of the result comes out right.  */
+      *expr_p = dummy_object (type);
+      return GS_ALL_DONE;
     }
   else
-    boundary = align;
-
-  /* If the actual alignment is less than the alignment of the type,
-     adjust the type accordingly so that we don't assume strict alignment
-     when dereferencing the pointer.  */
-  boundary *= BITS_PER_UNIT;
-  if (boundary < TYPE_ALIGN (type))
     {
-      type = build_variant_type_copy (type);
-      TYPE_ALIGN (type) = boundary;
-    }
+      /* Make it easier for the backends by protecting the valist argument
+        from multiple evaluations.  */
+      if (TREE_CODE (have_va_type) == ARRAY_TYPE)
+       {
+         /* For this case, the backends will be expecting a pointer to
+            TREE_TYPE (abi), but it's possible we've
+            actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
+            So fix it.  */
+         if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
+           {
+             tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
+             valist = fold_convert_loc (loc, p1,
+                                        build_fold_addr_expr_loc (loc, valist));
+           }
 
-  /* Compute the rounded size of the type.  */
-  type_size = size_in_bytes (type);
-  rounded_size = round_up (type_size, align);
+         gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
+       }
+      else
+       gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
 
-  /* Reduce rounded_size so it's sharable with the postqueue.  */
-  gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
+      if (!targetm.gimplify_va_arg_expr)
+       /* FIXME: Once most targets are converted we should merely
+          assert this is non-null.  */
+       return GS_ALL_DONE;
 
-  /* Get AP.  */
-  addr = valist_tmp;
-  if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
-    {
-      /* Small args are padded downward.  */
-      t = fold_build2_loc (input_location, GT_EXPR, sizetype,
-                      rounded_size, size_int (align));
-      t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
-                      size_binop (MINUS_EXPR, rounded_size, type_size));
-      addr = fold_build_pointer_plus (addr, t);
+      *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
+      return GS_OK;
     }
-
-  /* Compute new value for AP.  */
-  t = fold_build_pointer_plus (valist_tmp, rounded_size);
-  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
-  gimplify_and_add (t, pre_p);
-
-  addr = fold_convert (build_pointer_type (type), addr);
-
-  if (indirect)
-    addr = build_va_arg_indirect_ref (addr);
-
-  return build_va_arg_indirect_ref (addr);
 }
 
 #include "gt-gimplify.h"