and in other cases as well. */
int inhibit_defer_pop;
-/* A list of all cleanups which belong to the arguments of
- function calls being expanded by expand_call. */
-tree cleanups_this_call;
-
/* When temporaries are created by TARGET_EXPRs, they are created at
this level of temp_slot_level, so that they can remain allocated
until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
static void do_jump_for_compare PROTO((rtx, rtx, rtx));
static rtx compare PROTO((tree, enum rtx_code, enum rtx_code));
static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int));
-static tree defer_cleanups_to PROTO((tree));
extern tree truthvalue_conversion PROTO((tree));
/* Record for each mode whether we can move a register directly to or
int mode;
for (mode = 0; mode < (int) MAX_MACHINE_MODE; mode++)
- mode_to_const_map[mode] =
- mode_to_load_map[mode] =
- mode_to_store_map[mode] = neverneverland;
+ mode_to_const_map[mode]
+ = mode_to_load_map[mode]
+ = mode_to_store_map[mode] = neverneverland;
#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
mode_to_const_map[(int) SYM] = CONST; \
pending_stack_adjust = 0;
inhibit_defer_pop = 0;
- cleanups_this_call = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
p->pending_stack_adjust = pending_stack_adjust;
p->inhibit_defer_pop = inhibit_defer_pop;
- p->cleanups_this_call = cleanups_this_call;
p->saveregs_value = saveregs_value;
p->apply_args_value = apply_args_value;
p->forced_labels = forced_labels;
pending_stack_adjust = 0;
inhibit_defer_pop = 0;
- cleanups_this_call = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
{
pending_stack_adjust = p->pending_stack_adjust;
inhibit_defer_pop = p->inhibit_defer_pop;
- cleanups_this_call = p->cleanups_this_call;
saveregs_value = p->saveregs_value;
apply_args_value = p->apply_args_value;
forced_labels = p->forced_labels;
to1 = (data->autinc_to
? gen_rtx (MEM, mode, data->to_addr)
- : change_address (data->to, mode,
- plus_constant (data->to_addr, data->offset)));
+ : copy_rtx (change_address (data->to, mode,
+ plus_constant (data->to_addr,
+ data->offset))));
MEM_IN_STRUCT_P (to1) = data->to_struct;
- from1 =
- (data->autinc_from
- ? gen_rtx (MEM, mode, data->from_addr)
- : change_address (data->from, mode,
- plus_constant (data->from_addr, data->offset)));
+
+ from1
+ = (data->autinc_from
+ ? gen_rtx (MEM, mode, data->from_addr)
+ : copy_rtx (change_address (data->from, mode,
+ plus_constant (data->from_addr,
+ data->offset))));
MEM_IN_STRUCT_P (from1) = data->from_struct;
#ifdef HAVE_PRE_DECREMENT
{
int i;
rtx pat, last;
+ enum machine_mode mode;
+ /* If SIZE is that of a mode no bigger than a word, just use that
+ mode's store operation. */
+ if (size <= UNITS_PER_WORD
+ && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
+ {
+ emit_move_insn (change_address (x, mode, NULL),
+ gen_rtx (REG, mode, regno));
+ return;
+ }
+
/* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
- to the left before storing to memory. */
+ to the left before storing to memory. Note that the previous test
+ doesn't handle all cases (e.g. SIZE == 3). */
if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
{
rtx tem = operand_subword (x, 0, 1, BLKmode);
to allow for AIX with 4 DF arguments after a single SI arg. The
last DF argument will only load 1 word into the integer registers,
but load a DF value into the float registers. */
+ else if ((GET_MODE_SIZE (GET_MODE (target_reg))
+ <= GET_MODE_SIZE (GET_MODE (y)))
+ && GET_MODE (target_reg) == word_mode)
+ /* This might be a const_double, so we can't just use SUBREG. */
+ source = operand_subword (y, 0, 0, VOIDmode);
else if (GET_MODE_SIZE (GET_MODE (target_reg))
- <= GET_MODE_SIZE (GET_MODE (y)))
- source = gen_rtx (SUBREG, GET_MODE (target_reg), y, 0);
+ == GET_MODE_SIZE (GET_MODE (y)))
+ source = gen_lowpart (GET_MODE (target_reg), y);
else
abort ();
}
to1 = (data->autinc_to
? gen_rtx (MEM, mode, data->to_addr)
- : change_address (data->to, mode,
- plus_constant (data->to_addr, data->offset)));
+ : copy_rtx (change_address (data->to, mode,
+ plus_constant (data->to_addr,
+ data->offset))));
MEM_IN_STRUCT_P (to1) = data->to_struct;
#ifdef HAVE_PRE_DECREMENT
Default is below for small data on big-endian machines; else above. */
enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
- /* If we're placing part of X into a register and part of X onto
- the stack, indicate that the entire register is clobbered to
- keep flow from thinking the unused part of the register is live. */
- if (partial > 0 && reg != 0)
- emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
-
/* Invert direction if stack is post-update. */
if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
if (where_pad != none)
structure we are storing into, and hence may be shared.
We must make a new MEM before setting the volatile bit. */
if (offset == 0)
- to_rtx = change_address (to_rtx, VOIDmode, XEXP (to_rtx, 0));
+ to_rtx = copy_rtx (to_rtx);
+
MEM_VOLATILE_P (to_rtx) = 1;
}
#if 0 /* This was turned off because, when a field is volatile
For non-BLKmode, it is more efficient not to do this. */
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
- rtx flag = NULL_RTX;
- tree left_cleanups = NULL_TREE;
- tree right_cleanups = NULL_TREE;
- tree old_cleanups = cleanups_this_call;
-
- /* Used to save a pointer to the place to put the setting of
- the flag that indicates if this side of the conditional was
- taken. We backpatch the code, if we find out later that we
- have any conditional cleanups that need to be performed. */
- rtx dest_right_flag = NULL_RTX;
- rtx dest_left_flag = NULL_RTX;
emit_queue ();
target = protect_from_queue (target, 1);
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
+ start_cleanup_deferal ();
store_expr (TREE_OPERAND (exp, 1), target, 0);
- dest_left_flag = get_last_insn ();
- /* Handle conditional cleanups, if any. */
- left_cleanups = defer_cleanups_to (old_cleanups);
+ end_cleanup_deferal ();
emit_queue ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
+ start_cleanup_deferal ();
store_expr (TREE_OPERAND (exp, 2), target, 0);
- dest_right_flag = get_last_insn ();
- /* Handle conditional cleanups, if any. */
- right_cleanups = defer_cleanups_to (old_cleanups);
+ end_cleanup_deferal ();
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
- /* Add back in any conditional cleanups. */
- if (left_cleanups || right_cleanups)
- {
- tree new_cleanups;
- tree cond;
- rtx last;
-
- /* Now that we know that a flag is needed, go back and add in the
- setting of the flag. */
-
- flag = gen_reg_rtx (word_mode);
-
- /* Do the left side flag. */
- last = get_last_insn ();
- /* Flag left cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- /* ??? deprecated, use sequences instead. */
- reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
-
- /* Do the right side flag. */
- last = get_last_insn ();
- /* Flag left cleanups as needed. */
- emit_move_insn (flag, const0_rtx);
- /* ??? deprecated, use sequences instead. */
- reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
-
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- if (! left_cleanups)
- left_cleanups = integer_zero_node;
- if (! right_cleanups)
- right_cleanups = integer_zero_node;
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- left_cleanups, right_cleanups);
- new_cleanups = fold (new_cleanups);
-
- pop_obstacks ();
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- expand_eh_region_start ();
- }
return want_value ? target : NULL_RTX;
}
else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
if (!(target && GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
&& !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
- && temp != target
+ && ! rtx_equal_p (temp, target)
&& (CONSTANT_P (temp) || want_value))
dont_return_target = 1;
}
/* If value was not generated in the target, store it there.
Convert the value to TARGET's type first if nec. */
- if (temp != target && TREE_CODE (exp) != ERROR_MARK)
+ if (! rtx_equal_p (temp, target) && TREE_CODE (exp) != ERROR_MARK)
{
target = protect_from_queue (target, 1);
if (GET_MODE (temp) != GET_MODE (target)
if (TREE_READONLY (field))
{
if (GET_CODE (to_rtx) == MEM)
- to_rtx = change_address (to_rtx, GET_MODE (to_rtx),
- XEXP (to_rtx, 0));
+ to_rtx = copy_rtx (to_rtx);
+
RTX_UNCHANGING_P (to_rtx) = 1;
}
/* Now build a reference to just the desired component. */
- to_rtx = change_address (target, mode,
- plus_constant (addr, (bitpos / BITS_PER_UNIT)));
+ to_rtx = copy_rtx (change_address (target, mode,
+ plus_constant (addr,
+ (bitpos
+ / BITS_PER_UNIT))));
MEM_IN_STRUCT_P (to_rtx) = 1;
return store_expr (exp, to_rtx, value_mode != VOIDmode);
int vars_need_expansion = 0;
/* Need to open a binding contour here because
- if there are any cleanups they most be contained here. */
+ if there are any cleanups they must be contained here. */
expand_start_bindings (0);
/* Mark the corresponding BLOCK for output in its proper place. */
}
case RTL_EXPR:
- if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
- abort ();
- emit_insns (RTL_EXPR_SEQUENCE (exp));
- RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+ if (RTL_EXPR_SEQUENCE (exp))
+ {
+ if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
+ abort ();
+ emit_insns (RTL_EXPR_SEQUENCE (exp));
+ RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+ }
preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
free_temps_for_rtl_expr (exp);
return RTL_EXPR_RTL (exp);
if (TREE_READONLY (exp))
{
if (GET_CODE (target) == MEM)
- target = change_address (target, GET_MODE (target),
- XEXP (target, 0));
+ target = copy_rtx (target);
+
RTX_UNCHANGING_P (target) = 1;
}
{
RTL_EXPR_RTL (exp)
= expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
- cleanups_this_call
- = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2), cleanups_this_call);
+ expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 2));
+
/* That's it for this cleanup. */
TREE_OPERAND (exp, 2) = 0;
- expand_eh_region_start ();
}
return RTL_EXPR_RTL (exp);
case CLEANUP_POINT_EXPR:
{
extern int temp_slot_level;
- tree old_cleanups = cleanups_this_call;
- int old_temp_level = target_temp_slot_level;
- push_temp_slots ();
+ /* Start a new binding layer that will keep track of all cleanup
+ actions to be performed. */
+ expand_start_bindings (0);
+
target_temp_slot_level = temp_slot_level;
+
op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
/* If we're going to use this value, load it up now. */
if (! ignore)
op0 = force_not_mem (op0);
- expand_cleanups_to (old_cleanups);
preserve_temp_slots (op0);
- free_temp_slots ();
- pop_temp_slots ();
- target_temp_slot_level = old_temp_level;
+ expand_end_bindings (NULL_TREE, 0, 0);
}
return op0;
}
{
- rtx flag = NULL_RTX;
- tree left_cleanups = NULL_TREE;
- tree right_cleanups = NULL_TREE;
-
- /* Used to save a pointer to the place to put the setting of
- the flag that indicates if this side of the conditional was
- taken. We backpatch the code, if we find out later that we
- have any conditional cleanups that need to be performed. */
- rtx dest_right_flag = NULL_RTX;
- rtx dest_left_flag = NULL_RTX;
-
/* Note that COND_EXPRs whose type is a structure or union
are required to be constructed to contain assignments of
a temporary variable, so that we can evaluate them here
tree singleton = 0;
tree binary_op = 0, unary_op = 0;
- tree old_cleanups = cleanups_this_call;
/* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
convert it to our mode, if necessary. */
NO_DEFER_POP;
op0 = gen_label_rtx ();
- flag = gen_reg_rtx (word_mode);
if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
{
if (temp != 0)
else
expand_expr (singleton,
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- dest_left_flag = get_last_insn ();
if (singleton == TREE_OPERAND (exp, 1))
jumpif (TREE_OPERAND (exp, 0), op0);
else
jumpifnot (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferal ();
if (binary_op && temp == 0)
/* Just touch the other operand. */
expand_expr (TREE_OPERAND (binary_op, 1),
make_tree (type, temp)),
temp, 0);
op1 = op0;
- dest_right_flag = get_last_insn ();
}
-#if 0
- /* This is now done in jump.c and is better done there because it
- produces shorter register lifetimes. */
-
- /* Check for both possibilities either constants or variables
- in registers (but not the same as the target!). If so, can
- save branches by assigning one, branching, and assigning the
- other. */
- else if (temp && GET_MODE (temp) != BLKmode
- && (TREE_CONSTANT (TREE_OPERAND (exp, 1))
- || ((TREE_CODE (TREE_OPERAND (exp, 1)) == PARM_DECL
- || TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL)
- && DECL_RTL (TREE_OPERAND (exp, 1))
- && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 1))) == REG
- && DECL_RTL (TREE_OPERAND (exp, 1)) != temp))
- && (TREE_CONSTANT (TREE_OPERAND (exp, 2))
- || ((TREE_CODE (TREE_OPERAND (exp, 2)) == PARM_DECL
- || TREE_CODE (TREE_OPERAND (exp, 2)) == VAR_DECL)
- && DECL_RTL (TREE_OPERAND (exp, 2))
- && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 2))) == REG
- && DECL_RTL (TREE_OPERAND (exp, 2)) != temp)))
- {
- if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
- temp = gen_reg_rtx (mode);
- store_expr (TREE_OPERAND (exp, 2), temp, 0);
- dest_left_flag = get_last_insn ();
- jumpifnot (TREE_OPERAND (exp, 0), op0);
-
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
- store_expr (TREE_OPERAND (exp, 1), temp, 0);
- op1 = op0;
- dest_right_flag = get_last_insn ();
- }
-#endif
/* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
comparison operator. If we have one of these cases, set the
output to A, branch on A (cse will merge these two references),
if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 1), temp, 0);
- dest_left_flag = get_last_insn ();
jumpif (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferal ();
store_expr (TREE_OPERAND (exp, 2), temp, 0);
op1 = op0;
- dest_right_flag = get_last_insn ();
}
else if (temp
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 2), temp, 0);
- dest_left_flag = get_last_insn ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferal ();
store_expr (TREE_OPERAND (exp, 1), temp, 0);
op1 = op0;
- dest_right_flag = get_last_insn ();
}
else
{
op1 = gen_label_rtx ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferal ();
if (temp != 0)
store_expr (TREE_OPERAND (exp, 1), temp, 0);
else
expand_expr (TREE_OPERAND (exp, 1),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- dest_left_flag = get_last_insn ();
-
- /* Handle conditional cleanups, if any. */
- left_cleanups = defer_cleanups_to (old_cleanups);
-
+ end_cleanup_deferal ();
emit_queue ();
emit_jump_insn (gen_jump (op1));
emit_barrier ();
emit_label (op0);
+ start_cleanup_deferal ();
if (temp != 0)
store_expr (TREE_OPERAND (exp, 2), temp, 0);
else
expand_expr (TREE_OPERAND (exp, 2),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- dest_right_flag = get_last_insn ();
}
- /* Handle conditional cleanups, if any. */
- right_cleanups = defer_cleanups_to (old_cleanups);
+ end_cleanup_deferal ();
emit_queue ();
emit_label (op1);
OK_DEFER_POP;
- /* Add back in, any conditional cleanups. */
- if (left_cleanups || right_cleanups)
- {
- tree new_cleanups;
- tree cond;
- rtx last;
-
- /* Now that we know that a flag is needed, go back and add in the
- setting of the flag. */
-
- /* Do the left side flag. */
- last = get_last_insn ();
- /* Flag left cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- /* ??? deprecated, use sequences instead. */
- reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
-
- /* Do the right side flag. */
- last = get_last_insn ();
- /* Flag left cleanups as needed. */
- emit_move_insn (flag, const0_rtx);
- /* ??? deprecated, use sequences instead. */
- reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
-
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- if (! left_cleanups)
- left_cleanups = integer_zero_node;
- if (! right_cleanups)
- right_cleanups = integer_zero_node;
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- left_cleanups, right_cleanups);
- new_cleanups = fold (new_cleanups);
-
- pop_obstacks ();
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- expand_eh_region_start ();
- }
return temp;
}
store_expr (exp1, target, 0);
- if (cleanups)
- {
- cleanups_this_call = tree_cons (NULL_TREE,
- cleanups,
- cleanups_this_call);
- expand_eh_region_start ();
- }
+ expand_decl_cleanup (NULL_TREE, cleanups);
return target;
}
return target;
}
+ case TRY_CATCH_EXPR:
+ {
+ tree handler = TREE_OPERAND (exp, 1);
+
+ expand_eh_region_start ();
+
+ op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+
+ expand_eh_region_end (handler);
+
+ return op0;
+ }
+
+ case POPDCC_EXPR:
+ {
+ rtx dcc = get_dynamic_cleanup_chain ();
+ emit_move_insn (dcc, validize_mem (gen_rtx (MEM, Pmode, dcc)));
+ return const0_rtx;
+ }
+
+ case POPDHC_EXPR:
+ {
+ rtx dhc = get_dynamic_handler_chain ();
+ emit_move_insn (dhc, validize_mem (gen_rtx (MEM, Pmode, dhc)));
+ return const0_rtx;
+ }
+
case ERROR_MARK:
op0 = CONST0_RTX (tmode);
if (op0 != 0)
#endif
return tem;
}
+
+/* __builtin_setjmp is passed a pointer to an array of five words (not
+ all will be used on all machines). It operates similarly to the C
+ library function of the same name, but is more efficient. Much of
+ the code below (and for longjmp) is copied from the handling of
+ non-local gotos.
+
+ NOTE: This is intended for use by GNAT and the exception handling
+ scheme in the compiler and will only work in the method used by
+ them. */
+
+rtx
+expand_builtin_setjmp (buf_addr, target)
+ rtx buf_addr;
+ rtx target;
+{
+ rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+ enum machine_mode sa_mode = Pmode, value_mode;
+ rtx stack_save;
+ int old_inhibit_defer_pop = inhibit_defer_pop;
+ int return_pops
+ = RETURN_POPS_ARGS (get_identifier ("__dummy"),
+ build_function_type (void_type_node, NULL_TREE),
+ 0);
+ rtx next_arg_reg;
+ CUMULATIVE_ARGS args_so_far;
+ rtx op0;
+ int i;
+
+ value_mode = TYPE_MODE (integer_type_node);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ buf_addr = convert_memory_address (Pmode, buf_addr);
+#endif
+
+ buf_addr = force_reg (Pmode, buf_addr);
+
+ if (target == 0 || GET_CODE (target) != REG
+ || REGNO (target) < FIRST_PSEUDO_REGISTER)
+ target = gen_reg_rtx (value_mode);
+
+ emit_queue ();
+
+ CONST_CALL_P (emit_note (NULL_PTR, NOTE_INSN_SETJMP)) = 1;
+ current_function_calls_setjmp = 1;
+
+ /* We store the frame pointer and the address of lab1 in the buffer
+ and use the rest of it for the stack save area, which is
+ machine-dependent. */
+ emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
+ virtual_stack_vars_rtx);
+ emit_move_insn
+ (validize_mem (gen_rtx (MEM, Pmode,
+ plus_constant (buf_addr,
+ GET_MODE_SIZE (Pmode)))),
+ gen_rtx (LABEL_REF, Pmode, lab1));
+
+#ifdef HAVE_save_stack_nonlocal
+ if (HAVE_save_stack_nonlocal)
+ sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
+#endif
+
+ stack_save = gen_rtx (MEM, sa_mode,
+ plus_constant (buf_addr,
+ 2 * GET_MODE_SIZE (Pmode)));
+ emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
+
+#ifdef HAVE_setjmp
+ if (HAVE_setjmp)
+ emit_insn (gen_setjmp ());
+#endif
+
+ /* Set TARGET to zero and branch around the other case. */
+ emit_move_insn (target, const0_rtx);
+ emit_jump_insn (gen_jump (lab2));
+ emit_barrier ();
+ emit_label (lab1);
+
+ /* Note that setjmp clobbers FP when we get here, so we have to make
+ sure it's marked as used by this function. */
+ emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
+
+ /* Mark the static chain as clobbered here so life information
+ doesn't get messed up for it. */
+ emit_insn (gen_rtx (CLOBBER, VOIDmode, static_chain_rtx));
+
+ /* Now put in the code to restore the frame pointer, and argument
+ pointer, if needed. The code below is from expand_end_bindings
+ in stmt.c; see detailed documentation there. */
+#ifdef HAVE_nonlocal_goto
+ if (! HAVE_nonlocal_goto)
+#endif
+ emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
+
+ /* Do we need to do something like:
+
+ current_function_has_nonlocal_label = 1;
+
+ here? It seems like we might have to, or some subset of that
+ functionality, but I am unsure. (mrs) */
+
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ if (fixed_regs[ARG_POINTER_REGNUM])
+ {
+#ifdef ELIMINABLE_REGS
+ static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+
+ for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+ if (elim_regs[i].from == ARG_POINTER_REGNUM
+ && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+ break;
+
+ if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+ {
+ /* Now restore our arg pointer from the address at which it
+ was saved in our stack frame.
+ If there hasn't be space allocated for it yet, make
+ some now. */
+ if (arg_pointer_save_area == 0)
+ arg_pointer_save_area
+ = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+ emit_move_insn (virtual_incoming_args_rtx,
+ copy_to_reg (arg_pointer_save_area));
+ }
+ }
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+ /* The static chain pointer contains the address of dummy function.
+ We need to call it here to handle some PIC cases of restoring a
+ global pointer. Then return 1. */
+ op0 = copy_to_mode_reg (Pmode, static_chain_rtx);
+
+ /* We can't actually call emit_library_call here, so do everything
+ it does, which isn't much for a libfunc with no args. */
+ op0 = memory_address (FUNCTION_MODE, op0);
+
+ INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE,
+ gen_rtx (SYMBOL_REF, Pmode, "__dummy"), 1);
+ next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
+
+#ifndef ACCUMULATE_OUTGOING_ARGS
+#ifdef HAVE_call_pop
+ if (HAVE_call_pop)
+ emit_call_insn (gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, op0),
+ const0_rtx, next_arg_reg,
+ GEN_INT (return_pops)));
+ else
+#endif
+#endif
+
+#ifdef HAVE_call
+ if (HAVE_call)
+ emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, op0),
+ const0_rtx, next_arg_reg, const0_rtx));
+ else
+#endif
+ abort ();
+
+ emit_move_insn (target, const1_rtx);
+ emit_label (lab2);
+ return target;
+}
+
\f
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
if (arglist == 0)
/* Warning about missing arg was already issued. */
return const0_rtx;
- else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST)
- {
- error ("invalid arg to `__builtin_return_address'");
- return const0_rtx;
- }
- else if (tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
+ else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST
+ || tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
{
- error ("invalid arg to `__builtin_return_address'");
+ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
+ error ("invalid arg to `__builtin_frame_address'");
+ else
+ error ("invalid arg to `__builtin_return_address'");
return const0_rtx;
}
else
break;
#endif
- /* __builtin_setjmp is passed a pointer to an array of five words
- (not all will be used on all machines). It operates similarly to
- the C library function of the same name, but is more efficient.
- Much of the code below (and for longjmp) is copied from the handling
- of non-local gotos.
-
- NOTE: This is intended for use by GNAT and will only work in
- the method used by it. This code will likely NOT survive to
- the GCC 2.8.0 release. */
case BUILT_IN_SETJMP:
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
{
rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
VOIDmode, 0);
- rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
- enum machine_mode sa_mode = Pmode;
- rtx stack_save;
- int old_inhibit_defer_pop = inhibit_defer_pop;
- int return_pops
- = RETURN_POPS_ARGS (get_identifier ("__dummy"),
- build_function_type (void_type_node, NULL_TREE),
- 0);
- rtx next_arg_reg;
- CUMULATIVE_ARGS args_so_far;
- int i;
-
-#ifdef POINTERS_EXTEND_UNSIGNED
- buf_addr = convert_memory_address (Pmode, buf_addr);
-#endif
-
- buf_addr = force_reg (Pmode, buf_addr);
-
- if (target == 0 || GET_CODE (target) != REG
- || REGNO (target) < FIRST_PSEUDO_REGISTER)
- target = gen_reg_rtx (value_mode);
-
- emit_queue ();
-
- CONST_CALL_P (emit_note (NULL_PTR, NOTE_INSN_SETJMP)) = 1;
- current_function_calls_setjmp = 1;
-
- /* We store the frame pointer and the address of lab1 in the buffer
- and use the rest of it for the stack save area, which is
- machine-dependent. */
- emit_move_insn (gen_rtx (MEM, Pmode, buf_addr),
- virtual_stack_vars_rtx);
- emit_move_insn
- (validize_mem (gen_rtx (MEM, Pmode,
- plus_constant (buf_addr,
- GET_MODE_SIZE (Pmode)))),
- gen_rtx (LABEL_REF, Pmode, lab1));
-
-#ifdef HAVE_save_stack_nonlocal
- if (HAVE_save_stack_nonlocal)
- sa_mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
-#endif
-
- stack_save = gen_rtx (MEM, sa_mode,
- plus_constant (buf_addr,
- 2 * GET_MODE_SIZE (Pmode)));
- emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
-
-#ifdef HAVE_setjmp
- if (HAVE_setjmp)
- emit_insn (gen_setjmp ());
-#endif
-
- /* Set TARGET to zero and branch around the other case. */
- emit_move_insn (target, const0_rtx);
- emit_jump_insn (gen_jump (lab2));
- emit_barrier ();
- emit_label (lab1);
-
- /* Note that setjmp clobbers FP when we get here, so we have to
- make sure it's marked as used by this function. */
- emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
-
- /* Mark the static chain as clobbered here so life information
- doesn't get messed up for it. */
- emit_insn (gen_rtx (CLOBBER, VOIDmode, static_chain_rtx));
-
- /* Now put in the code to restore the frame pointer, and argument
- pointer, if needed. The code below is from expand_end_bindings
- in stmt.c; see detailed documentation there. */
-#ifdef HAVE_nonlocal_goto
- if (! HAVE_nonlocal_goto)
-#endif
- emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
-
- current_function_has_nonlocal_goto = 1;
-
-#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- if (fixed_regs[ARG_POINTER_REGNUM])
- {
-#ifdef ELIMINABLE_REGS
- static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
-
- for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
- if (elim_regs[i].from == ARG_POINTER_REGNUM
- && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
- break;
-
- if (i == sizeof elim_regs / sizeof elim_regs [0])
-#endif
- {
- /* Now restore our arg pointer from the address at which it
- was saved in our stack frame.
- If there hasn't be space allocated for it yet, make
- some now. */
- if (arg_pointer_save_area == 0)
- arg_pointer_save_area
- = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
- emit_move_insn (virtual_incoming_args_rtx,
- copy_to_reg (arg_pointer_save_area));
- }
- }
-#endif
-
-#ifdef HAVE_nonlocal_goto_receiver
- if (HAVE_nonlocal_goto_receiver)
- emit_insn (gen_nonlocal_goto_receiver ());
-#endif
- /* The static chain pointer contains the address of dummy function.
- We need to call it here to handle some PIC cases of restoring
- a global pointer. Then return 1. */
- op0 = copy_to_mode_reg (Pmode, static_chain_rtx);
-
- /* We can't actually call emit_library_call here, so do everything
- it does, which isn't much for a libfunc with no args. */
- op0 = memory_address (FUNCTION_MODE, op0);
-
- INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE,
- gen_rtx (SYMBOL_REF, Pmode, "__dummy"), 1);
- next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
-
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#ifdef HAVE_call_pop
- if (HAVE_call_pop)
- emit_call_insn (gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, op0),
- const0_rtx, next_arg_reg,
- GEN_INT (return_pops)));
- else
-#endif
-#endif
-
-#ifdef HAVE_call
- if (HAVE_call)
- emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, op0),
- const0_rtx, next_arg_reg, const0_rtx));
- else
-#endif
- abort ();
-
- emit_move_insn (target, const1_rtx);
- emit_label (lab2);
- return target;
+ return expand_builtin_setjmp (buf_addr, target);
}
/* __builtin_longjmp is passed a pointer to an array of five words
pending_stack_adjust = 0;
}
}
-
-/* Defer the expansion all cleanups up to OLD_CLEANUPS.
- Returns the cleanups to be performed. */
-
-static tree
-defer_cleanups_to (old_cleanups)
- tree old_cleanups;
-{
- tree new_cleanups = NULL_TREE;
- tree cleanups = cleanups_this_call;
- tree last = NULL_TREE;
-
- while (cleanups_this_call != old_cleanups)
- {
- expand_eh_region_end (TREE_VALUE (cleanups_this_call));
- last = cleanups_this_call;
- cleanups_this_call = TREE_CHAIN (cleanups_this_call);
- }
-
- if (last)
- {
- /* Remove the list from the chain of cleanups. */
- TREE_CHAIN (last) = NULL_TREE;
-
- /* reverse them so that we can build them in the right order. */
- cleanups = nreverse (cleanups);
-
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- while (cleanups)
- {
- if (new_cleanups)
- new_cleanups = build (COMPOUND_EXPR, TREE_TYPE (new_cleanups),
- TREE_VALUE (cleanups), new_cleanups);
- else
- new_cleanups = TREE_VALUE (cleanups);
-
- cleanups = TREE_CHAIN (cleanups);
- }
-
- pop_obstacks ();
- }
-
- return new_cleanups;
-}
-
-/* Expand all cleanups up to OLD_CLEANUPS.
- Needed here, and also for language-dependent calls. */
-
-void
-expand_cleanups_to (old_cleanups)
- tree old_cleanups;
-{
- while (cleanups_this_call != old_cleanups)
- {
- expand_eh_region_end (TREE_VALUE (cleanups_this_call));
- expand_expr (TREE_VALUE (cleanups_this_call), const0_rtx, VOIDmode, 0);
- cleanups_this_call = TREE_CHAIN (cleanups_this_call);
- }
-}
\f
/* Expand conditional expressions. */
break;
case TRUTH_ANDIF_EXPR:
- {
- rtx seq1, seq2;
- tree cleanups, old_cleanups;
-
- if (if_false_label == 0)
- if_false_label = drop_through_label = gen_label_rtx ();
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
- seq1 = get_insns ();
- end_sequence ();
-
- old_cleanups = cleanups_this_call;
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
- seq2 = get_insns ();
- cleanups = defer_cleanups_to (old_cleanups);
- end_sequence ();
-
- if (cleanups)
- {
- rtx flag = gen_reg_rtx (word_mode);
- tree new_cleanups;
- tree cond;
-
- /* Flag cleanups as not needed. */
- emit_move_insn (flag, const0_rtx);
- emit_insns (seq1);
-
- /* Flag cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- emit_insns (seq2);
-
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- cleanups, integer_zero_node);
- new_cleanups = fold (new_cleanups);
-
- pop_obstacks ();
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- expand_eh_region_start ();
- }
- else
- {
- emit_insns (seq1);
- emit_insns (seq2);
- }
- }
+ if (if_false_label == 0)
+ if_false_label = drop_through_label = gen_label_rtx ();
+ do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
+ start_cleanup_deferal ();
+ do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ end_cleanup_deferal ();
break;
case TRUTH_ORIF_EXPR:
- {
- rtx seq1, seq2;
- tree cleanups, old_cleanups;
-
- if (if_true_label == 0)
- if_true_label = drop_through_label = gen_label_rtx ();
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
- seq1 = get_insns ();
- end_sequence ();
-
- old_cleanups = cleanups_this_call;
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
- seq2 = get_insns ();
- cleanups = defer_cleanups_to (old_cleanups);
- end_sequence ();
-
- if (cleanups)
- {
- rtx flag = gen_reg_rtx (word_mode);
- tree new_cleanups;
- tree cond;
-
- /* Flag cleanups as not needed. */
- emit_move_insn (flag, const0_rtx);
- emit_insns (seq1);
-
- /* Flag cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- emit_insns (seq2);
-
- /* All cleanups must be on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- cleanups, integer_zero_node);
- new_cleanups = fold (new_cleanups);
-
- pop_obstacks ();
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- expand_eh_region_start ();
- }
- else
- {
- emit_insns (seq1);
- emit_insns (seq2);
- }
- }
+ if (if_true_label == 0)
+ if_true_label = drop_through_label = gen_label_rtx ();
+ do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
+ start_cleanup_deferal ();
+ do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ end_cleanup_deferal ();
break;
case COMPOUND_EXPR:
else
{
- rtx seq1, seq2;
- tree cleanups_left_side, cleanups_right_side, old_cleanups;
-
register rtx label1 = gen_label_rtx ();
drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
- /* We need to save the cleanups for the lhs and rhs separately.
- Keep track of the cleanups seen before the lhs. */
- old_cleanups = cleanups_this_call;
- start_sequence ();
+ start_cleanup_deferal ();
/* Now the THEN-expression. */
do_jump (TREE_OPERAND (exp, 1),
if_false_label ? if_false_label : drop_through_label,
/* In case the do_jump just above never jumps. */
do_pending_stack_adjust ();
emit_label (label1);
- seq1 = get_insns ();
- /* Now grab the cleanups for the lhs. */
- cleanups_left_side = defer_cleanups_to (old_cleanups);
- end_sequence ();
- /* And keep track of where we start before the rhs. */
- old_cleanups = cleanups_this_call;
- start_sequence ();
/* Now the ELSE-expression. */
do_jump (TREE_OPERAND (exp, 2),
if_false_label ? if_false_label : drop_through_label,
if_true_label ? if_true_label : drop_through_label);
- seq2 = get_insns ();
- /* Grab the cleanups for the rhs. */
- cleanups_right_side = defer_cleanups_to (old_cleanups);
- end_sequence ();
-
- if (cleanups_left_side || cleanups_right_side)
- {
- /* Make the cleanups for the THEN and ELSE clauses
- conditional based on which half is executed. */
- rtx flag = gen_reg_rtx (word_mode);
- tree new_cleanups;
- tree cond;
-
- /* Set the flag to 0 so that we know we executed the lhs. */
- emit_move_insn (flag, const0_rtx);
- emit_insns (seq1);
-
- /* Set the flag to 1 so that we know we executed the rhs. */
- emit_move_insn (flag, const1_rtx);
- emit_insns (seq2);
-
- /* Make sure the cleanup lives on the function_obstack. */
- push_obstacks_nochange ();
- resume_temporary_allocation ();
-
- /* Now, build up a COND_EXPR that tests the value of the
- flag, and then either do the cleanups for the lhs or the
- rhs. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- cleanups_right_side, cleanups_left_side);
- new_cleanups = fold (new_cleanups);
-
- pop_obstacks ();
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- expand_eh_region_start ();
- }
- else
- {
- /* No cleanups were needed, so emit the two sequences
- directly. */
- emit_insns (seq1);
- emit_insns (seq2);
- }
+ end_cleanup_deferal ();
}
break;
else
abort ();
else
- /* See corresponding comment in bc_store_memory(). */
+ /* See corresponding comment in bc_store_memory. */
if (TYPE_MODE (type) == BLKmode
|| TYPE_MODE (type) == VOIDmode)
return;
/* Load: sign-extend if signed, else zero-extend */
bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
-}
+}
/* Adjust interpreter stack by NLEVELS. Positive means drop NLEVELS