From 4ed6720543e21d4bbd1576549d01407dec870864 Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Sat, 27 Jan 1996 07:57:21 -0500 Subject: [PATCH] Include hard-reg-set.h. (arg_pointer_save_area): New declaration. (expand_builtin, case BUILT_IN_{SET,LONG}JMP): New cases. (expand_expr, case COMPONENT_REF): Pass EXPAND_INITIALIZER to recursive call. From-SVN: r11112 --- gcc/expr.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 2 deletions(-) diff --git a/gcc/expr.c b/gcc/expr.c index be7c78ccb7e..2fe100c73ec 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA. */ #include "obstack.h" #include "flags.h" #include "regs.h" +#include "hard-reg-set.h" #include "function.h" #include "insn-flags.h" #include "insn-codes.h" @@ -153,7 +154,7 @@ extern int local_vars_size; extern int stack_depth; extern int max_stack_depth; extern struct obstack permanent_obstack; - +extern rtx arg_pointer_save_area; static rtx enqueue_insn PROTO((rtx, rtx)); static int queued_subexp_p PROTO((rtx)); @@ -5280,7 +5281,8 @@ expand_expr (exp, target, tmode, modifier) && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) != INTEGER_CST) ? target : NULL_RTX), - VOIDmode, 0); + VOIDmode, + modifier == EXPAND_INITIALIZER ? modifier : 0); /* If this is a constant, put it into a register if it is a legitimate constant and memory if it isn't. */ @@ -8492,6 +8494,161 @@ expand_builtin (exp, target, subtarget, mode, ignore) 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) + break; + + { + rtx buf_addr + = force_reg (Pmode, 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; + + if (target == 0 || GET_CODE (target) != REG + || REGNO (target) < FIRST_PSEUDO_REGISTER) + target = gen_reg_rtx (value_mode); + + emit_queue (); + + emit_note (NULL_PTR, NOTE_INSN_SETJMP); + 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); + + /* 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); + + /* 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); + +#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; + int i; + + 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 + + /* The result to return is in the static chain pointer. */ + if (GET_MODE (static_chain_rtx) == GET_MODE (target)) + emit_move_insn (target, static_chain_rtx); + else + convert_move (target, static_chain_rtx, 0); + + emit_label (lab2); + return target; + } + + /* __builtin_longjmp is passed a pointer to an array of five words + and a value to return. It's similar to the C library longjmp + function but works with __builtin_setjmp above. */ + case BUILT_IN_LONGJMP: + if (arglist == 0 || TREE_CHAIN (arglist) == 0 + || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE) + break; + + { + rtx buf_addr + = force_reg (Pmode, expand_expr (TREE_VALUE (arglist), NULL_RTX, + VOIDmode, 0)); + rtx fp = gen_rtx (MEM, Pmode, buf_addr); + rtx lab = gen_rtx (MEM, Pmode, + plus_constant (buf_addr, GET_MODE_SIZE (Pmode))); + enum machine_mode sa_mode +#ifdef HAVE_save_stack_nonlocal + = (HAVE_save_stack_nonlocal + ? insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0] + : Pmode); +#else + = Pmode; +#endif + rtx stack = gen_rtx (MEM, sa_mode, + plus_constant (buf_addr, + 2 * GET_MODE_SIZE (Pmode))); + rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), NULL_RTX, + VOIDmode, 0); + + /* Pick up FP, label, and SP from the block and jump. This code is + from expand_goto in stmt.c; see there for detailed comments. */ +#if HAVE_nonlocal_goto + if (HAVE_nonlocal_goto) + emit_insn (gen_nonlocal_goto (fp, lab, stack, value)); + else +#endif + { + emit_move_insn (hard_frame_pointer_rtx, fp); + emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); + + /* Put in the static chain register the return value. */ + emit_move_insn (static_chain_rtx, value); + emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx)); + emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); + emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx)); + emit_indirect_jump (copy_to_reg (lab)); + } + + return const0_rtx; + } + default: /* just do library call, if unknown builtin */ error ("built-in function `%s' not currently supported", IDENTIFIER_POINTER (DECL_NAME (fndecl))); -- 2.30.2