/* 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.
#include "attribs.h"
#include "gimple.h"
#include "options.h"
+#include "function-abi.h"
/* So we can assign to cfun in this file. */
#undef cfun
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_or_fixed_reg_p (regno + i))
+ if (!fixed_regs[regno + i] && !abi.clobbers_full_reg_p (regno + i))
return 1;
return 0;
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),
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)
{
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.arg.pass_by_reference)
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);
}
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
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
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;
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 =