/* Expands front end tree to back end RTL for GCC.
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl-error.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stor-layout.h"
#include "varasm.h"
#include "stringpool.h"
#include "flags.h"
#include "except.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "vec.h"
-#include "machmode.h"
#include "hard-reg-set.h"
-#include "input.h"
#include "function.h"
+#include "rtl.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "libfuncs.h"
#include "regs.h"
-#include "insn-config.h"
#include "recog.h"
#include "output.h"
#include "tm_p.h"
#include "shrink-wrap.h"
#include "toplev.h"
#include "rtl-iter.h"
+#include "tree-chkp.h"
+#include "rtl-chkp.h"
/* So we can assign to cfun in this file. */
#undef cfun
struct function *cfun = 0;
/* These hashes record the prologue and epilogue insns. */
-static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
- htab_t prologue_insn_hash;
-static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
- htab_t epilogue_insn_hash;
+
+struct insn_cache_hasher : ggc_cache_ptr_hash<rtx_def>
+{
+ static hashval_t hash (rtx x) { return htab_hash_pointer (x); }
+ static bool equal (rtx a, rtx b) { return a == b; }
+};
+
+static GTY((cache))
+ hash_table<insn_cache_hasher> *prologue_insn_hash;
+static GTY((cache))
+ hash_table<insn_cache_hasher> *epilogue_insn_hash;
\f
hash_table<used_type_hasher> *types_used_by_vars_hash = NULL;
extern tree debug_find_var_in_block_tree (tree, tree);
/* We always define `record_insns' even if it's not used so that we
can always export `prologue_epilogue_contains'. */
-static void record_insns (rtx_insn *, rtx, htab_t *) ATTRIBUTE_UNUSED;
-static bool contains (const_rtx, htab_t);
+static void record_insns (rtx_insn *, rtx, hash_table<insn_cache_hasher> **)
+ ATTRIBUTE_UNUSED;
+static bool contains (const_rtx, hash_table<insn_cache_hasher> *);
static void prepare_function_start (void);
static void do_clobber_return_reg (rtx, void *);
static void do_use_return_reg (rtx, void *);
struct temp_slot *temp_slot;
};
-struct temp_address_hasher : ggc_hasher<temp_slot_address_entry *>
+struct temp_address_hasher : ggc_ptr_hash<temp_slot_address_entry>
{
static hashval_t hash (temp_slot_address_entry *);
static bool equal (temp_slot_address_entry *, temp_slot_address_entry *);
case CALL_EXPR:
{
tree fndecl = get_callee_fndecl (fntype);
- fntype = (fndecl
- ? TREE_TYPE (fndecl)
- : TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype))));
+ if (fndecl)
+ fntype = TREE_TYPE (fndecl);
+ else if (CALL_EXPR_FN (fntype))
+ fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (fntype)));
+ else
+ /* For internal functions, assume nothing needs to be
+ returned in memory. */
+ return 0;
}
break;
case FUNCTION_DECL:
if (TREE_ADDRESSABLE (decl))
return false;
+ /* Decl is implicitly addressible by bound stores and loads
+ if it is an aggregate holding bounds. */
+ if (chkp_function_instrumented_p (current_function_decl)
+ && TREE_TYPE (decl)
+ && !BOUNDED_P (decl)
+ && chkp_type_has_pointer (TREE_TYPE (decl)))
+ return false;
+
/* Only register-like things go in registers. */
if (DECL_MODE (decl) == BLKmode)
return false;
/* When not optimizing, disregard register keyword for variables with
types containing methods, otherwise the methods won't be callable
from the debugger. */
- if (TYPE_METHODS (TREE_TYPE (decl)))
+ if (TYPE_METHODS (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
return false;
break;
default:
return true;
}
-/* Return true if TYPE should be passed by invisible reference. */
-
-bool
-pass_by_reference (CUMULATIVE_ARGS *ca, machine_mode mode,
- tree type, bool named_arg)
-{
- if (type)
- {
- /* If this type contains non-trivial constructors, then it is
- forbidden for the middle-end to create any new copies. */
- if (TREE_ADDRESSABLE (type))
- return true;
-
- /* GCC post 3.4 passes *all* variable sized types by reference. */
- if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- return true;
-
- /* If a record type should be passed the same as its first (and only)
- member, use the type and mode of that member. */
- if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type))
- {
- type = TREE_TYPE (first_field (type));
- mode = TYPE_MODE (type);
- }
- }
-
- return targetm.calls.pass_by_reference (pack_cumulative_args (ca), mode,
- type, named_arg);
-}
-
-/* Return true if TYPE, which is passed by reference, should be callee
- copied instead of caller copied. */
-
-bool
-reference_callee_copied (CUMULATIVE_ARGS *ca, machine_mode mode,
- tree type, bool named_arg)
-{
- if (type && TREE_ADDRESSABLE (type))
- return false;
- return targetm.calls.callee_copies (pack_cumulative_args (ca), mode, type,
- named_arg);
-}
-
/* Structures to communicate between the subroutines of assign_parms.
The first holds data persistent across all parameters, the second
is cleared out for each parameter. */
BOOL_BITFIELD loaded_in_reg : 1;
};
+struct bounds_parm_data
+{
+ assign_parm_data_one parm_data;
+ tree bounds_parm;
+ tree ptr_parm;
+ rtx ptr_entry;
+ int bound_no;
+};
+
/* A subroutine of assign_parms. Initialize ALL. */
static void
fnargs.safe_insert (0, decl);
all->function_result_decl = decl;
+
+ /* If function is instrumented then bounds of the
+ passed structure address is the second argument. */
+ if (chkp_function_instrumented_p (fndecl))
+ {
+ decl = build_decl (DECL_SOURCE_LOCATION (fndecl),
+ PARM_DECL, get_identifier (".result_bnd"),
+ pointer_bounds_type_node);
+ DECL_ARG_TYPE (decl) = pointer_bounds_type_node;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_NAMELESS (decl) = 1;
+ TREE_CONSTANT (decl) = 1;
+
+ DECL_CHAIN (decl) = DECL_CHAIN (all->orig_fnargs);
+ DECL_CHAIN (all->orig_fnargs) = decl;
+ fnargs.safe_insert (1, decl);
+ }
}
/* If the target wants to split complex arguments into scalars, do so. */
it came in a register so that REG_PARM_STACK_SPACE isn't skipped.
In this case, we call FUNCTION_ARG with NAMED set to 1 instead of 0
as it was the previous time. */
- in_regs = entry_parm != 0;
+ in_regs = (entry_parm != 0) || POINTER_BOUNDS_TYPE_P (data->passed_type);
#ifdef STACK_PARMS_IN_REG_PARM_AREA
in_regs = true;
#endif
assign_parm_is_stack_parm (struct assign_parm_data_all *all,
struct assign_parm_data_one *data)
{
+ /* Bounds are never passed on the stack to keep compatibility
+ with not instrumented code. */
+ if (POINTER_BOUNDS_TYPE_P (data->passed_type))
+ return false;
/* Trivially true if we've no incoming register. */
- if (data->entry_parm == NULL)
+ else if (data->entry_parm == NULL)
;
/* Also true if we're partially in registers and partially not,
since we've arranged to drop the entire argument on the stack. */
}
else
t = op1;
- rtx pat = gen_extend_insn (op0, t, promoted_nominal_mode,
- data->passed_mode, unsignedp);
+ rtx_insn *pat = gen_extend_insn (op0, t, promoted_nominal_mode,
+ data->passed_mode, unsignedp);
emit_insn (pat);
insns = get_insns ();
}
}
+/* Load bounds of PARM from bounds table. */
+static void
+assign_parm_load_bounds (struct assign_parm_data_one *data,
+ tree parm,
+ rtx entry,
+ unsigned bound_no)
+{
+ bitmap_iterator bi;
+ unsigned i, offs = 0;
+ int bnd_no = -1;
+ rtx slot = NULL, ptr = NULL;
+
+ if (parm)
+ {
+ bitmap slots;
+ bitmap_obstack_initialize (NULL);
+ slots = BITMAP_ALLOC (NULL);
+ chkp_find_bound_slots (TREE_TYPE (parm), slots);
+ EXECUTE_IF_SET_IN_BITMAP (slots, 0, i, bi)
+ {
+ if (bound_no)
+ bound_no--;
+ else
+ {
+ bnd_no = i;
+ break;
+ }
+ }
+ BITMAP_FREE (slots);
+ bitmap_obstack_release (NULL);
+ }
+
+ /* We may have bounds not associated with any pointer. */
+ if (bnd_no != -1)
+ offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT;
+
+ /* Find associated pointer. */
+ if (bnd_no == -1)
+ {
+ /* If bounds are not associated with any bounds,
+ then it is passed in a register or special slot. */
+ gcc_assert (data->entry_parm);
+ ptr = const0_rtx;
+ }
+ else if (MEM_P (entry))
+ slot = adjust_address (entry, Pmode, offs);
+ else if (REG_P (entry))
+ ptr = gen_rtx_REG (Pmode, REGNO (entry) + bnd_no);
+ else if (GET_CODE (entry) == PARALLEL)
+ ptr = chkp_get_value_with_offs (entry, GEN_INT (offs));
+ else
+ gcc_unreachable ();
+ data->entry_parm = targetm.calls.load_bounds_for_arg (slot, ptr,
+ data->entry_parm);
+}
+
+/* Assign RTL expressions to the function's bounds parameters BNDARGS. */
+
+static void
+assign_bounds (vec<bounds_parm_data> &bndargs,
+ struct assign_parm_data_all &all,
+ bool assign_regs, bool assign_special,
+ bool assign_bt)
+{
+ unsigned i, pass;
+ bounds_parm_data *pbdata;
+
+ if (!bndargs.exists ())
+ return;
+
+ /* We make few passes to store input bounds. Firstly handle bounds
+ passed in registers. After that we load bounds passed in special
+ slots. Finally we load bounds from Bounds Table. */
+ for (pass = 0; pass < 3; pass++)
+ FOR_EACH_VEC_ELT (bndargs, i, pbdata)
+ {
+ /* Pass 0 => regs only. */
+ if (pass == 0
+ && (!assign_regs
+ ||(!pbdata->parm_data.entry_parm
+ || GET_CODE (pbdata->parm_data.entry_parm) != REG)))
+ continue;
+ /* Pass 1 => slots only. */
+ else if (pass == 1
+ && (!assign_special
+ || (!pbdata->parm_data.entry_parm
+ || GET_CODE (pbdata->parm_data.entry_parm) == REG)))
+ continue;
+ /* Pass 2 => BT only. */
+ else if (pass == 2
+ && (!assign_bt
+ || pbdata->parm_data.entry_parm))
+ continue;
+
+ if (!pbdata->parm_data.entry_parm
+ || GET_CODE (pbdata->parm_data.entry_parm) != REG)
+ assign_parm_load_bounds (&pbdata->parm_data, pbdata->ptr_parm,
+ pbdata->ptr_entry, pbdata->bound_no);
+
+ set_decl_incoming_rtl (pbdata->bounds_parm,
+ pbdata->parm_data.entry_parm, false);
+
+ if (assign_parm_setup_block_p (&pbdata->parm_data))
+ assign_parm_setup_block (&all, pbdata->bounds_parm,
+ &pbdata->parm_data);
+ else if (pbdata->parm_data.passed_pointer
+ || use_register_for_decl (pbdata->bounds_parm))
+ assign_parm_setup_reg (&all, pbdata->bounds_parm,
+ &pbdata->parm_data);
+ else
+ assign_parm_setup_stack (&all, pbdata->bounds_parm,
+ &pbdata->parm_data);
+ }
+}
+
/* Assign RTL expressions to the function's parameters. This may involve
copying them into registers and using those registers as the DECL_RTL. */
struct assign_parm_data_all all;
tree parm;
vec<tree> fnargs;
- unsigned i;
+ unsigned i, bound_no = 0;
+ tree last_arg = NULL;
+ rtx last_arg_entry = NULL;
+ vec<bounds_parm_data> bndargs = vNULL;
+ bounds_parm_data bdata;
crtl->args.internal_arg_pointer
= targetm.calls.internal_arg_pointer ();
}
}
- if (cfun->stdarg && !DECL_CHAIN (parm))
- assign_parms_setup_varargs (&all, &data, false);
-
/* Find out where the parameter arrives in this function. */
assign_parm_find_entry_rtl (&all, &data);
assign_parm_find_stack_rtl (parm, &data);
assign_parm_adjust_entry_rtl (&data);
}
-
+ if (!POINTER_BOUNDS_TYPE_P (data.passed_type))
+ {
+ /* Remember where last non bounds arg was passed in case
+ we have to load associated bounds for it from Bounds
+ Table. */
+ last_arg = parm;
+ last_arg_entry = data.entry_parm;
+ bound_no = 0;
+ }
/* Record permanently how this parm was passed. */
if (data.passed_pointer)
{
else
set_decl_incoming_rtl (parm, data.entry_parm, false);
+ /* Boudns should be loaded in the particular order to
+ have registers allocated correctly. Collect info about
+ input bounds and load them later. */
+ if (POINTER_BOUNDS_TYPE_P (data.passed_type))
+ {
+ /* Expect bounds in instrumented functions only. */
+ gcc_assert (chkp_function_instrumented_p (fndecl));
+
+ bdata.parm_data = data;
+ bdata.bounds_parm = parm;
+ bdata.ptr_parm = last_arg;
+ bdata.ptr_entry = last_arg_entry;
+ bdata.bound_no = bound_no;
+ bndargs.safe_push (bdata);
+ }
+ else
+ {
+ assign_parm_adjust_stack_rtl (&data);
+
+ if (assign_parm_setup_block_p (&data))
+ assign_parm_setup_block (&all, parm, &data);
+ else if (data.passed_pointer || use_register_for_decl (parm))
+ assign_parm_setup_reg (&all, parm, &data);
+ else
+ assign_parm_setup_stack (&all, parm, &data);
+ }
+
+ if (cfun->stdarg && !DECL_CHAIN (parm))
+ {
+ int pretend_bytes = 0;
+
+ assign_parms_setup_varargs (&all, &data, false);
+
+ if (chkp_function_instrumented_p (fndecl))
+ {
+ /* We expect this is the last parm. Otherwise it is wrong
+ to assign bounds right now. */
+ gcc_assert (i == (fnargs.length () - 1));
+ assign_bounds (bndargs, all, true, false, false);
+ targetm.calls.setup_incoming_vararg_bounds (all.args_so_far,
+ data.promoted_mode,
+ data.passed_type,
+ &pretend_bytes,
+ false);
+ assign_bounds (bndargs, all, false, true, true);
+ bndargs.release ();
+ }
+ }
+
/* Update info on where next arg arrives in registers. */
targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
data.passed_type, data.named_arg);
- assign_parm_adjust_stack_rtl (&data);
-
- if (assign_parm_setup_block_p (&data))
- assign_parm_setup_block (&all, parm, &data);
- else if (data.passed_pointer || use_register_for_decl (parm))
- assign_parm_setup_reg (&all, parm, &data);
- else
- assign_parm_setup_stack (&all, parm, &data);
+ if (POINTER_BOUNDS_TYPE_P (data.passed_type))
+ bound_no++;
}
+ assign_bounds (bndargs, all, true, true, true);
+ bndargs.release ();
+
if (targetm.calls.split_complex_arg)
assign_parms_unsplit_complex (&all, fnargs);
fnargs.release ();
- /* Initialize pic_offset_table_rtx with a pseudo register
- if required. */
- if (targetm.use_pseudo_pic_reg ())
- pic_offset_table_rtx = gen_reg_rtx (Pmode);
-
/* Output all parameter conversion instructions (possibly including calls)
now that all parameters have been copied out of hard registers. */
emit_insn (all.first_conversion_insn);
crtl->args.size = CEIL_ROUND (crtl->args.size,
PARM_BOUNDARY / BITS_PER_UNIT);
-#ifdef ARGS_GROW_DOWNWARD
- crtl->args.arg_offset_rtx
- = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
- : expand_expr (size_diffop (all.stack_args_size.var,
- size_int (-all.stack_args_size.constant)),
- NULL_RTX, VOIDmode, EXPAND_NORMAL));
-#else
- crtl->args.arg_offset_rtx = ARGS_SIZE_RTX (all.stack_args_size);
-#endif
+ if (ARGS_GROW_DOWNWARD)
+ {
+ crtl->args.arg_offset_rtx
+ = (all.stack_args_size.var == 0 ? GEN_INT (-all.stack_args_size.constant)
+ : expand_expr (size_diffop (all.stack_args_size.var,
+ size_int (-all.stack_args_size.constant)),
+ NULL_RTX, VOIDmode, EXPAND_NORMAL));
+ }
+ else
+ crtl->args.arg_offset_rtx = ARGS_SIZE_RTX (all.stack_args_size);
/* See how many bytes, if any, of its args a function should try to pop
on return. */
real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result),
fndecl, true);
+ if (chkp_function_instrumented_p (fndecl))
+ crtl->return_bnd
+ = targetm.calls.chkp_function_value_bounds (TREE_TYPE (decl_result),
+ fndecl, true);
REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
/* The delay slot scheduler assumes that crtl->return_rtx
holds the hard register containing the return value, not a
if (crtl->preferred_stack_boundary < boundary)
crtl->preferred_stack_boundary = boundary;
-#ifdef ARGS_GROW_DOWNWARD
- locate->slot_offset.constant = -initial_offset_ptr->constant;
- if (initial_offset_ptr->var)
- locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
- initial_offset_ptr->var);
+ if (ARGS_GROW_DOWNWARD)
+ {
+ locate->slot_offset.constant = -initial_offset_ptr->constant;
+ if (initial_offset_ptr->var)
+ locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
+ initial_offset_ptr->var);
- {
- tree s2 = sizetree;
- if (where_pad != none
- && (!tree_fits_uhwi_p (sizetree)
- || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
- s2 = round_up (s2, round_boundary / BITS_PER_UNIT);
- SUB_PARM_SIZE (locate->slot_offset, s2);
- }
+ {
+ tree s2 = sizetree;
+ if (where_pad != none
+ && (!tree_fits_uhwi_p (sizetree)
+ || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
+ s2 = round_up (s2, round_boundary / BITS_PER_UNIT);
+ SUB_PARM_SIZE (locate->slot_offset, s2);
+ }
+
+ locate->slot_offset.constant += part_size_in_regs;
- locate->slot_offset.constant += part_size_in_regs;
-
- if (!in_regs || reg_parm_stack_space > 0)
- pad_to_arg_alignment (&locate->slot_offset, boundary,
- &locate->alignment_pad);
-
- locate->size.constant = (-initial_offset_ptr->constant
- - locate->slot_offset.constant);
- if (initial_offset_ptr->var)
- locate->size.var = size_binop (MINUS_EXPR,
- size_binop (MINUS_EXPR,
- ssize_int (0),
- initial_offset_ptr->var),
- locate->slot_offset.var);
-
- /* Pad_below needs the pre-rounded size to know how much to pad
- below. */
- locate->offset = locate->slot_offset;
- if (where_pad == downward)
- pad_below (&locate->offset, passed_mode, sizetree);
-
-#else /* !ARGS_GROW_DOWNWARD */
- if (!in_regs || reg_parm_stack_space > 0)
- pad_to_arg_alignment (initial_offset_ptr, boundary,
- &locate->alignment_pad);
- locate->slot_offset = *initial_offset_ptr;
+ if (!in_regs || reg_parm_stack_space > 0)
+ pad_to_arg_alignment (&locate->slot_offset, boundary,
+ &locate->alignment_pad);
+
+ locate->size.constant = (-initial_offset_ptr->constant
+ - locate->slot_offset.constant);
+ if (initial_offset_ptr->var)
+ locate->size.var = size_binop (MINUS_EXPR,
+ size_binop (MINUS_EXPR,
+ ssize_int (0),
+ initial_offset_ptr->var),
+ locate->slot_offset.var);
+
+ /* Pad_below needs the pre-rounded size to know how much to pad
+ below. */
+ locate->offset = locate->slot_offset;
+ if (where_pad == downward)
+ pad_below (&locate->offset, passed_mode, sizetree);
+
+ }
+ else
+ {
+ if (!in_regs || reg_parm_stack_space > 0)
+ pad_to_arg_alignment (initial_offset_ptr, boundary,
+ &locate->alignment_pad);
+ locate->slot_offset = *initial_offset_ptr;
#ifdef PUSH_ROUNDING
- if (passed_mode != BLKmode)
- sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
+ if (passed_mode != BLKmode)
+ sizetree = size_int (PUSH_ROUNDING (TREE_INT_CST_LOW (sizetree)));
#endif
- /* Pad_below needs the pre-rounded size to know how much to pad below
- so this must be done before rounding up. */
- locate->offset = locate->slot_offset;
- if (where_pad == downward)
- pad_below (&locate->offset, passed_mode, sizetree);
+ /* Pad_below needs the pre-rounded size to know how much to pad below
+ so this must be done before rounding up. */
+ locate->offset = locate->slot_offset;
+ if (where_pad == downward)
+ pad_below (&locate->offset, passed_mode, sizetree);
- if (where_pad != none
- && (!tree_fits_uhwi_p (sizetree)
- || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
- sizetree = round_up (sizetree, round_boundary / BITS_PER_UNIT);
+ if (where_pad != none
+ && (!tree_fits_uhwi_p (sizetree)
+ || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
+ sizetree = round_up (sizetree, round_boundary / BITS_PER_UNIT);
- ADD_PARM_SIZE (locate->size, sizetree);
+ ADD_PARM_SIZE (locate->size, sizetree);
- locate->size.constant -= part_size_in_regs;
-#endif /* ARGS_GROW_DOWNWARD */
+ locate->size.constant -= part_size_in_regs;
+ }
#ifdef FUNCTION_ARG_OFFSET
locate->offset.constant += FUNCTION_ARG_OFFSET (passed_mode, type);
tree offset = size_binop (PLUS_EXPR,
ARGS_SIZE_TREE (*offset_ptr),
sp_offset_tree);
-#ifdef ARGS_GROW_DOWNWARD
- tree rounded = round_down (offset, boundary / BITS_PER_UNIT);
-#else
- tree rounded = round_up (offset, boundary / BITS_PER_UNIT);
-#endif
+ tree rounded;
+ if (ARGS_GROW_DOWNWARD)
+ rounded = round_down (offset, boundary / BITS_PER_UNIT);
+ else
+ rounded = round_up (offset, boundary / BITS_PER_UNIT);
offset_ptr->var = size_binop (MINUS_EXPR, rounded, sp_offset_tree);
/* ARGS_SIZE_TREE includes constant term. */
else
{
offset_ptr->constant = -sp_offset +
-#ifdef ARGS_GROW_DOWNWARD
- FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
-#else
- CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes);
-#endif
+ (ARGS_GROW_DOWNWARD
+ ? FLOOR_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes)
+ : CEIL_ROUND (offset_ptr->constant + sp_offset, boundary_in_bytes));
+
if (boundary > PARM_BOUNDARY)
alignment_pad->constant = offset_ptr->constant - save_constant;
}
static void
prepare_function_start (void)
{
- gcc_assert (!crtl->emit.x_last_insn);
+ gcc_assert (!get_last_insn ());
init_temp_slots ();
init_emit ();
init_varasm_status ();
frame_pointer_needed = 0;
}
+void
+push_dummy_function (bool with_decl)
+{
+ tree fn_decl, fn_type, fn_result_decl;
+
+ gcc_assert (!in_dummy_function);
+ in_dummy_function = true;
+
+ if (with_decl)
+ {
+ fn_type = build_function_type_list (void_type_node, NULL_TREE);
+ fn_decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, NULL_TREE,
+ fn_type);
+ fn_result_decl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+ NULL_TREE, void_type_node);
+ DECL_RESULT (fn_decl) = fn_result_decl;
+ }
+ else
+ fn_decl = NULL_TREE;
+
+ push_struct_function (fn_decl);
+}
+
/* Initialize the rtl expansion mechanism so that we can do simple things
like generate sequences. This is used to provide a context during global
initialization of some passes. You must call expand_dummy_function_end
void
init_dummy_function_start (void)
{
- gcc_assert (!in_dummy_function);
- in_dummy_function = true;
- push_struct_function (NULL_TREE);
+ push_dummy_function (false);
prepare_function_start ();
}
/* Allow the target to compare Y with X without leaking either into
a register. */
- switch ((int) (HAVE_stack_protect_test != 0))
+ switch (HAVE_stack_protect_test != 0)
{
case 1:
tmp = gen_stack_protect_test (x, y, label);
/* Set DECL_REGISTER flag so that expand_function_end will copy the
result to the real return register(s). */
DECL_REGISTER (DECL_RESULT (subr)) = 1;
+
+ if (chkp_function_instrumented_p (current_function_decl))
+ {
+ tree return_type = TREE_TYPE (DECL_RESULT (subr));
+ rtx bounds = targetm.calls.chkp_function_value_bounds (return_type,
+ subr, 1);
+ SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds);
+ }
}
/* Initialize rtx for parameters and local variables.
if (cfun->static_chain_decl)
{
tree parm = cfun->static_chain_decl;
- rtx local, chain, insn;
+ rtx local, chain;
+ rtx_insn *insn;
local = gen_reg_rtx (Pmode);
chain = targetm.calls.static_chain (current_function_decl, true);
stack_check_probe_note = emit_note (NOTE_INSN_DELETED);
}
\f
+void
+pop_dummy_function (void)
+{
+ pop_cfun ();
+ in_dummy_function = false;
+}
+
/* Undo the effects of init_dummy_function_start. */
void
expand_dummy_function_end (void)
free_after_parsing (cfun);
free_after_compilation (cfun);
- pop_cfun ();
- in_dummy_function = false;
+ pop_dummy_function ();
}
-/* Call DOIT for each hard register used as a return value from
- the current function. */
+/* Helper for diddle_return_value. */
void
-diddle_return_value (void (*doit) (rtx, void *), void *arg)
+diddle_return_value_1 (void (*doit) (rtx, void *), void *arg, rtx outgoing)
{
- rtx outgoing = crtl->return_rtx;
-
if (! outgoing)
return;
}
}
+/* Call DOIT for each hard register used as a return value from
+ the current function. */
+
+void
+diddle_return_value (void (*doit) (rtx, void *), void *arg)
+{
+ diddle_return_value_1 (doit, arg, crtl->return_bnd);
+ diddle_return_value_1 (doit, arg, crtl->return_rtx);
+}
+
static void
do_clobber_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
{
void
expand_function_end (void)
{
- rtx clobber_after;
-
/* If arg_pointer_save_area was referenced only from a nested
function, we will not have initialized it yet. Do that now. */
if (arg_pointer_save_area && ! crtl->arg_pointer_save_area_init)
We delay actual code generation after the current_function_value_rtx
is computed. */
- clobber_after = get_last_insn ();
+ rtx_insn *clobber_after = get_last_insn ();
/* Output the label for the actual return from the function. */
emit_label (return_label);
If returning a structure PCC style,
the caller also depends on this value.
And cfun->returns_pcc_struct is not necessarily set. */
- if (cfun->returns_struct
- || cfun->returns_pcc_struct)
+ if ((cfun->returns_struct || cfun->returns_pcc_struct)
+ && !targetm.calls.omit_struct_return_reg)
{
rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl));
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
certainly doesn't fall thru into the exit block. */
if (!BARRIER_P (clobber_after))
{
- rtx seq;
-
start_sequence ();
clobber_return_register ();
- seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
emit_insn_after (seq, clobber_after);
if (! EXIT_IGNORE_STACK
&& cfun->calls_alloca)
{
- rtx tem = 0, seq;
+ rtx tem = 0;
start_sequence ();
emit_stack_save (SAVE_FUNCTION, &tem);
- seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
emit_insn_before (seq, parm_birth_insn);
if (! crtl->arg_pointer_save_area_init)
{
- rtx seq;
-
/* Save the arg pointer at the beginning of the function. The
generated stack slot may not be a valid memory address, so we
have to check it and fix it if necessary. */
start_sequence ();
emit_move_insn (validize_mem (copy_rtx (ret)),
crtl->args.internal_arg_pointer);
- seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
push_topmost_sequence ();
for the first time. */
static void
-record_insns (rtx_insn *insns, rtx end, htab_t *hashp)
+record_insns (rtx_insn *insns, rtx end, hash_table<insn_cache_hasher> **hashp)
{
rtx_insn *tmp;
- htab_t hash = *hashp;
+ hash_table<insn_cache_hasher> *hash = *hashp;
if (hash == NULL)
- *hashp = hash
- = htab_create_ggc (17, htab_hash_pointer, htab_eq_pointer, NULL);
+ *hashp = hash = hash_table<insn_cache_hasher>::create_ggc (17);
for (tmp = insns; tmp != end; tmp = NEXT_INSN (tmp))
{
- void **slot = htab_find_slot (hash, tmp, INSERT);
+ rtx *slot = hash->find_slot (tmp, INSERT);
gcc_assert (*slot == NULL);
*slot = tmp;
}
void
maybe_copy_prologue_epilogue_insn (rtx insn, rtx copy)
{
- htab_t hash;
- void **slot;
+ hash_table<insn_cache_hasher> *hash;
+ rtx *slot;
hash = epilogue_insn_hash;
- if (!hash || !htab_find (hash, insn))
+ if (!hash || !hash->find (insn))
{
hash = prologue_insn_hash;
- if (!hash || !htab_find (hash, insn))
+ if (!hash || !hash->find (insn))
return;
}
- slot = htab_find_slot (hash, copy, INSERT);
+ slot = hash->find_slot (copy, INSERT);
gcc_assert (*slot == NULL);
*slot = copy;
}
we can be running after reorg, SEQUENCE rtl is possible. */
static bool
-contains (const_rtx insn, htab_t hash)
+contains (const_rtx insn, hash_table<insn_cache_hasher> *hash)
{
if (hash == NULL)
return false;
rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn));
int i;
for (i = seq->len () - 1; i >= 0; i--)
- if (htab_find (hash, seq->element (i)))
+ if (hash->find (seq->element (i)))
return true;
return false;
}
- return htab_find (hash, insn) != NULL;
+ return hash->find (const_cast<rtx> (insn)) != NULL;
}
int
return 0;
}
-#ifdef HAVE_return
/* Insert use of return register before the end of BB. */
static void
emit_use_return_register_into_block (basic_block bb)
{
- rtx seq, insn;
start_sequence ();
use_return_register ();
- seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
- insn = BB_END (bb);
-#ifdef HAVE_cc0
- if (reg_mentioned_p (cc0_rtx, PATTERN (insn)))
+ rtx_insn *insn = BB_END (bb);
+ if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
insn = prev_cc0_setter (insn);
-#endif
+
emit_insn_before (seq, insn);
}
/* Create a return pattern, either simple_return or return, depending on
simple_p. */
-static rtx
+static rtx_insn *
gen_return_pattern (bool simple_p)
{
-#ifdef HAVE_simple_return
- return simple_p ? gen_simple_return () : gen_return ();
-#else
- gcc_assert (!simple_p);
- return gen_return ();
-#endif
+ return (simple_p
+ ? targetm.gen_simple_return ()
+ : targetm.gen_return ());
}
/* Insert an appropriate return pattern at the end of block BB. This
void
emit_return_into_block (bool simple_p, basic_block bb)
{
- rtx jump, pat;
- jump = emit_jump_insn_after (gen_return_pattern (simple_p), BB_END (bb));
- pat = PATTERN (jump);
+ rtx_jump_insn *jump = emit_jump_insn_after (gen_return_pattern (simple_p),
+ BB_END (bb));
+ rtx pat = PATTERN (jump);
if (GET_CODE (pat) == PARALLEL)
pat = XVECEXP (pat, 0, 0);
gcc_assert (ANY_RETURN_P (pat));
JUMP_LABEL (jump) = pat;
}
-#endif
/* Set JUMP_LABEL for a return insn. */
void
-set_return_jump_label (rtx returnjump)
+set_return_jump_label (rtx_insn *returnjump)
{
rtx pat = PATTERN (returnjump);
if (GET_CODE (pat) == PARALLEL)
JUMP_LABEL (returnjump) = ret_rtx;
}
-#if defined (HAVE_return) || defined (HAVE_simple_return)
/* Return true if there are any active insns between HEAD and TAIL. */
bool
active_insn_between (rtx_insn *head, rtx_insn *tail)
{
int i;
basic_block bb;
- rtx label;
edge_iterator ei;
edge e;
auto_vec<basic_block> src_bbs (EDGE_COUNT (last_bb->preds));
if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
src_bbs.quick_push (e->src);
- label = BB_HEAD (last_bb);
+ rtx_insn *label = BB_HEAD (last_bb);
FOR_EACH_VEC_ELT (src_bbs, i, bb)
{
dest = simple_return_rtx;
else
dest = ret_rtx;
- if (!redirect_jump (jump, dest, 0))
+ if (!redirect_jump (as_a <rtx_jump_insn *> (jump), dest, 0))
{
-#ifdef HAVE_simple_return
- if (simple_p)
+ if (targetm.have_simple_return () && simple_p)
{
if (dump_file)
fprintf (dump_file,
"Failed to redirect bb %d branch.\n", bb->index);
unconverted.safe_push (e);
}
-#endif
continue;
}
}
else
{
-#ifdef HAVE_simple_return
- if (simple_p)
+ if (targetm.have_simple_return () && simple_p)
{
if (dump_file)
fprintf (dump_file,
"Failed to redirect bb %d branch.\n", bb->index);
unconverted.safe_push (e);
}
-#endif
continue;
}
exit_fallthru_edge->flags &= ~EDGE_FALLTHRU;
return last_bb;
}
-#endif
/* Generate the prologue and epilogue RTL if the machine supports it. Thread
in a sibcall omit the sibcall_epilogue if the block is not in
ANTIC. */
-static void
+void
thread_prologue_and_epilogue_insns (void)
{
bool inserted;
-#ifdef HAVE_simple_return
vec<edge> unconverted_simple_returns = vNULL;
bitmap_head bb_flags;
-#endif
rtx_insn *returnjump;
rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
rtx_insn *prologue_seq ATTRIBUTE_UNUSED, *split_prologue_seq ATTRIBUTE_UNUSED;
}
#endif
-#ifdef HAVE_simple_return
bitmap_initialize (&bb_flags, &bitmap_default_obstack);
/* Try to perform a kind of shrink-wrapping, making sure the
function that require it. */
try_shrink_wrapping (&entry_edge, orig_entry_edge, &bb_flags, prologue_seq);
-#endif
if (split_prologue_seq != NULL_RTX)
{
exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
-#ifdef HAVE_simple_return
- if (entry_edge != orig_entry_edge)
+ if (targetm.have_simple_return () && entry_edge != orig_entry_edge)
exit_fallthru_edge
= get_unconverted_simple_return (exit_fallthru_edge, bb_flags,
&unconverted_simple_returns,
&returnjump);
-#endif
-#ifdef HAVE_return
- if (HAVE_return)
+ if (targetm.have_return ())
{
if (exit_fallthru_edge == NULL)
goto epilogue_done;
{
last_bb = emit_return_for_exit (exit_fallthru_edge, false);
epilogue_end = returnjump = BB_END (last_bb);
-#ifdef HAVE_simple_return
+
/* Emitting the return may add a basic block.
Fix bb_flags for the added block. */
- if (last_bb != exit_fallthru_edge->src)
+ if (targetm.have_simple_return ()
+ && last_bb != exit_fallthru_edge->src)
bitmap_set_bit (&bb_flags, last_bb->index);
-#endif
+
goto epilogue_done;
}
}
}
-#endif
/* A small fib -- epilogue is not yet completed, but we wish to re-use
this marker for the splits of EH_RETURN patterns, and nothing else
if (exit_fallthru_edge == NULL)
goto epilogue_done;
-#ifdef HAVE_epilogue
if (HAVE_epilogue)
{
start_sequence ();
set_return_jump_label (returnjump);
}
else
-#endif
{
basic_block cur_bb;
}
}
-#ifdef HAVE_simple_return
- convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags, returnjump,
- unconverted_simple_returns);
-#endif
+ if (targetm.have_simple_return ())
+ convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags,
+ returnjump, unconverted_simple_returns);
#ifdef HAVE_sibcall_epilogue
/* Emit sibling epilogues before any sibling call sites. */
if (!CALL_P (insn)
|| ! SIBLING_CALL_P (insn)
-#ifdef HAVE_simple_return
- || (entry_edge != orig_entry_edge
- && !bitmap_bit_p (&bb_flags, bb->index))
-#endif
- )
+ || (targetm.have_simple_return ()
+ && entry_edge != orig_entry_edge
+ && !bitmap_bit_p (&bb_flags, bb->index)))
{
ei_next (&ei);
continue;
}
#endif
-#ifdef HAVE_epilogue
if (epilogue_end)
{
rtx_insn *insn, *next;
reorder_insns (insn, insn, PREV_INSN (epilogue_end));
}
}
-#endif
-#ifdef HAVE_simple_return
bitmap_clear (&bb_flags);
-#endif
/* Threading the prologue and epilogue changes the artificial refs
in the entry and exit blocks. */
void
reposition_prologue_and_epilogue_notes (void)
{
-#if defined (HAVE_prologue) || defined (HAVE_epilogue) \
- || defined (HAVE_sibcall_epilogue)
+#if ! defined (HAVE_prologue) && ! defined (HAVE_sibcall_epilogue)
+ if (!HAVE_epilogue)
+ return;
+#endif
+
/* Since the hash table is created on demand, the fact that it is
non-null is a signal that it is non-empty. */
if (prologue_insn_hash != NULL)
{
- size_t len = htab_elements (prologue_insn_hash);
+ size_t len = prologue_insn_hash->elements ();
rtx_insn *insn, *last = NULL, *note = NULL;
/* Scan from the beginning until we reach the last prologue insn. */
}
}
}
-#endif /* HAVE_prologue or HAVE_epilogue */
}
/* Returns the name of function declared by FNDECL. */
df_insn_rescan (insn);
}
+/* Add the decl D to the local_decls list of FUN. */
+
+void
+add_local_decl (struct function *fun, tree d)
+{
+ gcc_assert (TREE_CODE (d) == VAR_DECL);
+ vec_safe_push (fun->local_decls, d);
+}
+
namespace {
const pass_data pass_data_match_asm_constraints =