]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/function.c
Update copyright years.
[thirdparty/gcc.git] / gcc / function.c
index d6d38b92a756915e9127ff82d349dcbbacf1f559..d8008f60422e5b433ab63cc3cef0c00b537dd0b9 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GCC.
-   Copyright (C) 1987-2019 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -79,6 +79,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h"
 #include "gimple.h"
 #include "options.h"
+#include "function-abi.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
@@ -2119,10 +2120,17 @@ aggregate_value_p (const_tree exp, const_tree fntype)
   if (!REG_P (reg))
     return 0;
 
+  /* Use the default ABI if the type of the function isn't known.
+     The scheme for handling interoperability between different ABIs
+     requires us to be able to tell when we're calling a function with
+     a nondefault ABI.  */
+  const predefined_function_abi &abi = (fntype
+                                       ? fntype_abi (fntype)
+                                       : default_function_abi);
   regno = REGNO (reg);
   nregs = hard_regno_nregs (regno, TYPE_MODE (type));
   for (i = 0; i < nregs; i++)
-    if (! call_used_regs[regno + i])
+    if (!fixed_regs[regno + i] && !abi.clobbers_full_reg_p (regno + i))
       return 1;
 
   return 0;
@@ -2271,7 +2279,6 @@ struct assign_parm_data_one
   machine_mode passed_mode;
   struct locate_and_pad_arg_data locate;
   int partial;
-  BOOL_BITFIELD passed_pointer : 1;
 };
 
 /* A subroutine of assign_parms.  Initialize ALL.  */
@@ -2444,8 +2451,7 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
   /* If the parm is to be passed as a transparent union or record, use the
      type of the first field for the tests below.  We have already verified
      that the modes are the same.  */
-  if ((TREE_CODE (data->arg.type) == UNION_TYPE
-       || TREE_CODE (data->arg.type) == RECORD_TYPE)
+  if (RECORD_OR_UNION_TYPE_P (data->arg.type)
       && TYPE_TRANSPARENT_AGGR (data->arg.type))
     data->arg.type = TREE_TYPE (first_field (data->arg.type));
 
@@ -2453,7 +2459,6 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm,
   if (apply_pass_by_reference_rules (&all->args_so_far_v, data->arg))
     {
       data->nominal_type = data->arg.type;
-      data->passed_pointer = true;
       data->passed_mode = data->nominal_mode = data->arg.mode;
     }
 
@@ -2653,7 +2658,7 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
     stack_parm = gen_rtx_PLUS (Pmode, stack_parm, offset_rtx);
   stack_parm = gen_rtx_MEM (data->arg.mode, stack_parm);
 
-  if (!data->passed_pointer)
+  if (!data->arg.pass_by_reference)
     {
       set_mem_attributes (stack_parm, parm, 1);
       /* set_mem_attributes could set MEM_SIZE to the passed mode's size,
@@ -2689,7 +2694,7 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
         stack slot boundary, take advantage of that excess alignment.
         Don't make any assumptions if STACK_POINTER_OFFSET is in use.  */
       if (poly_int_rtx_p (offset_rtx, &offset)
-         && STACK_POINTER_OFFSET == 0)
+         && known_eq (STACK_POINTER_OFFSET, 0))
        {
          unsigned int offset_align = known_alignment (offset) * BITS_PER_UNIT;
          if (offset_align == 0 || offset_align > STACK_BOUNDARY)
@@ -2809,8 +2814,10 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
      stack slot, if we need one.  */
   if (stack_parm
       && ((GET_MODE_ALIGNMENT (data->nominal_mode) > MEM_ALIGN (stack_parm)
-          && targetm.slow_unaligned_access (data->nominal_mode,
-                                            MEM_ALIGN (stack_parm)))
+          && ((optab_handler (movmisalign_optab, data->nominal_mode)
+               != CODE_FOR_nothing)
+              || targetm.slow_unaligned_access (data->nominal_mode,
+                                                MEM_ALIGN (stack_parm))))
          || (data->nominal_type
              && TYPE_ALIGN (data->nominal_type) > MEM_ALIGN (stack_parm)
              && MEM_ALIGN (stack_parm) < PREFERRED_STACK_BOUNDARY)))
@@ -2827,7 +2834,7 @@ assign_parm_adjust_stack_rtl (struct assign_parm_data_one *data)
      pointers in their passed stack slots.  */
   else if (crtl->stack_protect_guard
           && (flag_stack_protect == 2
-              || data->passed_pointer
+              || data->arg.pass_by_reference
               || POINTER_TYPE_P (data->nominal_type)))
     stack_parm = NULL;
 
@@ -3080,7 +3087,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
        move_block_from_reg (REGNO (entry_parm), mem,
                             size_stored / UNITS_PER_WORD);
     }
-  else if (data->stack_parm == 0)
+  else if (data->stack_parm == 0 && !TYPE_EMPTY_P (data->arg.type))
     {
       push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn);
       emit_block_move (stack_parm, data->entry_parm, GEN_INT (size),
@@ -3140,7 +3147,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 
   /* If this was an item that we received a pointer to,
      set rtl appropriately.  */
-  if (data->passed_pointer)
+  if (data->arg.pass_by_reference)
     {
       rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->arg.type)), parmreg);
       set_mem_attributes (rtl, parm, 1);
@@ -3228,8 +3235,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
          for (insn = insns; insn && moved; insn = NEXT_INSN (insn))
            {
              if (INSN_P (insn))
-               note_stores (PATTERN (insn), record_hard_reg_sets,
-                            &hardregs);
+               note_stores (insn, record_hard_reg_sets, &hardregs);
              if (!hard_reg_set_empty_p (hardregs))
                moved = false;
            }
@@ -3310,7 +3316,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 
   /* If we were passed a pointer but the actual value can safely live
      in a register, retrieve it and use it directly.  */
-  if (data->passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
+  if (data->arg.pass_by_reference && TYPE_MODE (TREE_TYPE (parm)) != BLKmode)
     {
       /* We can't use nominal_mode, because it will have been set to
         Pmode above.  We must use the actual mode of the parm.  */
@@ -3463,17 +3469,28 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
          int align = STACK_SLOT_ALIGNMENT (data->arg.type,
                                            GET_MODE (data->entry_parm),
                                            TYPE_ALIGN (data->arg.type));
+         if (align < (int)GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm))
+             && ((optab_handler (movmisalign_optab,
+                                 GET_MODE (data->entry_parm))
+                  != CODE_FOR_nothing)
+                 || targetm.slow_unaligned_access (GET_MODE (data->entry_parm),
+                                                   align)))
+           align = GET_MODE_ALIGNMENT (GET_MODE (data->entry_parm));
          data->stack_parm
            = assign_stack_local (GET_MODE (data->entry_parm),
                                  GET_MODE_SIZE (GET_MODE (data->entry_parm)),
                                  align);
+         align = MEM_ALIGN (data->stack_parm);
          set_mem_attributes (data->stack_parm, parm, 1);
+         set_mem_align (data->stack_parm, align);
        }
 
       dest = validize_mem (copy_rtx (data->stack_parm));
       src = validize_mem (copy_rtx (data->entry_parm));
 
-      if (MEM_P (src))
+      if (TYPE_EMPTY_P (data->arg.type))
+       /* Empty types don't really need to be copied.  */;
+      else if (MEM_P (src))
        {
          /* Use a block move to handle potentially misaligned entry_parm.  */
          if (!to_conversion)
@@ -3628,9 +3645,19 @@ assign_parms (tree fndecl)
        {
          assign_parm_find_stack_rtl (parm, &data);
          assign_parm_adjust_entry_rtl (&data);
+         /* For arguments that occupy no space in the parameter
+            passing area, have non-zero size and have address taken,
+            force creation of a stack slot so that they have distinct
+            address from other parameters.  */
+         if (TYPE_EMPTY_P (data.arg.type)
+             && TREE_ADDRESSABLE (parm)
+             && data.entry_parm == data.stack_parm
+             && MEM_P (data.entry_parm)
+             && int_size_in_bytes (data.arg.type))
+           data.stack_parm = NULL_RTX;
        }
       /* Record permanently how this parm was passed.  */
-      if (data.passed_pointer)
+      if (data.arg.pass_by_reference)
        {
          rtx incoming_rtl
            = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data.arg.type)),
@@ -3644,7 +3671,7 @@ assign_parms (tree fndecl)
 
       if (assign_parm_setup_block_p (&data))
        assign_parm_setup_block (&all, parm, &data);
-      else if (data.passed_pointer || use_register_for_decl (parm))
+      else if (data.arg.pass_by_reference || use_register_for_decl (parm))
        assign_parm_setup_reg (&all, parm, &data);
       else
        assign_parm_setup_stack (&all, parm, &data);
@@ -3855,7 +3882,7 @@ gimplify_parameters (gimple_seq *cleanup)
          gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts);
        }
 
-      if (data.passed_pointer)
+      if (data.arg.pass_by_reference)
        {
          tree type = TREE_TYPE (data.arg.type);
          function_arg_info orig_arg (type, data.arg.named);
@@ -3885,9 +3912,8 @@ gimplify_parameters (gimple_seq *cleanup)
                  if (!is_gimple_reg (local)
                      && flag_stack_reuse != SR_NONE)
                    {
-                     tree clobber = build_constructor (type, NULL);
+                     tree clobber = build_clobber (type);
                      gimple *clobber_stmt;
-                     TREE_THIS_VOLATILE (clobber) = 1;
                      clobber_stmt = gimple_build_assign (local, clobber);
                      gimple_seq_add_stmt (cleanup, clobber_stmt);
                    }
@@ -4711,6 +4737,16 @@ get_last_funcdef_no (void)
   return funcdef_no;
 }
 
+/* Allocate and initialize the stack usage info data structure for the
+   current function.  */
+static void
+allocate_stack_usage_info (void)
+{
+  gcc_assert (!cfun->su);
+  cfun->su = ggc_cleared_alloc<stack_usage> ();
+  cfun->su->static_stack_size = -1;
+}
+
 /* Allocate a function structure for FNDECL and set its contents
    to the defaults.  Set cfun to the newly-allocated object.
    Some of the helper functions invoked during initialization assume
@@ -4788,6 +4824,9 @@ allocate_struct_function (tree fndecl, bool abstract_p)
 
       if (!profile_flag && !flag_instrument_function_entry_exit)
        DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) = 1;
+
+      if (flag_callgraph_info)
+       allocate_stack_usage_info ();
     }
 
   /* Don't enable begin stmt markers if var-tracking at assignments is
@@ -4820,17 +4859,20 @@ static void
 prepare_function_start (void)
 {
   gcc_assert (!get_last_insn ());
+
+  if (in_dummy_function)
+    crtl->abi = &default_function_abi;
+  else
+    crtl->abi = &fndecl_abi (cfun->decl).base_abi ();
+
   init_temp_slots ();
   init_emit ();
   init_varasm_status ();
   init_expr ();
   default_rtl_profile ();
 
-  if (flag_stack_usage_info)
-    {
-      cfun->su = ggc_cleared_alloc<stack_usage> ();
-      cfun->su->static_stack_size = -1;
-    }
+  if (flag_stack_usage_info && !flag_callgraph_info)
+    allocate_stack_usage_info ();
 
   cse_not_expected = ! optimize;
 
@@ -6353,12 +6395,46 @@ rest_of_handle_thread_prologue_and_epilogue (void)
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
-  if (flag_stack_usage_info)
+  if (flag_stack_usage_info || flag_callgraph_info)
     output_stack_usage ();
 
   return 0;
 }
 
+/* Record a final call to CALLEE at LOCATION.  */
+
+void
+record_final_call (tree callee, location_t location)
+{
+  struct callinfo_callee datum = { location, callee };
+  vec_safe_push (cfun->su->callees, datum);
+}
+
+/* Record a dynamic allocation made for DECL_OR_EXP.  */
+
+void
+record_dynamic_alloc (tree decl_or_exp)
+{
+  struct callinfo_dalloc datum;
+
+  if (DECL_P (decl_or_exp))
+    {
+      datum.location = DECL_SOURCE_LOCATION (decl_or_exp);
+      const char *name = lang_hooks.decl_printable_name (decl_or_exp, 2);
+      const char *dot = strrchr (name, '.');
+      if (dot)
+       name = dot + 1;
+      datum.name = ggc_strdup (name);
+    }
+  else
+    {
+      datum.location = EXPR_LOCATION (decl_or_exp);
+      datum.name = NULL;
+    }
+
+  vec_safe_push (cfun->su->dallocs, datum);
+}
+
 namespace {
 
 const pass_data pass_data_thread_prologue_and_epilogue =