* builtins.def (BUILT_IN_STACK_ALLOC): Remove.
* builtins.c (expand_builtin) <BUILT_IN_STACK_ALLOC>: Remove.
* dwarf2out.c (loc_descriptor): Handle PARALLEL here ...
(add_location_or_const_value_attribute): ... not here. Use
loc_descriptor_from_tree if possible.
(loc_descriptor_from_tree_1): Rename from loc_descriptor_from_tree.
Simplify address handling. Handle DECL_VALUE_EXPR. Handle register
values specially.
(loc_descriptor_from_tree): New. Update callers.
* expr.c (expand_var): Ignore DECL_VALUE_EXPR variables.
* gimplify.c (gimplify_decl_expr): Lower variable sized types to
pointer plus dereference. Set DECL_VALUE_EXPR. Set save_stack.
(gimplify_call_expr): Do not recognize BUILT_IN_STACK_ALLOC
and BUILT_IN_STACK_RESTORE.
(gimplify_expr): Lower DECL_VALUE_EXPR decls.
* stmt.c (expand_stack_alloc): Remove.
* tree-mudflap.c (mx_register_decls): Don't look for
BUILT_IN_STACK_ALLOC.
* tree-nested.c (convert_local_reference): Likewise.
* tree.h (DECL_VALUE_EXPR): New.
ada/
* utils.c (gnat_install_builtins): Remove __builtin_stack_alloc,
add __builtin_alloca.
fortran/
* f95-lang.c (gfc_init_builtin_functions): Remove
__builtin_stack_alloc, add __builtin_alloca.
* trans-array.c (gfc_trans_auto_array_allocation): Use DECL_EXPR.
* trans-decl.c (gfc_trans_auto_character_variable): Likewise.
From-SVN: r85794
+2004-08-10 Richard Henderson <rth@redhat.com>
+
+ * builtins.def (BUILT_IN_STACK_ALLOC): Remove.
+ * builtins.c (expand_builtin) <BUILT_IN_STACK_ALLOC>: Remove.
+ * dwarf2out.c (loc_descriptor): Handle PARALLEL here ...
+ (add_location_or_const_value_attribute): ... not here. Use
+ loc_descriptor_from_tree if possible.
+ (loc_descriptor_from_tree_1): Rename from loc_descriptor_from_tree.
+ Simplify address handling. Handle DECL_VALUE_EXPR. Handle register
+ values specially.
+ (loc_descriptor_from_tree): New. Update callers.
+ * expr.c (expand_var): Ignore DECL_VALUE_EXPR variables.
+ * gimplify.c (gimplify_decl_expr): Lower variable sized types to
+ pointer plus dereference. Set DECL_VALUE_EXPR. Set save_stack.
+ (gimplify_call_expr): Do not recognize BUILT_IN_STACK_ALLOC
+ and BUILT_IN_STACK_RESTORE.
+ (gimplify_expr): Lower DECL_VALUE_EXPR decls.
+ * stmt.c (expand_stack_alloc): Remove.
+ * tree-mudflap.c (mx_register_decls): Don't look for
+ BUILT_IN_STACK_ALLOC.
+ * tree-nested.c (convert_local_reference): Likewise.
+ * tree.h (DECL_VALUE_EXPR): New.
+
2004-08-10 Richard Henderson <rth@redhat.com>
* stor-layout.c (round_up): Check for 0/1 before dividing.
+2004-08-10 Richard Henderson <rth@redhat.com>
+
+ * utils.c (gnat_install_builtins): Remove __builtin_stack_alloc,
+ add __builtin_alloca.
+
2004-08-10 Richard Henderson <rth@redhat.com>
* config-lang.in (boot_language): Yes.
gnat_define_builtin ("__builtin_clzll", ftype, BUILT_IN_CLZLL, "clzll",
true);
+ /* The init_trampoline and adjust_trampoline builtins aren't used directly.
+ They are inserted during lowering of nested functions. */
+
tmp = tree_cons (NULL_TREE, ptr_void_type_node, void_list_node);
tmp = tree_cons (NULL_TREE, ptr_void_type_node, tmp);
tmp = tree_cons (NULL_TREE, ptr_void_type_node, tmp);
gnat_define_builtin ("__builtin_adjust_trampoline", ftype,
BUILT_IN_ADJUST_TRAMPOLINE, "adjust_trampoline", true);
- tmp = tree_cons (NULL_TREE, ptr_void_type_node, void_list_node);
- tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
- ftype = build_function_type (ptr_void_type_node, tmp);
- gnat_define_builtin ("__builtin_stack_alloc", ftype, BUILT_IN_STACK_ALLOC,
- "stack_alloc", false);
+ /* The stack_save, stack_restore, and alloca builtins aren't used directly.
+ They are inserted during gimplification to implement variable sized stack
+ allocation. */
- /* The stack_save and stack_restore builtins aren't used directly. They
- are inserted during gimplification to implement stack_alloc calls. */
ftype = build_function_type (ptr_void_type_node, void_list_node);
gnat_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE,
"stack_save", false);
+
tmp = tree_cons (NULL_TREE, ptr_void_type_node, void_list_node);
ftype = build_function_type (void_type_node, tmp);
gnat_define_builtin ("__builtin_stack_restore", ftype,
BUILT_IN_STACK_RESTORE, "stack_restore", false);
+
+ tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
+ ftype = build_function_type (ptr_void_type_node, tmp);
+ gnat_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
+ "alloca", false);
+
}
/* Create the predefined scalar types such as `integer_type_node' needed
return target;
break;
- case BUILT_IN_STACK_ALLOC:
- expand_stack_alloc (TREE_VALUE (arglist),
- TREE_VALUE (TREE_CHAIN (arglist)));
- return const0_rtx;
-
case BUILT_IN_STACK_SAVE:
return expand_stack_save ();
DEF_GCC_BUILTIN (BUILT_IN_RETURN_ADDRESS, "return_address", BT_FN_PTR_UINT, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_SAVEREGS, "saveregs", BT_FN_PTR_VAR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_SETJMP, "setjmp", BT_FN_INT_PTR, ATTR_NULL)
-DEF_GCC_BUILTIN (BUILT_IN_STACK_ALLOC, "stack_alloc", BT_FN_VOID_PTR_SIZE, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_STACK_SAVE, "stack_save", BT_FN_PTR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_STACK_RESTORE, "stack_restore", BT_FN_VOID_PTR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_STDARG_START, "stdarg_start", BT_FN_VOID_VALIST_REF_VAR, ATTR_NULL)
static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode, bool);
static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx);
static dw_loc_descr_ref loc_descriptor (rtx, bool);
-static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
+static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree);
static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
static tree field_type (tree);
static unsigned int simple_type_align_in_bits (tree);
if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
{
loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), can_use_fbreg);
+ break;
}
- /* Multiple parts. */
- else
- {
- rtvec par_elems = XVEC (XEXP (rtl, 1), 0);
- int num_elem = GET_NUM_ELEM (par_elems);
- enum machine_mode mode;
- int i;
- /* Create the first one, so we have something to add to. */
- loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
- can_use_fbreg);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
- add_loc_descr (&loc_result,
- new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
- for (i = 1; i < num_elem; i++)
- {
- dw_loc_descr_ref temp;
+ rtl = XEXP (rtl, 1);
+ /* FALLTHRU */
- temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
+ case PARALLEL:
+ {
+ rtvec par_elems = XVEC (rtl, 0);
+ int num_elem = GET_NUM_ELEM (par_elems);
+ enum machine_mode mode;
+ int i;
+
+ /* Create the first one, so we have something to add to. */
+ loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
can_use_fbreg);
- add_loc_descr (&loc_result, temp);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
- add_loc_descr (&loc_result,
- new_loc_descr (DW_OP_piece,
- GET_MODE_SIZE (mode), 0));
- }
- }
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
+ for (i = 1; i < num_elem; i++)
+ {
+ dw_loc_descr_ref temp;
+
+ temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
+ can_use_fbreg);
+ add_loc_descr (&loc_result, temp);
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_piece,
+ GET_MODE_SIZE (mode), 0));
+ }
+ }
break;
default:
}
/* Similar, but generate the descriptor from trees instead of rtl. This comes
- up particularly with variable length arrays. If ADDRESSP is nonzero, we are
- looking for an address. Otherwise, we return a value. If we can't make a
- descriptor, return 0. */
+ up particularly with variable length arrays. WANT_ADDRESS is 2 if this is
+ a top-level invocation of loc_descriptor_from_tree; is 1 if this is not a
+ top-level invocation, and we require the address of LOC; is 0 if we require
+ the value of LOC. */
static dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc, int addressp)
+loc_descriptor_from_tree_1 (tree loc, int want_address)
{
dw_loc_descr_ref ret, ret1;
- int indirect_p = 0;
+ int have_address = 0;
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
enum dwarf_location_atom op;
return 0;
case ADDR_EXPR:
- /* We can support this only if we can look through conversions and
- find an INDIRECT_EXPR. */
- for (loc = TREE_OPERAND (loc, 0);
- TREE_CODE (loc) == CONVERT_EXPR || TREE_CODE (loc) == NOP_EXPR
- || TREE_CODE (loc) == NON_LVALUE_EXPR
- || TREE_CODE (loc) == VIEW_CONVERT_EXPR
- || TREE_CODE (loc) == SAVE_EXPR;
- loc = TREE_OPERAND (loc, 0))
- ;
+ /* If we already want an address, there's nothing we can do. */
+ if (want_address)
+ return 0;
- return (TREE_CODE (loc) == INDIRECT_REF
- ? loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp)
- : 0);
+ /* Otherwise, process the argument and look for the address. */
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 1);
case VAR_DECL:
if (DECL_THREAD_LOCAL (loc))
ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
add_loc_descr (&ret, ret1);
- indirect_p = 1;
+ have_address = 1;
break;
}
- /* Fall through. */
+ /* FALLTHRU */
case PARM_DECL:
+ if (DECL_VALUE_EXPR (loc))
+ return loc_descriptor_from_tree_1 (DECL_VALUE_EXPR (loc), want_address);
+ /* FALLTHRU */
+
case RESULT_DECL:
{
rtx rtl = rtl_for_decl_location (loc);
if (rtl == NULL_RTX)
return 0;
+ else if (GET_CODE (rtl) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (rtl);
+ if (TYPE_UNSIGNED (TREE_TYPE (loc)))
+ val &= GET_MODE_MASK (DECL_MODE (loc));
+ ret = int_loc_descriptor (val);
+ }
+ else if (GET_CODE (rtl) == CONST_STRING)
+ return 0;
else if (CONSTANT_P (rtl))
{
ret = new_loc_descr (DW_OP_addr, 0, 0);
ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
ret->dw_loc_oprnd1.v.val_addr = rtl;
- indirect_p = 1;
}
else
{
- enum machine_mode mode = GET_MODE (rtl);
+ enum machine_mode mode;
+
+ /* Certain constructs can only be represented at top-level. */
+ if (want_address == 2)
+ return loc_descriptor (rtl, true);
+ mode = GET_MODE (rtl);
if (MEM_P (rtl))
{
- indirect_p = 1;
rtl = XEXP (rtl, 0);
+ have_address = 1;
}
-
ret = mem_loc_descriptor (rtl, mode, true);
}
}
break;
case INDIRECT_REF:
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
- indirect_p = 1;
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ have_address = 1;
break;
case COMPOUND_EXPR:
- return loc_descriptor_from_tree (TREE_OPERAND (loc, 1), addressp);
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), want_address);
case NOP_EXPR:
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR:
case SAVE_EXPR:
case MODIFY_EXPR:
- return loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp);
+ return loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), want_address);
case COMPONENT_REF:
case BIT_FIELD_REF:
if (obj == loc)
return 0;
- ret = loc_descriptor_from_tree (obj, 1);
+ ret = loc_descriptor_from_tree_1 (obj, 1);
if (ret == 0
|| bitpos % BITS_PER_UNIT != 0 || bitsize % BITS_PER_UNIT != 0)
return 0;
if (offset != NULL_TREE)
{
/* Variable offset. */
- add_loc_descr (&ret, loc_descriptor_from_tree (offset, 0));
+ add_loc_descr (&ret, loc_descriptor_from_tree_1 (offset, 0));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
- if (!addressp)
- indirect_p = 1;
-
bytepos = bitpos / BITS_PER_UNIT;
if (bytepos > 0)
add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
add_loc_descr (&ret, int_loc_descriptor (bytepos));
add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
}
+
+ have_address = 1;
break;
}
rtx rtl = lookup_constant_def (loc);
enum machine_mode mode;
- if (!MEM_P (rtl))
+ if (!rtl || !MEM_P (rtl))
return 0;
mode = GET_MODE (rtl);
rtl = XEXP (rtl, 0);
-
- rtl = targetm.delegitimize_address (rtl);
-
- indirect_p = 1;
ret = mem_loc_descriptor (rtl, mode, true);
+ have_address = 1;
break;
}
if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
&& host_integerp (TREE_OPERAND (loc, 1), 0))
{
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
goto do_binop;
do_binop:
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
- ret1 = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
+ ret1 = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
if (ret == 0 || ret1 == 0)
return 0;
goto do_unop;
do_unop:
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0)
return 0;
loc = build3 (COND_EXPR, TREE_TYPE (loc),
build2 (code, integer_type_node,
TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
- TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+ TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
}
/* ... fall through ... */
case COND_EXPR:
{
dw_loc_descr_ref lhs
- = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+ = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 1), 0);
dw_loc_descr_ref rhs
- = loc_descriptor_from_tree (TREE_OPERAND (loc, 2), 0);
+ = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 2), 0);
dw_loc_descr_ref bra_node, jump_node, tmp;
- ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+ ret = loc_descriptor_from_tree_1 (TREE_OPERAND (loc, 0), 0);
if (ret == 0 || lhs == 0 || rhs == 0)
return 0;
}
/* Show if we can't fill the request for an address. */
- if (addressp && indirect_p == 0)
+ if (want_address && !have_address)
return 0;
/* If we've got an address and don't want one, dereference. */
- if (!addressp && indirect_p > 0)
+ if (!want_address && have_address)
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc));
return ret;
}
+static inline dw_loc_descr_ref
+loc_descriptor_from_tree (tree loc)
+{
+ return loc_descriptor_from_tree_1 (loc, 2);
+}
+
/* Given a value, round it up to the lowest multiple of `boundary'
which is not less than the value itself. */
}
rtl = rtl_for_decl_location (decl);
- if (rtl == NULL_RTX)
- return;
-
- switch (GET_CODE (rtl))
+ if (rtl && (CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING))
{
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- case CONST_STRING:
- case SYMBOL_REF:
- case LABEL_REF:
- case CONST:
- case PLUS:
- /* DECL_RTL could be (plus (reg ...) (const_int ...)) */
add_const_value_attribute (die, rtl);
- break;
-
- case MEM:
- if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
- {
- /* Need loc_descriptor_from_tree since that's where we know
- how to handle TLS variables. Want the object's address
- since the top-level DW_AT_location assumes such. See
- the confusion in loc_descriptor for reference. */
- descr = loc_descriptor_from_tree (decl, 1);
- }
- else
- {
- case REG:
- case SUBREG:
- case CONCAT:
- descr = loc_descriptor (rtl, true);
- }
- add_AT_location_description (die, attr, descr);
- break;
-
- case PARALLEL:
- {
- rtvec par_elems = XVEC (rtl, 0);
- int num_elem = GET_NUM_ELEM (par_elems);
- enum machine_mode mode;
- int i;
-
- /* Create the first one, so we have something to add to. */
- descr = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0), true);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
- add_loc_descr (&descr,
- new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
- for (i = 1; i < num_elem; i++)
- {
- dw_loc_descr_ref temp;
-
- temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0), true);
- add_loc_descr (&descr, temp);
- mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
- add_loc_descr (&descr,
- new_loc_descr (DW_OP_piece,
- GET_MODE_SIZE (mode), 0));
- }
- }
- add_AT_location_description (die, DW_AT_location, descr);
- break;
-
- default:
- abort ();
+ return;
}
+
+ descr = loc_descriptor_from_tree (decl);
+ if (descr)
+ add_AT_location_description (die, attr, descr);
}
/* If we don't have a copy of this variable in memory for some reason (such
dw_die_ref ctx, decl_die;
dw_loc_descr_ref loc;
- loc = loc_descriptor_from_tree (bound, 0);
+ loc = loc_descriptor_from_tree (bound);
if (loc == NULL)
break;
if (cfun->static_chain_decl)
add_AT_location_description (subr_die, DW_AT_static_link,
- loc_descriptor_from_tree (cfun->static_chain_decl, 0));
+ loc_descriptor_from_tree (cfun->static_chain_decl));
}
/* Now output descriptions of the arguments for this function. This gets
? !TREE_ASM_WRITTEN (var)
: !DECL_RTL_SET_P (var))
{
- if (TREE_CODE (var) == VAR_DECL && DECL_DEFER_OUTPUT (var))
- {
- /* Prepare a mem & address for the decl. */
- rtx x;
-
- if (TREE_STATIC (var))
- abort ();
-
- x = gen_rtx_MEM (DECL_MODE (var),
- gen_reg_rtx (Pmode));
-
- set_mem_attributes (x, var, 1);
- SET_DECL_RTL (var, x);
- }
+ if (TREE_CODE (var) == VAR_DECL && DECL_VALUE_EXPR (var))
+ /* Should be ignored. */;
else if (lang_hooks.expand_decl (var))
/* OK. */;
else if (TREE_CODE (var) == VAR_DECL && !TREE_STATIC (var))
+2004-08-10 Richard Henderson <rth@redhat.com>
+
+ * f95-lang.c (gfc_init_builtin_functions): Remove
+ __builtin_stack_alloc, add __builtin_alloca.
+ * trans-array.c (gfc_trans_auto_array_allocation): Use DECL_EXPR.
+ * trans-decl.c (gfc_trans_auto_character_variable): Likewise.
+
2004-08-10 Paul Brook <paul@codesourcery.com>
* trans-io.c (transfer_expr): Handle pointters.
gfc_define_builtin ("__builtin_adjust_trampoline", ftype,
BUILT_IN_ADJUST_TRAMPOLINE, "adjust_trampoline", true);
- tmp = tree_cons (NULL_TREE, pvoid_type_node, void_list_node);
- tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
- ftype = build_function_type (pvoid_type_node, tmp);
- gfc_define_builtin ("__builtin_stack_alloc", ftype, BUILT_IN_STACK_ALLOC,
- "stack_alloc", false);
+ /* The stack_save, stack_restore, and alloca builtins aren't used directly.
+ They are inserted during gimplification to implement variable sized
+ stack allocation. */
- /* The stack_save and stack_restore builtins aren't used directly. They
- are inserted during gimplification to implement stack_alloc calls. */
ftype = build_function_type (pvoid_type_node, void_list_node);
gfc_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE,
"stack_save", false);
+
tmp = tree_cons (NULL_TREE, pvoid_type_node, void_list_node);
ftype = build_function_type (void_type_node, tmp);
gfc_define_builtin ("__builtin_stack_restore", ftype, BUILT_IN_STACK_RESTORE,
"stack_restore", false);
+
+ tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
+ ftype = build_function_type (pvoid_type_node, tmp);
+ gfc_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
+ "alloca", false);
}
#undef DEFINE_MATH_BUILTIN
{
gfc_trans_init_string_length (sym->ts.cl, &block);
- DECL_DEFER_OUTPUT (decl) = 1;
-
- /* Generate code to allocate the automatic variable. It will be
- freed automatically. */
- tmp = gfc_build_addr_expr (NULL, decl);
- args = gfc_chainon_list (NULL_TREE, tmp);
- args = gfc_chainon_list (args, sym->ts.cl->backend_decl);
- tmp = gfc_build_function_call (built_in_decls[BUILT_IN_STACK_ALLOC],
- args);
+ /* Emit a DECL_EXPR for this variable, which will cause the
+ gimplifier to allocate stoage, and all that good stuff. */
+ tmp = build (DECL_EXPR, TREE_TYPE (decl), decl);
gfc_add_expr_to_block (&block, tmp);
}
{
stmtblock_t body;
tree decl;
- tree args;
tree tmp;
assert (sym->backend_decl);
decl = sym->backend_decl;
- DECL_DEFER_OUTPUT (decl) = 1;
-
- /* Since we don't use a DECL_STMT or equivalent, we have to deal
- with getting these gimplified. But we can't gimplify it yet since
- we're still generating statements.
-
- ??? This should be cleaned up and handled like other front ends. */
- gfc_add_expr_to_block (&body, save_expr (DECL_SIZE (decl)));
- gfc_add_expr_to_block (&body, save_expr (DECL_SIZE_UNIT (decl)));
-
- /* Generate code to allocate the automatic variable. It will be freed
- automatically. */
- tmp = gfc_build_addr_expr (NULL, decl);
- args = gfc_chainon_list (NULL_TREE, tmp);
- args = gfc_chainon_list (args, sym->ts.cl->backend_decl);
- tmp = gfc_build_function_call (built_in_decls[BUILT_IN_STACK_ALLOC], args);
+ /* Emit a DECL_EXPR for this variable, which will cause the
+ gimplifier to allocate stoage, and all that good stuff. */
+ tmp = build (DECL_EXPR, TREE_TYPE (decl), decl);
gfc_add_expr_to_block (&body, tmp);
+
gfc_add_expr_to_block (&body, fnbody);
return gfc_finish_block (&body);
}
/* This is a variable-sized decl. Simplify its size and mark it
for deferred expansion. Note that mudflap depends on the format
of the emitted code: see mx_register_decls(). */
- tree t, args;
+ tree t, args, addr, ptr_type;
gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
+ /* All occurences of this decl in final gimplified code will be
+ replaced by indirection. Setting DECL_VALUE_EXPR does two
+ things: First, it lets the rest of the gimplifier know what
+ replacement to use. Second, it lets the debug info know
+ where to find the value. */
+ ptr_type = build_pointer_type (TREE_TYPE (decl));
+ addr = create_tmp_var (ptr_type, get_name (decl));
+ DECL_IGNORED_P (addr) = 0;
+ t = build_fold_indirect_ref (addr);
+ DECL_VALUE_EXPR (decl) = t;
+
args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL);
- t = build_fold_addr_expr (decl);
- args = tree_cons (NULL, t, args);
- t = implicit_built_in_decls[BUILT_IN_STACK_ALLOC];
+ t = built_in_decls[BUILT_IN_ALLOCA];
t = build_function_call_expr (t, args);
+ t = fold_convert (ptr_type, t);
+ t = build2 (MODIFY_EXPR, void_type_node, addr, t);
gimplify_and_add (t, stmt_p);
- DECL_DEFER_OUTPUT (decl) = 1;
+
+ /* Indicate that we need to restore the stack level when the
+ enclosing BIND_EXPR is exited. */
+ gimplify_ctxp->save_stack = true;
}
if (init && init != error_mark_node)
decl = get_callee_fndecl (*expr_p);
if (decl && DECL_BUILT_IN (decl))
{
- tree new;
-
- /* If it is allocation of stack, record the need to restore the memory
- when the enclosing bind_expr is exited. */
- if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_ALLOC)
- gimplify_ctxp->save_stack = true;
-
- /* If it is restore of the stack, reset it, since it means we are
- regimplifying the bind_expr. Note that we use the fact that
- for try_finally_expr, try part is processed first. */
- if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_RESTORE)
- gimplify_ctxp->save_stack = false;
-
- new = simplify_builtin (*expr_p, !want_value);
+ tree new = simplify_builtin (*expr_p, !want_value);
if (new && new != *expr_p)
{
abort ();
#endif
ret = GS_ERROR;
+ break;
}
- else
- ret = GS_ALL_DONE;
+
+ /* If this is a local variable sized decl, it must be accessed
+ indirectly. Perform that substitution. */
+ if (DECL_VALUE_EXPR (tmp))
+ {
+ *expr_p = unshare_expr (DECL_VALUE_EXPR (tmp));
+ ret = GS_OK;
+ break;
+ }
+
+ ret = GS_ALL_DONE;
break;
case SSA_NAME:
}
}
\f
-/* Emit code to allocate T_SIZE bytes of dynamic stack space for ALLOC. */
-void
-expand_stack_alloc (tree alloc, tree t_size)
-{
- rtx address, dest, size;
- tree var, type;
-
- if (TREE_CODE (alloc) != ADDR_EXPR)
- abort ();
- var = TREE_OPERAND (alloc, 0);
- if (TREE_CODE (var) != VAR_DECL)
- abort ();
-
- type = TREE_TYPE (var);
-
- /* Compute the variable's size, in bytes. */
- size = expand_expr (t_size, NULL_RTX, VOIDmode, 0);
- free_temp_slots ();
-
- /* Allocate space on the stack for the variable. */
- address = XEXP (DECL_RTL (var), 0);
- dest = allocate_dynamic_stack_space (size, address, TYPE_ALIGN (type));
- if (dest != address)
- emit_move_insn (address, dest);
-
- /* Indicate the alignment we actually gave this variable. */
-#ifdef STACK_BOUNDARY
- DECL_ALIGN (var) = STACK_BOUNDARY;
-#else
- DECL_ALIGN (var) = BIGGEST_ALIGNMENT;
-#endif
- DECL_USER_ALIGN (var) = 0;
-}
-
/* Emit code to save the current value of stack. */
rtx
expand_stack_save (void)
&& TREE_ADDRESSABLE (decl)
/* The type of the variable must be complete. */
&& COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl))
+ /* The decl hasn't been decomposed somehow. */
+ && DECL_VALUE_EXPR (decl) == NULL
/* Don't process the same decl twice. */
&& ! mf_marked_p (decl))
{
tree unregister_fncall, unregister_fncall_params;
tree register_fncall, register_fncall_params;
- if (DECL_DEFER_OUTPUT (decl))
- {
- /* Oh no ... it's probably a variable-length array (VLA).
- The size and address cannot be computed by merely
- looking at the DECL. See gimplify_decl_stmt for the
- method by which VLA declarations turn into calls to
- BUILT_IN_STACK_ALLOC. We assume that multiple
- VLAs declared later in the same block get allocation
- code later than the others. */
- tree stack_alloc_call = NULL_TREE;
-
- while(! tsi_end_p (initially_stmts))
- {
- tree t = tsi_stmt (initially_stmts);
-
- tree call = NULL_TREE;
- if (TREE_CODE (t) == CALL_EXPR)
- call = t;
- else if (TREE_CODE (t) == MODIFY_EXPR &&
- TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
- call = TREE_OPERAND (t, 1);
- else if (TREE_CODE (t) == TRY_FINALLY_EXPR)
- {
- /* We hope that this is the try/finally block sometimes
- constructed by gimplify_bind_expr() for a BIND_EXPR
- that contains VLAs. This very naive recursion
- appears to be sufficient. */
- initially_stmts = tsi_start (TREE_OPERAND (t, 0));
- }
-
- if (call != NULL_TREE)
- {
- if (TREE_CODE (TREE_OPERAND(call, 0)) == ADDR_EXPR &&
- TREE_OPERAND (TREE_OPERAND (call, 0), 0) ==
- implicit_built_in_decls [BUILT_IN_STACK_ALLOC])
- {
- tree stack_alloc_args = TREE_OPERAND (call, 1);
- tree stack_alloc_op1 = TREE_VALUE (stack_alloc_args);
- tree stack_alloc_op2 = TREE_VALUE (TREE_CHAIN (stack_alloc_args));
-
- if (TREE_CODE (stack_alloc_op1) == ADDR_EXPR &&
- TREE_OPERAND (stack_alloc_op1, 0) == decl)
- {
- /* Got it! */
- size = stack_alloc_op2;
- stack_alloc_call = call;
- /* Advance iterator to point past this allocation call. */
- tsi_next (&initially_stmts);
- break;
- }
- }
- }
-
- tsi_next (&initially_stmts);
- }
-
- if (stack_alloc_call == NULL_TREE)
- {
- warning ("mudflap cannot handle variable-sized declaration `%s'",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- break;
- }
- }
- else
- {
- size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
- }
+ size = convert (size_type_node, TYPE_SIZE_UNIT (TREE_TYPE (decl)));
/* (& VARIABLE, sizeof (VARIABLE), __MF_TYPE_STACK) */
unregister_fncall_params =
{
struct walk_stmt_info *wi = data;
struct nesting_info *info = wi->info;
- tree t = *tp, field, x, y;
+ tree t = *tp, field, x;
switch (TREE_CODE (t))
{
}
break;
- case CALL_EXPR:
- *walk_subtrees = 1;
-
- /* Ready for some fun? We need to recognize
- __builtin_stack_alloc (&x, n)
- and insert
- FRAME.x = &x
- after that. X should have use_pointer_in_frame set. We can't
- do this any earlier, since we can't meaningfully evaluate &x. */
-
- x = get_callee_fndecl (t);
- if (!x || DECL_BUILT_IN_CLASS (x) != BUILT_IN_NORMAL)
- break;
- if (DECL_FUNCTION_CODE (x) != BUILT_IN_STACK_ALLOC)
- break;
- t = TREE_VALUE (TREE_OPERAND (t, 1));
- if (TREE_CODE (t) != ADDR_EXPR)
- abort ();
- t = TREE_OPERAND (t, 0);
- if (TREE_CODE (t) != VAR_DECL)
- abort ();
- field = lookup_field_for_decl (info, t, NO_INSERT);
- if (!field)
- break;
- if (!use_pointer_in_frame (t))
- abort ();
-
- x = build_addr (t);
- y = get_frame_field (info, info->context, field, &wi->tsi);
- x = build (MODIFY_EXPR, void_type_node, y, x);
- SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi)));
- tsi_link_after (&wi->tsi, x, TSI_SAME_STMT);
- break;
-
case REALPART_EXPR:
case IMAGPART_EXPR:
case COMPONENT_REF:
entire function. */
#define DECL_SAVED_TREE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.saved_tree)
+/* In a VAR_DECL or PARM_DECL, the location at which the value may be found,
+ if transformations have made this more complicated than evaluating the
+ decl itself. This should only be used for debugging; once this field has
+ been set, the decl itself may not legitimately appear in the function. */
+#define DECL_VALUE_EXPR(NODE) \
+ (TREE_CHECK2 (NODE, VAR_DECL, PARM_DECL)->decl.saved_tree)
+
/* List of FUNCTION_DECLs inlined into this function's body. */
#define DECL_INLINED_FNS(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.inlined_fns)
int GTY ((tag ("VAR_DECL"))) i;
} GTY ((desc ("TREE_CODE((tree) &(%0))"))) u2;
- /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */
+ /* In a FUNCTION_DECL, this is DECL_SAVED_TREE.
+ In a VAR_DECL or PARM_DECL, this is DECL_VALUE_EXPR. */
tree saved_tree;
/* In a FUNCTION_DECL, these are function data which is to be kept
extern void expand_goto (tree);
extern void expand_asm (tree, int);
-extern void expand_stack_alloc (tree, tree);
extern rtx expand_stack_save (void);
extern void expand_stack_restore (tree);
extern void expand_return (tree);