]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/function.cc
function: Change return type of predicate function from int to bool
[thirdparty/gcc.git] / gcc / function.cc
index e1d2565f8d9254a21d42b04736c77456c3ee0519..6a79a8290f67e8f2150f0e40fcd20c4bb9911423 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GCC.
-   Copyright (C) 1987-2022 Free Software Foundation, Inc.
+   Copyright (C) 1987-2023 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -578,8 +578,8 @@ public:
   tree type;
   /* The alignment (in bits) of the slot.  */
   unsigned int align;
-  /* Nonzero if this temporary is currently in use.  */
-  char in_use;
+  /* True if this temporary is currently in use.  */
+  bool in_use;
   /* Nesting level at which this slot is being used.  */
   int level;
   /* The offset of the slot from the frame_pointer, including extra space
@@ -674,7 +674,7 @@ make_slot_available (class temp_slot *temp)
 {
   cut_slot_from_list (temp, temp_slots_at_level (temp->level));
   insert_slot_to_list (temp, &avail_temp_slots);
-  temp->in_use = 0;
+  temp->in_use = false;
   temp->level = -1;
   n_temp_slots_in_use--;
 }
@@ -848,7 +848,7 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64 size, tree type)
          if (known_ge (best_p->size - rounded_size, alignment))
            {
              p = ggc_alloc<temp_slot> ();
-             p->in_use = 0;
+             p->in_use = false;
              p->size = best_p->size - rounded_size;
              p->base_offset = best_p->base_offset + rounded_size;
              p->full_size = best_p->full_size - rounded_size;
@@ -918,7 +918,7 @@ assign_stack_temp_for_type (machine_mode mode, poly_int64 size, tree type)
     }
 
   p = selected;
-  p->in_use = 1;
+  p->in_use = true;
   p->type = type;
   p->level = temp_slot_level;
   n_temp_slots_in_use++;
@@ -1340,7 +1340,7 @@ has_hard_reg_initial_val (machine_mode mode, unsigned int regno)
   return NULL_RTX;
 }
 
-unsigned int
+void
 emit_initial_value_sets (void)
 {
   struct initial_value_struct *ivs = crtl->hard_reg_initial_vals;
@@ -1348,7 +1348,7 @@ emit_initial_value_sets (void)
   rtx_insn *seq;
 
   if (ivs == 0)
-    return 0;
+    return;
 
   start_sequence ();
   for (i = 0; i < ivs->num_entries; i++)
@@ -1357,7 +1357,6 @@ emit_initial_value_sets (void)
   end_sequence ();
 
   emit_insn_at_entry (seq);
-  return 0;
 }
 
 /* Return the hardreg-pseudoreg initial values pair entry I and
@@ -1535,7 +1534,7 @@ instantiate_virtual_regs_in_rtx (rtx *loc)
 /* A subroutine of instantiate_virtual_regs_in_insn.  Return true if X
    matches the predicate for insn CODE operand OPERAND.  */
 
-static int
+static bool
 safe_insn_predicate (int code, int operand, rtx x)
 {
   return code < 0 || insn_operand_matches ((enum insn_code) code, operand, x);
@@ -1838,8 +1837,7 @@ instantiate_decl_rtl (rtx x)
   addr = XEXP (x, 0);
   if (CONSTANT_P (addr)
       || (REG_P (addr)
-         && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
-             || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
+         && !VIRTUAL_REGISTER_P (addr)))
     return;
 
   instantiate_virtual_regs_in_rtx (&XEXP (x, 0));
@@ -1948,7 +1946,7 @@ instantiate_decls (tree fndecl)
 /* Pass through the INSNS of function FNDECL and convert virtual register
    references to hard register references.  */
 
-static unsigned int
+static void
 instantiate_virtual_regs (void)
 {
   rtx_insn *insn;
@@ -2002,8 +2000,6 @@ instantiate_virtual_regs (void)
   /* Indicate that, from now on, assign_stack_local should use
      frame_pointer_rtx.  */
   virtuals_instantiated = 1;
-
-  return 0;
 }
 
 namespace {
@@ -2029,9 +2025,10 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual unsigned int execute (function *)
+  unsigned int execute (function *) final override
     {
-      return instantiate_virtual_regs ();
+      instantiate_virtual_regs ();
+      return 0;
     }
 
 }; // class pass_instantiate_virtual_regs
@@ -2045,12 +2042,12 @@ make_pass_instantiate_virtual_regs (gcc::context *ctxt)
 }
 
 \f
-/* Return 1 if EXP is an aggregate type (or a value with aggregate type).
+/* Return true if EXP is an aggregate type (or a value with aggregate type).
    This means a type for which function calls must pass an address to the
    function or get an address back from the function.
    EXP may be a type node or an expression (whose type is tested).  */
 
-int
+bool
 aggregate_value_p (const_tree exp, const_tree fntype)
 {
   const_tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp);
@@ -2070,7 +2067,7 @@ aggregate_value_p (const_tree exp, const_tree fntype)
          else
            /* For internal functions, assume nothing needs to be
               returned in memory.  */
-           return 0;
+           return false;
        }
        break;
       case FUNCTION_DECL:
@@ -2088,7 +2085,10 @@ aggregate_value_p (const_tree exp, const_tree fntype)
       }
 
   if (VOID_TYPE_P (type))
-    return 0;
+    return false;
+
+  if (error_operand_p (fntype))
+    return false;
 
   /* If a record should be passed the same as its first (and only) member
      don't pass it as an aggregate.  */
@@ -2099,25 +2099,25 @@ aggregate_value_p (const_tree exp, const_tree fntype)
      reference, do so.  */
   if ((TREE_CODE (exp) == PARM_DECL || TREE_CODE (exp) == RESULT_DECL)
       && DECL_BY_REFERENCE (exp))
-    return 1;
+    return true;
 
   /* Function types that are TREE_ADDRESSABLE force return in memory.  */
   if (fntype && TREE_ADDRESSABLE (fntype))
-    return 1;
+    return true;
 
   /* Types that are TREE_ADDRESSABLE must be constructed in memory,
      and thus can't be returned in registers.  */
   if (TREE_ADDRESSABLE (type))
-    return 1;
+    return true;
 
   if (TYPE_EMPTY_P (type))
-    return 0;
+    return false;
 
   if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
-    return 1;
+    return true;
 
   if (targetm.calls.return_in_memory (type, fntype))
-    return 1;
+    return true;
 
   /* Make sure we have suitable call-clobbered regs to return
      the value in; if not, we must return it in memory.  */
@@ -2126,7 +2126,7 @@ aggregate_value_p (const_tree exp, const_tree fntype)
   /* If we have something other than a REG (e.g. a PARALLEL), then assume
      it is OK.  */
   if (!REG_P (reg))
-    return 0;
+    return false;
 
   /* Use the default ABI if the type of the function isn't known.
      The scheme for handling interoperability between different ABIs
@@ -2139,9 +2139,9 @@ aggregate_value_p (const_tree exp, const_tree fntype)
   nregs = hard_regno_nregs (regno, TYPE_MODE (type));
   for (i = 0; i < nregs; i++)
     if (!fixed_regs[regno + i] && !abi.clobbers_full_reg_p (regno + i))
-      return 1;
+      return true;
 
-  return 0;
+  return false;
 }
 \f
 /* Return true if we should assign DECL a pseudo register; false if it
@@ -3472,6 +3472,17 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
 
       emit_move_insn (tempreg, validize_mem (copy_rtx (data->entry_parm)));
 
+      /* Some ABIs require scalar floating point modes to be passed
+        in a wider scalar integer mode.  We need to explicitly
+        truncate to an integer mode of the correct precision before
+        using a SUBREG to reinterpret as a floating point value.  */
+      if (SCALAR_FLOAT_MODE_P (data->nominal_mode)
+         && SCALAR_INT_MODE_P (data->arg.mode)
+         && known_lt (GET_MODE_SIZE (data->nominal_mode),
+                      GET_MODE_SIZE (data->arg.mode)))
+       tempreg = convert_wider_int_to_float (data->nominal_mode,
+                                             data->arg.mode, tempreg);
+
       push_to_sequence2 (all->first_conversion_insn, all->last_conversion_insn);
       to_conversion = true;
 
@@ -3636,6 +3647,12 @@ assign_parms (tree fndecl)
   assign_parms_initialize_all (&all);
   fnargs = assign_parms_augmented_arg_list (&all);
 
+  if (TYPE_NO_NAMED_ARGS_STDARG_P (TREE_TYPE (fndecl)))
+    {
+      struct assign_parm_data_one data = {};
+      assign_parms_setup_varargs (&all, &data, false);
+    }
+
   FOR_EACH_VEC_ELT (fnargs, i, parm)
     {
       struct assign_parm_data_one data;
@@ -3853,30 +3870,6 @@ assign_parms (tree fndecl)
     }
 }
 
-/* A subroutine of gimplify_parameters, invoked via walk_tree.
-   For all seen types, gimplify their sizes.  */
-
-static tree
-gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
-{
-  tree t = *tp;
-
-  *walk_subtrees = 0;
-  if (TYPE_P (t))
-    {
-      if (POINTER_TYPE_P (t))
-       *walk_subtrees = 1;
-      else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
-              && !TYPE_SIZES_GIMPLIFIED (t))
-       {
-         gimplify_type_sizes (t, (gimple_seq *) data);
-         *walk_subtrees = 1;
-       }
-    }
-
-  return NULL;
-}
-
 /* Gimplify the parameter list for current_function_decl.  This involves
    evaluating SAVE_EXPRs of variable sized parameters and generating code
    to implement callee-copies reference parameters.  Returns a sequence of
@@ -3912,8 +3905,7 @@ gimplify_parameters (gimple_seq *cleanup)
         SAVE_EXPRs (amongst others) onto a pending sizes list.  This
         turned out to be less than manageable in the gimple world.
         Now we have to hunt them down ourselves.  */
-      walk_tree_without_duplicates (&data.arg.type,
-                                   gimplify_parm_type, &stmts);
+      gimplify_type_sizes (TREE_TYPE (parm), &stmts);
 
       if (TREE_CODE (DECL_SIZE_UNIT (parm)) != INTEGER_CST)
        {
@@ -4628,14 +4620,6 @@ number_blocks (tree fn)
   int n_blocks;
   tree *block_vector;
 
-  /* For XCOFF debugging output, we start numbering the blocks
-     from 1 within each function, rather than keeping a running
-     count.  */
-#if defined (XCOFF_DEBUGGING_INFO)
-  if (write_symbols == XCOFF_DEBUG)
-    next_block_index = 1;
-#endif
-
   block_vector = get_block_vector (DECL_INITIAL (fn), &n_blocks);
 
   /* The top-level BLOCK isn't numbered at all.  */
@@ -4879,7 +4863,7 @@ allocate_struct_function (tree fndecl, bool abstract_p)
    instead of just setting it.  */
 
 void
-push_struct_function (tree fndecl)
+push_struct_function (tree fndecl, bool abstract_p)
 {
   /* When in_dummy_function we might be in the middle of a pop_cfun and
      current_function_decl and cfun may not match.  */
@@ -4888,7 +4872,7 @@ push_struct_function (tree fndecl)
              || (cfun && current_function_decl == cfun->decl));
   cfun_stack.safe_push (cfun);
   current_function_decl = fndecl;
-  allocate_struct_function (fndecl, false);
+  allocate_struct_function (fndecl, abstract_p);
 }
 
 /* Reset crtl and other non-struct-function variables to defaults as
@@ -4985,7 +4969,8 @@ init_function_start (tree subr)
   /* Warn if this value is an aggregate type,
      regardless of which calling convention we are using for it.  */
   if (AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr))))
-    warning (OPT_Waggregate_return, "function returns an aggregate");
+    warning_at (DECL_SOURCE_LOCATION (DECL_RESULT (subr)),
+               OPT_Waggregate_return, "function returns an aggregate");
 }
 
 /* Expand code to verify the stack_protect_guard.  This is invoked at
@@ -5049,9 +5034,12 @@ stack_protect_epilogue (void)
    PARMS_HAVE_CLEANUPS is nonzero if there are cleanups associated with
    the function's parameters, which must be run at any return statement.  */
 
+bool currently_expanding_function_start;
 void
 expand_function_start (tree subr)
 {
+  currently_expanding_function_start = true;
+
   /* Make sure volatile mem refs aren't considered
      valid operands of arithmetic insns.  */
   init_recog_no_volatile ();
@@ -5244,6 +5232,8 @@ expand_function_start (tree subr)
   /* If we are doing generic stack checking, the probe should go here.  */
   if (flag_stack_check == GENERIC_STACK_CHECK)
     stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
+
+  currently_expanding_function_start = false;
 }
 \f
 void
@@ -5741,26 +5731,26 @@ contains (const rtx_insn *insn, hash_table<insn_cache_hasher> *hash)
   return hash->find (const_cast<rtx_insn *> (insn)) != NULL;
 }
 
-int
+bool
 prologue_contains (const rtx_insn *insn)
 {
   return contains (insn, prologue_insn_hash);
 }
 
-int
+bool
 epilogue_contains (const rtx_insn *insn)
 {
   return contains (insn, epilogue_insn_hash);
 }
 
-int
+bool
 prologue_epilogue_contains (const rtx_insn *insn)
 {
   if (contains (insn, prologue_insn_hash))
-    return 1;
+    return true;
   if (contains (insn, epilogue_insn_hash))
-    return 1;
-  return 0;
+    return true;
+  return false;
 }
 
 void
@@ -5892,7 +5882,9 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
   df_simulate_one_insn_backwards (bb, ret, live_out);
 
   HARD_REG_SET selected_hardregs;
+  HARD_REG_SET all_call_used_regs;
   CLEAR_HARD_REG_SET (selected_hardregs);
+  CLEAR_HARD_REG_SET (all_call_used_regs);
   for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     {
       if (!crtl->abi->clobbers_full_reg_p (regno))
@@ -5901,6 +5893,13 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
        continue;
       if (REGNO_REG_SET_P (live_out, regno))
        continue;
+#ifdef LEAF_REG_REMAP
+      if (crtl->uses_only_leaf_regs && LEAF_REG_REMAP (regno) < 0)
+       continue;
+#endif
+      /* This is a call used register that is dead at return.  */
+      SET_HARD_REG_BIT (all_call_used_regs, regno);
+
       if (only_gpr
          && !TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], regno))
        continue;
@@ -5908,10 +5907,6 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
        continue;
       if (only_arg && !FUNCTION_ARG_REGNO_P (regno))
        continue;
-#ifdef LEAF_REG_REMAP
-      if (crtl->uses_only_leaf_regs && LEAF_REG_REMAP (regno) < 0)
-       continue;
-#endif
 
       /* Now this is a register that we might want to zero.  */
       SET_HARD_REG_BIT (selected_hardregs, regno);
@@ -5925,6 +5920,15 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
   HARD_REG_SET zeroed_hardregs;
   start_sequence ();
   zeroed_hardregs = targetm.calls.zero_call_used_regs (selected_hardregs);
+
+  /* For most targets, the returned set of registers is a subset of
+     selected_hardregs, however, for some of the targets (for example MIPS),
+     clearing some registers that are in selected_hardregs requires clearing
+     other call used registers that are not in the selected_hardregs, under
+     such situation, the returned set of registers must be a subset of
+     all call used registers.  */
+  gcc_assert (hard_reg_set_subset_p (zeroed_hardregs, all_call_used_regs));
+
   rtx_insn *seq = get_insns ();
   end_sequence ();
   if (seq)
@@ -5941,7 +5945,7 @@ gen_call_used_regs_seq (rtx_insn *ret, unsigned int zero_regs_type)
 
       /* Update the data flow information.  */
       crtl->must_be_zero_on_return |= zeroed_hardregs;
-      df_set_bb_dirty (EXIT_BLOCK_PTR_FOR_FN (cfun));
+      df_update_exit_block_uses ();
     }
 }
 
@@ -6232,10 +6236,18 @@ thread_prologue_and_epilogue_insns (void)
        }
     }
 
-  /* Threading the prologue and epilogue changes the artificial refs
-     in the entry and exit blocks.  */
-  epilogue_completed = 1;
-  df_update_entry_exit_and_calls ();
+  /* Threading the prologue and epilogue changes the artificial refs in the
+     entry and exit blocks, and may invalidate DF info for tail calls.  */
+  if (optimize
+      || flag_optimize_sibling_calls
+      || flag_ipa_icf_functions
+      || in_lto_p)
+    df_update_entry_exit_and_calls ();
+  else
+    {
+      df_update_entry_block_defs ();
+      df_update_exit_block_uses ();
+    }
 }
 
 /* Reposition the prologue-end and epilogue-begin notes after
@@ -6372,14 +6384,13 @@ current_function_name (void)
 }
 \f
 
-static unsigned int
+static void
 rest_of_handle_check_leaf_regs (void)
 {
 #ifdef LEAF_REGISTERS
   crtl->uses_only_leaf_regs
     = optimize > 0 && only_leaf_regs_used () && leaf_function_p ();
 #endif
-  return 0;
 }
 
 /* Insert a TYPE into the used types hash table of CFUN.  */
@@ -6502,9 +6513,10 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual unsigned int execute (function *)
+  unsigned int execute (function *) final override
     {
-      return rest_of_handle_check_leaf_regs ();
+      rest_of_handle_check_leaf_regs ();
+      return 0;
     }
 
 }; // class pass_leaf_regs
@@ -6517,8 +6529,8 @@ make_pass_leaf_regs (gcc::context *ctxt)
   return new pass_leaf_regs (ctxt);
 }
 
-static unsigned int
-rest_of_handle_thread_prologue_and_epilogue (void)
+static void
+rest_of_handle_thread_prologue_and_epilogue (function *fun)
 {
   /* prepare_shrink_wrap is sensitive to the block structure of the control
      flow graph, so clean it up first.  */
@@ -6535,6 +6547,13 @@ rest_of_handle_thread_prologue_and_epilogue (void)
      Fix that up.  */
   fixup_partitions ();
 
+  /* After prologue and epilogue generation, the judgement on whether
+     one memory access onto stack frame may trap or not could change,
+     since we get more exact stack information by now.  So try to
+     remove any EH edges here, see PR90259.  */
+  if (fun->can_throw_non_call_exceptions)
+    purge_all_dead_edges ();
+
   /* Shrink-wrapping can result in unreachable edges in the epilogue,
      see PR57320.  */
   cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
@@ -6542,8 +6561,6 @@ rest_of_handle_thread_prologue_and_epilogue (void)
   /* The stack usage info is finalized during prologue expansion.  */
   if (flag_stack_usage_info || flag_callgraph_info)
     output_stack_usage ();
-
-  return 0;
 }
 
 /* Record a final call to CALLEE at LOCATION.  */
@@ -6603,9 +6620,10 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual unsigned int execute (function *)
+  unsigned int execute (function * fun) final override
     {
-      return rest_of_handle_thread_prologue_and_epilogue ();
+      rest_of_handle_thread_prologue_and_epilogue (fun);
+      return 0;
     }
 
 }; // class pass_thread_prologue_and_epilogue
@@ -6641,7 +6659,7 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual unsigned int execute (function *);
+  unsigned int execute (function *) final override;
 
 }; // class pass_zero_call_used_regs
 
@@ -6912,7 +6930,7 @@ public:
   {}
 
   /* opt_pass methods: */
-  virtual unsigned int execute (function *);
+  unsigned int execute (function *) final override;
 
 }; // class pass_match_asm_constraints