]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-inline.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / tree-inline.c
index 5396131e176b53cb7b25a9957013d16b3331bfe5..5e50e8013e2af3b1ab6f9b45f6421a8933f23dc2 100644 (file)
@@ -1116,7 +1116,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
          *tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1));
          TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
          TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
-         TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+         copy_warning (*tp, old);
          if (MR_DEPENDENCE_CLIQUE (old) != 0)
            {
              MR_DEPENDENCE_CLIQUE (*tp)
@@ -1375,7 +1375,7 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
          *tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1));
          TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
          TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
-         TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+         copy_warning (*tp, old);
          if (MR_DEPENDENCE_CLIQUE (old) != 0)
            {
              MR_DEPENDENCE_CLIQUE (*tp)
@@ -1458,7 +1458,8 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
                   || OMP_CLAUSE_CODE (*tp) == OMP_CLAUSE_DEPEND))
        {
          tree t = OMP_CLAUSE_DECL (*tp);
-         if (TREE_CODE (t) == TREE_LIST
+         if (t
+             && TREE_CODE (t) == TREE_LIST
              && TREE_PURPOSE (t)
              && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
            {
@@ -1525,6 +1526,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
          : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
     return NULL;
 
+  if (!is_gimple_debug (stmt)
+      && id->param_body_adjs
+      && id->param_body_adjs->m_dead_stmts.contains (stmt))
+    return NULL;
+
   /* Begin by recognizing trees that we'll completely rewrite for the
      inlining context.  Our output for these trees is completely
      different from our input (e.g. RETURN_EXPR is deleted and morphs
@@ -1652,6 +1658,18 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
          copy = gimple_build_omp_master (s1);
          break;
 
+       case GIMPLE_OMP_MASKED:
+         s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+         copy = gimple_build_omp_masked
+                  (s1, gimple_omp_masked_clauses (stmt));
+         break;
+
+       case GIMPLE_OMP_SCOPE:
+         s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+         copy = gimple_build_omp_scope
+                  (s1, gimple_omp_scope_clauses (stmt));
+         break;
+
        case GIMPLE_OMP_TASKGROUP:
          s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
          copy = gimple_build_omp_taskgroup
@@ -1789,10 +1807,15 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
 
       if (gimple_debug_bind_p (stmt))
        {
+         tree value;
+         if (id->param_body_adjs
+             && id->param_body_adjs->m_dead_stmts.contains (stmt))
+           value = NULL_TREE;
+         else
+           value = gimple_debug_bind_get_value (stmt);
          gdebug *copy
            = gimple_build_debug_bind (gimple_debug_bind_get_var (stmt),
-                                      gimple_debug_bind_get_value (stmt),
-                                      stmt);
+                                      value, stmt);
          if (id->reset_location)
            gimple_set_location (copy, input_location);
          id->debug_stmts.safe_push (copy);
@@ -1921,7 +1944,7 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
   if (id->param_body_adjs)
     {
       gimple_seq extra_stmts = NULL;
-      id->param_body_adjs->modify_gimple_stmt (&copy, &extra_stmts);
+      id->param_body_adjs->modify_gimple_stmt (&copy, &extra_stmts, stmt);
       if (!gimple_seq_empty_p (extra_stmts))
        {
          memset (&wi, 0, sizeof (wi));
@@ -2090,27 +2113,29 @@ copy_bb (copy_body_data *id, basic_block bb,
              tree p;
              gcall *new_call;
              vec<tree> argarray;
-             size_t nargs = gimple_call_num_args (id->call_stmt);
-             size_t n;
+             size_t nargs_caller = gimple_call_num_args (id->call_stmt);
+             size_t nargs = nargs_caller;
 
              for (p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
                nargs--;
 
              /* Create the new array of arguments.  */
-             n = nargs + gimple_call_num_args (call_stmt);
+             size_t nargs_callee = gimple_call_num_args (call_stmt);
+             size_t n = nargs + nargs_callee;
              argarray.create (n);
              argarray.safe_grow_cleared (n, true);
 
              /* Copy all the arguments before '...'  */
-             memcpy (argarray.address (),
-                     gimple_call_arg_ptr (call_stmt, 0),
-                     gimple_call_num_args (call_stmt) * sizeof (tree));
+             if (nargs_callee)
+               memcpy (argarray.address (),
+                       gimple_call_arg_ptr (call_stmt, 0),
+                       nargs_callee * sizeof (tree));
 
              /* Append the arguments passed in '...'  */
-             memcpy (argarray.address () + gimple_call_num_args (call_stmt),
-                     gimple_call_arg_ptr (id->call_stmt, 0)
-                     + (gimple_call_num_args (id->call_stmt) - nargs),
-                     nargs * sizeof (tree));
+             if (nargs)
+               memcpy (argarray.address () + nargs_callee,
+                       gimple_call_arg_ptr (id->call_stmt, 0)
+                       + (nargs_caller - nargs), nargs * sizeof (tree));
 
              new_call = gimple_build_call_vec (gimple_call_fn (call_stmt),
                                                argarray);
@@ -2672,7 +2697,9 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
       phi = si.phi ();
       res = PHI_RESULT (phi);
       new_res = res;
-      if (!virtual_operand_p (res))
+      if (!virtual_operand_p (res)
+         && (!id->param_body_adjs
+             || !id->param_body_adjs->m_dead_stmts.contains (phi)))
        {
          walk_tree (&new_res, copy_tree_body_r, id, NULL);
          if (EDGE_COUNT (new_bb->preds) == 0)
@@ -2853,7 +2880,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
                  gimple_set_location (stmt, UNKNOWN_LOCATION);
                }
              gsi_remove (&si, false);
-             gsi_insert_before (&dsi, stmt, GSI_SAME_STMT);
+             gsi_insert_before (&dsi, stmt, GSI_NEW_STMT);
              continue;
            }
 
@@ -2879,7 +2906,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
            new_stmt = as_a <gdebug *> (gimple_copy (stmt));
          else
            gcc_unreachable ();
-         gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
+         gsi_insert_before (&dsi, new_stmt, GSI_NEW_STMT);
          id->debug_stmts.safe_push (new_stmt);
          gsi_prev (&ssi);
        }
@@ -3257,13 +3284,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
 static void
 copy_debug_stmts (copy_body_data *id)
 {
-  size_t i;
-  gdebug *stmt;
-
   if (!id->debug_stmts.exists ())
     return;
 
-  FOR_EACH_VEC_ELT (id->debug_stmts, i, stmt)
+  for (gdebug *stmt : id->debug_stmts)
     copy_debug_stmt (stmt, id);
 
   id->debug_stmts.release ();
@@ -3386,7 +3410,7 @@ insert_init_stmt (copy_body_data *id, basic_block bb, gimple *init_stmt)
          && gimple_assign_rhs_class (init_stmt) == GIMPLE_UNARY_RHS)
        {
          tree rhs = build1 (gimple_assign_rhs_code (init_stmt),
-                            gimple_expr_type (init_stmt),
+                            TREE_TYPE (gimple_assign_lhs (init_stmt)),
                             gimple_assign_rhs1 (init_stmt));
          rhs = force_gimple_operand_gsi (&si, rhs, true, NULL_TREE, false,
                                          GSI_NEW_STMT);
@@ -3491,17 +3515,11 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
      automatically replaced by the VAR_DECL.  */
   insert_decl_map (id, p, var);
 
-  /* Even if P was TREE_READONLY, the new VAR should not be.
-     In the original code, we would have constructed a
-     temporary, and then the function body would have never
-     changed the value of P.  However, now, we will be
-     constructing VAR directly.  The constructor body may
-     change its value multiple times as it is being
-     constructed.  Therefore, it must not be TREE_READONLY;
-     the back-end assumes that TREE_READONLY variable is
-     assigned to only once.  */
-  if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
-    TREE_READONLY (var) = 0;
+  /* Even if P was TREE_READONLY, the new VAR should not be.  In the original
+     code, we would have constructed a temporary, and then the function body
+     would have never changed the value of P.  However, now, we will be
+     constructing VAR directly.  Therefore, it must not be TREE_READONLY.  */
+  TREE_READONLY (var) = 0;
 
   tree rhs = value;
   if (value
@@ -3775,7 +3793,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
 
   /* Do not have the rest of GCC warn about this variable as it should
      not be visible to the user.  */
-  TREE_NO_WARNING (var) = 1;
+  suppress_warning (var /* OPT_Wuninitialized? */);
 
   declare_inline_vars (id->block, var);
 
@@ -4025,17 +4043,10 @@ inline_forbidden_p (tree fndecl)
   wi.info = (void *) fndecl;
   wi.pset = &visited_nodes;
 
-  /* We cannot inline a function with a VLA typed argument or result since
-     we have no implementation materializing a variable of such type in
-     the caller.  */
-  if (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))
-      && !poly_int_tree_p (TYPE_SIZE (TREE_TYPE (TREE_TYPE (fndecl)))))
-    {
-      inline_forbidden_reason
-       = G_("function %q+F can never be inlined because "
-            "it has a VLA return argument");
-      return true;
-    }
+  /* We cannot inline a function with a variable-sized parameter because we
+     cannot materialize a temporary of such a type in the caller if need be.
+     Note that the return case is not symmetrical because we can guarantee
+     that a temporary is not needed by means of CALL_EXPR_RETURN_SLOT_OPT.  */
   for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
     if (!poly_int_tree_p (DECL_SIZE (parm)))
       {
@@ -4425,8 +4436,8 @@ estimate_num_insns (gimple *stmt, eni_weights *weights)
            /* Do not special case builtins where we see the body.
               This just confuse inliner.  */
            struct cgraph_node *node;
-           if (!(node = cgraph_node::get (decl))
-               || node->definition)
+           if ((node = cgraph_node::get (decl))
+               && node->definition)
              ;
            /* For buitins that are likely expanded to nothing or
               inlined do not account operand costs.  */
@@ -4545,6 +4556,8 @@ estimate_num_insns (gimple *stmt, eni_weights *weights)
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
+    case GIMPLE_OMP_SCOPE:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
@@ -4743,7 +4756,6 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
   use_operand_p use;
   gimple *simtenter_stmt = NULL;
   vec<tree> *simtvars_save;
-  clone_info *info;
 
   /* The gimplifier uses input_location in too many places, such as
      internal_get_tmp_var ().  */
@@ -5040,7 +5052,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
         initialized.  We do not want to issue a warning about that
         uninitialized variable.  */
       if (DECL_P (modify_dest))
-       TREE_NO_WARNING (modify_dest) = 1;
+       suppress_warning (modify_dest, OPT_Wuninitialized);
 
       if (gimple_call_return_slot_opt_p (call_stmt))
        {
@@ -5068,40 +5080,6 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
   /* Add local vars in this inlined callee to caller.  */
   add_local_variables (id->src_cfun, cfun, id);
 
-  info = clone_info::get (id->src_node);
-  if (info && info->performed_splits)
-    {
-      clone_info *dst_info = clone_info::get_create (id->dst_node);
-      /* Any calls from the inlined function will be turned into calls from the
-        function we inline into.  We must preserve notes about how to split
-        parameters such calls should be redirected/updated.  */
-      unsigned len = vec_safe_length (info->performed_splits);
-      for (unsigned i = 0; i < len; i++)
-       {
-         ipa_param_performed_split ps
-           = (*info->performed_splits)[i];
-         ps.dummy_decl = remap_decl (ps.dummy_decl, id);
-         vec_safe_push (dst_info->performed_splits, ps);
-       }
-
-      if (flag_checking)
-       {
-         len = vec_safe_length (dst_info->performed_splits);
-         for (unsigned i = 0; i < len; i++)
-           {
-             ipa_param_performed_split *ps1
-               = &(*dst_info->performed_splits)[i];
-             for (unsigned j = i + 1; j < len; j++)
-               {
-                 ipa_param_performed_split *ps2
-                   = &(*dst_info->performed_splits)[j];
-                 gcc_assert (ps1->dummy_decl != ps2->dummy_decl
-                             || ps1->unit_offset != ps2->unit_offset);
-               }
-           }
-       }
-    }
-
   if (dump_enabled_p ())
     {
       char buf[128];
@@ -6125,23 +6103,10 @@ tree_versionable_function_p (tree fndecl)
 static void
 update_clone_info (copy_body_data * id)
 {
-  clone_info *dst_info = clone_info::get (id->dst_node);
-  vec<ipa_param_performed_split, va_gc> *cur_performed_splits
-    = dst_info ? dst_info->performed_splits : NULL;
-  if (cur_performed_splits)
-    {
-      unsigned len = cur_performed_splits->length ();
-      for (unsigned i = 0; i < len; i++)
-       {
-         ipa_param_performed_split *ps = &(*cur_performed_splits)[i];
-         ps->dummy_decl = remap_decl (ps->dummy_decl, id);
-       }
-    }
-
-  struct cgraph_node *node;
-  if (!id->dst_node->clones)
+  struct cgraph_node *this_node = id->dst_node;
+  if (!this_node->clones)
     return;
-  for (node = id->dst_node->clones; node != id->dst_node;)
+  for (cgraph_node *node = this_node->clones; node != this_node;)
     {
       /* First update replace maps to match the new body.  */
       clone_info *info = clone_info::get (node);
@@ -6155,53 +6120,6 @@ update_clone_info (copy_body_data * id)
              walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL);
            }
        }
-      if (info && info->performed_splits)
-       {
-         unsigned len = vec_safe_length (info->performed_splits);
-         for (unsigned i = 0; i < len; i++)
-           {
-             ipa_param_performed_split *ps
-               = &(*info->performed_splits)[i];
-             ps->dummy_decl = remap_decl (ps->dummy_decl, id);
-           }
-       }
-      if (unsigned len = vec_safe_length (cur_performed_splits))
-       {
-         /* We do not want to add current performed splits when we are saving
-            a copy of function body for later during inlining, that would just
-            duplicate all entries.  So let's have a look whether anything
-            referring to the first dummy_decl is present.  */
-         if (!info)
-           info = clone_info::get_create (node);
-         unsigned dst_len = vec_safe_length (info->performed_splits);
-         ipa_param_performed_split *first = &(*cur_performed_splits)[0];
-         for (unsigned i = 0; i < dst_len; i++)
-           if ((*info->performed_splits)[i].dummy_decl
-               == first->dummy_decl)
-             {
-               len = 0;
-               break;
-             }
-
-         for (unsigned i = 0; i < len; i++)
-           vec_safe_push (info->performed_splits,
-                          (*cur_performed_splits)[i]);
-         if (flag_checking)
-           {
-             for (unsigned i = 0; i < dst_len; i++)
-               {
-                 ipa_param_performed_split *ps1
-                   = &(*info->performed_splits)[i];
-                 for (unsigned j = i + 1; j < dst_len; j++)
-                   {
-                     ipa_param_performed_split *ps2
-                       = &(*info->performed_splits)[j];
-                     gcc_assert (ps1->dummy_decl != ps2->dummy_decl
-                                 || ps1->unit_offset != ps2->unit_offset);
-                   }
-               }
-           }
-       }
 
       if (node->clones)
        node = node->clones;