* function.h (struct stack_usage): Remove dynamic_alloc_count field.
(current_function_dynamic_alloc_count): Delete.
* builtins.c (expand_builtin_setjmp_setup): Do not set calls_setjmp.
(expand_builtin_nonlocal_goto): Remove obsolete comment.
(expand_builtin_update_setjmp_buf): Remove dead code.
* cse.c (cse_find_path): Do not follow a single abnormal incoming edge.
* explow.c (allocate_dynamic_stack_space): Remove SETJMP_VIA_SAVE_AREA
support.
* function.c (instantiate_virtual_regs): Likewise.
* postreload-gcse.c (bb_has_well_behaved_predecessors): Return false
for a block with a single abnormal incoming edge.
* config/sparc/sparc.h (STACK_SAVEAREA_MODE): Define.
* config/sparc/sparc-protos.h (load_got_register): Declare.
* config/sparc/sparc.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Define.
(load_got_register): Make global.
(sparc_frame_pointer_required): Add 'static'.
(sparc_can_eliminate): Likewise. Call sparc_frame_pointer_required.
(sparc_builtin_setjmp_frame_value): New function.
* config/sparc/sparc.md (UNSPECV_SETJMP): Remove.
(save_stack_nonlocal): New expander.
(restore_stack_nonlocal): Likewise.
(nonlocal_goto): Remove modes, adjust predicates and reimplement.
(nonlocal_goto_internal): New insn.
(goto_handler_and_restore): Delete.
(builtin_setjmp_setup): Likewise.
(do_builtin_setjmp_setup): Likewise.
(setjmp): Likewise.
(builtin_setjmp_receiver): New expander.
From-SVN: r174564
+2011-06-02 Eric Botcazou <ebotcazou@adacore.com>
+
+ * function.h (struct stack_usage): Remove dynamic_alloc_count field.
+ (current_function_dynamic_alloc_count): Delete.
+ * builtins.c (expand_builtin_setjmp_setup): Do not set calls_setjmp.
+ (expand_builtin_nonlocal_goto): Remove obsolete comment.
+ (expand_builtin_update_setjmp_buf): Remove dead code.
+ * cse.c (cse_find_path): Do not follow a single abnormal incoming edge.
+ * explow.c (allocate_dynamic_stack_space): Remove SETJMP_VIA_SAVE_AREA
+ support.
+ * function.c (instantiate_virtual_regs): Likewise.
+ * postreload-gcse.c (bb_has_well_behaved_predecessors): Return false
+ for a block with a single abnormal incoming edge.
+ * config/sparc/sparc.h (STACK_SAVEAREA_MODE): Define.
+ * config/sparc/sparc-protos.h (load_got_register): Declare.
+ * config/sparc/sparc.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Define.
+ (load_got_register): Make global.
+ (sparc_frame_pointer_required): Add 'static'.
+ (sparc_can_eliminate): Likewise. Call sparc_frame_pointer_required.
+ (sparc_builtin_setjmp_frame_value): New function.
+ * config/sparc/sparc.md (UNSPECV_SETJMP): Remove.
+ (save_stack_nonlocal): New expander.
+ (restore_stack_nonlocal): Likewise.
+ (nonlocal_goto): Remove modes, adjust predicates and reimplement.
+ (nonlocal_goto_internal): New insn.
+ (goto_handler_and_restore): Delete.
+ (builtin_setjmp_setup): Likewise.
+ (do_builtin_setjmp_setup): Likewise.
+ (setjmp): Likewise.
+ (builtin_setjmp_receiver): New expander.
+
2011-06-01 David Li <davidxl@google.com>
PR middle-end/49261
emit_insn (gen_builtin_setjmp_setup (buf_addr));
#endif
- /* Tell optimize_save_area_alloca that extra work is going to
- need to go on during alloca. */
- cfun->calls_setjmp = 1;
-
/* We have a nonlocal label. */
cfun->has_nonlocal_label = 1;
}
r_label = convert_memory_address (Pmode, r_label);
r_save_area = expand_normal (t_save_area);
r_save_area = convert_memory_address (Pmode, r_save_area);
- /* Copy the address of the save location to a register just in case it was based
- on the frame pointer. */
+ /* Copy the address of the save location to a register just in case it was
+ based on the frame pointer. */
r_save_area = copy_to_reg (r_save_area);
r_fp = gen_rtx_MEM (Pmode, r_save_area);
r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
- /* Restore frame pointer for containing function.
- This sets the actual hard register used for the frame pointer
- to the location of the function's incoming static chain info.
- The non-local goto handler will then adjust it to contain the
- proper value and reload the argument pointer, if needed. */
+ /* Restore frame pointer for containing function. */
emit_move_insn (hard_frame_pointer_rtx, r_fp);
emit_stack_restore (SAVE_NONLOCAL, r_sp);
static void
expand_builtin_update_setjmp_buf (rtx buf_addr)
{
- enum machine_mode sa_mode = Pmode;
- rtx stack_save;
-
-
-#ifdef HAVE_save_stack_nonlocal
- if (HAVE_save_stack_nonlocal)
- sa_mode = insn_data[(int) CODE_FOR_save_stack_nonlocal].operand[0].mode;
-#endif
-#ifdef STACK_SAVEAREA_MODE
- sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
-#endif
-
- stack_save
+ enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+ rtx stack_save
= gen_rtx_MEM (sa_mode,
memory_address
(sa_mode,
plus_constant (buf_addr, 2 * GET_MODE_SIZE (Pmode))));
-#ifdef HAVE_setjmp
- if (HAVE_setjmp)
- emit_insn (gen_setjmp ());
-#endif
-
emit_stack_save (SAVE_NONLOCAL, &stack_save);
}
extern bool legitimate_pic_operand_p (rtx);
extern rtx sparc_legitimize_reload_address (rtx, enum machine_mode, int, int,
int, int *win);
+extern void load_got_register (void);
extern void sparc_emit_call_insn (rtx, rtx);
extern void sparc_defer_case_vector (rtx, rtx, int);
extern bool sparc_expand_move (enum machine_mode, rtx *);
static int epilogue_renumber (rtx *, int);
static bool sparc_assemble_integer (rtx, unsigned int, int);
static int set_extends (rtx);
-static void load_got_register (void);
static int save_or_restore_regs (int, int, rtx, int, int);
static void emit_save_or_restore_regs (int);
static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
static void sparc_file_end (void);
static bool sparc_frame_pointer_required (void);
static bool sparc_can_eliminate (const int, const int);
+static rtx sparc_builtin_setjmp_frame_value (void);
static void sparc_conditional_register_usage (void);
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
static const char *sparc_mangle_type (const_tree);
#undef TARGET_FRAME_POINTER_REQUIRED
#define TARGET_FRAME_POINTER_REQUIRED sparc_frame_pointer_required
+#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
+#define TARGET_BUILTIN_SETJMP_FRAME_VALUE sparc_builtin_setjmp_frame_value
+
#undef TARGET_CAN_ELIMINATE
#define TARGET_CAN_ELIMINATE sparc_can_eliminate
+
#undef TARGET_PREFERRED_RELOAD_CLASS
#define TARGET_PREFERRED_RELOAD_CLASS sparc_preferred_reload_class
/* Emit code to load the GOT register. */
-static void
+void
load_got_register (void)
{
/* In PIC mode, this will retrieve pic_offset_table_rtx. */
/* Implement TARGET_FRAME_POINTER_REQUIRED. */
-bool
+static bool
sparc_frame_pointer_required (void)
{
return !(current_function_is_leaf && only_leaf_regs_used ());
in that case. But the test in update_eliminables doesn't know we are
assuming below that we only do the former elimination. */
-bool
+static bool
sparc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
{
- return (to == HARD_FRAME_POINTER_REGNUM
- || !targetm.frame_pointer_required ());
+ return to == HARD_FRAME_POINTER_REGNUM || !sparc_frame_pointer_required ();
+}
+
+/* Return the hard frame pointer directly to bypass the stack bias. */
+
+static rtx
+sparc_builtin_setjmp_frame_value (void)
+{
+ return hard_frame_pointer_rtx;
}
/* If !TARGET_FPU, then make the fp registers and fp cc regs fixed so that
#define EPILOGUE_USES(REGNO) ((REGNO) == 31 \
|| (crtl->calls_eh_return && (REGNO) == 1))
\f
+/* We need 2 words, so we can save the stack pointer and the return register
+ of the function containing a non-local goto target. */
+
+#define STACK_SAVEAREA_MODE(LEVEL) \
+ ((LEVEL) == SAVE_NONLOCAL ? (TARGET_ARCH64 ? TImode : DImode) : Pmode)
+
/* Length in units of the trampoline for entering a nested function. */
#define TRAMPOLINE_SIZE (TARGET_ARCH64 ? 32 : 16)
-#define TRAMPOLINE_ALIGNMENT 128 /* 16 bytes */
+/* Alignment required for trampolines, in bits. */
+
+#define TRAMPOLINE_ALIGNMENT 128
\f
/* Generate RTL to flush the register windows so as to make arbitrary frames
available. */
;; Machine description for SPARC chip for GCC
;; Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-;; Free Software Foundation, Inc.
+;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+;; 2011 Free Software Foundation, Inc.
;; Contributed by Michael Tiemann (tiemann@cygnus.com)
;; 64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
;; at Cygnus Support.
(UNSPECV_FLUSHW 1)
(UNSPECV_GOTO 2)
(UNSPECV_FLUSH 4)
- (UNSPECV_SETJMP 5)
(UNSPECV_SAVEW 6)
(UNSPECV_CAS 8)
(UNSPECV_SWAP 9)
"jmp\t%a0%#"
[(set_attr "type" "uncond_branch")])
+(define_expand "save_stack_nonlocal"
+ [(set (match_operand 0 "memory_operand" "")
+ (match_operand 1 "register_operand" ""))
+ (set (match_dup 2) (match_dup 3))]
+ ""
+{
+ operands[0] = adjust_address_nv (operands[0], Pmode, 0);
+ operands[2] = adjust_address_nv (operands[0], Pmode, GET_MODE_SIZE (Pmode));
+ operands[3] = gen_rtx_REG (Pmode, 31); /* %i7 */
+})
+
+(define_expand "restore_stack_nonlocal"
+ [(set (match_operand 0 "register_operand" "")
+ (match_operand 1 "memory_operand" ""))]
+ ""
+{
+ operands[1] = adjust_address_nv (operands[1], Pmode, 0);
+})
+
(define_expand "nonlocal_goto"
- [(match_operand:SI 0 "general_operand" "")
- (match_operand:SI 1 "general_operand" "")
- (match_operand:SI 2 "general_operand" "")
- (match_operand:SI 3 "" "")]
+ [(match_operand 0 "general_operand" "")
+ (match_operand 1 "general_operand" "")
+ (match_operand 2 "memory_operand" "")
+ (match_operand 3 "memory_operand" "")]
""
{
- rtx lab = operands[1];
- rtx stack = operands[2];
- rtx fp = operands[3];
- rtx labreg;
+ rtx r_label = copy_to_reg (operands[1]);
+ rtx r_sp = adjust_address_nv (operands[2], Pmode, 0);
+ rtx r_fp = operands[3];
+ rtx r_i7 = adjust_address_nv (operands[2], Pmode, GET_MODE_SIZE (Pmode));
- /* Trap instruction to flush all the register windows. */
+ /* We need to flush all the register windows so that their contents will
+ be re-synchronized by the restore insn of the target function. */
emit_insn (gen_flush_register_windows ());
- /* Load the fp value for the containing fn into %fp. This is needed
- because STACK refers to %fp. Note that virtual register instantiation
- fails if the virtual %fp isn't set from a register. */
- if (GET_CODE (fp) != REG)
- fp = force_reg (Pmode, fp);
- emit_move_insn (virtual_stack_vars_rtx, fp);
-
- /* Find the containing function's current nonlocal goto handler,
- which will do any cleanups and then jump to the label. */
- labreg = gen_rtx_REG (Pmode, 8);
- emit_move_insn (labreg, lab);
+ emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+ emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
- /* Restore %fp from stack pointer value for containing function.
- The restore insn that follows will move this to %sp,
- and reload the appropriate value into %fp. */
- emit_move_insn (hard_frame_pointer_rtx, stack);
+ /* Restore frame pointer for containing function. */
+ emit_move_insn (hard_frame_pointer_rtx, r_fp);
+ emit_stack_restore (SAVE_NONLOCAL, r_sp);
+ /* USE of hard_frame_pointer_rtx added for consistency;
+ not clear if really needed. */
+ emit_use (hard_frame_pointer_rtx);
emit_use (stack_pointer_rtx);
- /* ??? The V9-specific version was disabled in rev 1.65. */
- emit_jump_insn (gen_goto_handler_and_restore (labreg));
+ /* We need to smuggle the load of %i7 as it is a fixed register. */
+ emit_jump_insn (gen_nonlocal_goto_internal (r_label, r_i7));
emit_barrier ();
DONE;
})
-;; Special trap insn to flush register windows.
-(define_insn "flush_register_windows"
- [(unspec_volatile [(const_int 0)] UNSPECV_FLUSHW)]
- ""
- { return TARGET_V9 ? "flushw" : "ta\t3"; }
- [(set_attr "type" "flushw")])
-
-(define_insn "goto_handler_and_restore"
- [(unspec_volatile [(match_operand 0 "register_operand" "=r")] UNSPECV_GOTO)]
- "GET_MODE (operands[0]) == Pmode"
+(define_insn "nonlocal_goto_internal"
+ [(unspec_volatile [(match_operand 0 "register_operand" "r")
+ (match_operand 1 "memory_operand" "m")] UNSPECV_GOTO)]
+ "GET_MODE (operands[0]) == Pmode && GET_MODE (operands[1]) == Pmode"
{
if (flag_delayed_branch)
- return "jmp\t%0\n\t restore";
+ {
+ if (TARGET_ARCH64)
+ return "jmp\t%0\n\t ldx\t%1, %%i7";
+ else
+ return "jmp\t%0\n\t ld\t%1, %%i7";
+ }
else
- return "mov\t%0,%%g1\n\trestore\n\tjmp\t%%g1\n\t nop";
+ {
+ if (TARGET_ARCH64)
+ return "ldx\t%1, %%i7\n\tjmp\t%0\n\t nop";
+ else
+ return "ld\t%1, %%i7\n\tjmp\t%0\n\t nop";
+ }
}
[(set (attr "type") (const_string "multi"))
(set (attr "length")
(if_then_else (eq_attr "delayed_branch" "true")
(const_int 2)
- (const_int 4)))])
+ (const_int 3)))])
-;; For __builtin_setjmp we need to flush register windows iff the function
-;; calls alloca as well, because otherwise the current register window might
-;; be saved after the %sp adjustment and thus setjmp would crash.
-(define_expand "builtin_setjmp_setup"
- [(match_operand 0 "register_operand" "r")]
- ""
+(define_expand "builtin_setjmp_receiver"
+ [(label_ref (match_operand 0 "" ""))]
+ "flag_pic"
{
- emit_insn (gen_do_builtin_setjmp_setup ());
+ load_got_register ();
DONE;
})
-(define_insn "do_builtin_setjmp_setup"
- [(unspec_volatile [(const_int 0)] UNSPECV_SETJMP)]
- ""
-{
- if (!cfun->calls_alloca)
- return "";
- if (!TARGET_V9)
- return "ta\t3";
- fputs ("\tflushw\n", asm_out_file);
- if (flag_pic)
- fprintf (asm_out_file, "\tst%c\t%%l7, [%%sp+%d]\n",
- TARGET_ARCH64 ? 'x' : 'w',
- SPARC_STACK_BIAS + 7 * UNITS_PER_WORD);
- fprintf (asm_out_file, "\tst%c\t%%fp, [%%sp+%d]\n",
- TARGET_ARCH64 ? 'x' : 'w',
- SPARC_STACK_BIAS + 14 * UNITS_PER_WORD);
- fprintf (asm_out_file, "\tst%c\t%%i7, [%%sp+%d]\n",
- TARGET_ARCH64 ? 'x' : 'w',
- SPARC_STACK_BIAS + 15 * UNITS_PER_WORD);
- return "";
-}
- [(set_attr "type" "multi")
- (set (attr "length")
- (cond [(eq_attr "calls_alloca" "false")
- (const_int 0)
- (eq_attr "isa" "!v9")
- (const_int 1)
- (eq_attr "pic" "true")
- (const_int 4)] (const_int 3)))])
-
-;; Pattern for use after a setjmp to store registers into the save area.
+;; Special insn to flush register windows.
-(define_expand "setjmp"
- [(const_int 0)]
+(define_insn "flush_register_windows"
+ [(unspec_volatile [(const_int 0)] UNSPECV_FLUSHW)]
""
-{
- rtx mem;
-
- if (flag_pic)
- {
- mem = gen_rtx_MEM (Pmode,
- plus_constant (stack_pointer_rtx,
- SPARC_STACK_BIAS + 7 * UNITS_PER_WORD));
- emit_insn (gen_rtx_SET (VOIDmode, mem, pic_offset_table_rtx));
- }
-
- mem = gen_rtx_MEM (Pmode,
- plus_constant (stack_pointer_rtx,
- SPARC_STACK_BIAS + 14 * UNITS_PER_WORD));
- emit_insn (gen_rtx_SET (VOIDmode, mem, hard_frame_pointer_rtx));
-
- mem = gen_rtx_MEM (Pmode,
- plus_constant (stack_pointer_rtx,
- SPARC_STACK_BIAS + 15 * UNITS_PER_WORD));
- emit_insn (gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (Pmode, 31)));
- DONE;
-})
+ { return TARGET_V9 ? "flushw" : "ta\t3"; }
+ [(set_attr "type" "flushw")])
;; Special pattern for the FLUSH instruction.
/* Common subexpression elimination for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ 2011 Free Software Foundation, Inc.
This file is part of GCC.
else
e = NULL;
- if (e && e->dest != EXIT_BLOCK_PTR
+ if (e
+ && (e->flags & EDGE_ABNORMAL) == 0
+ && e->dest != EXIT_BLOCK_PTR
&& single_pred_p (e->dest)
/* Avoid visiting basic blocks twice. The large comment
above explains why this can happen. */
/* Subroutines for manipulating rtx's in semantically interesting ways.
- Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 1987, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
size_align = extra_align;
}
-#ifdef SETJMP_VIA_SAVE_AREA
- /* If setjmp restores regs from a save area in the stack frame,
- avoid clobbering the reg save area. Note that the offset of
- virtual_incoming_args_rtx includes the preallocated stack args space.
- It would be no problem to clobber that, but it's on the wrong side
- of the old save area.
-
- What used to happen is that, since we did not know for sure
- whether setjmp() was invoked until after RTL generation, we
- would use reg notes to store the "optimized" size and fix things
- up later. These days we know this information before we ever
- start building RTL so the reg notes are unnecessary. */
- if (cfun->calls_setjmp)
- {
- rtx dynamic_offset
- = expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
- stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
- size = expand_binop (Pmode, add_optab, size, dynamic_offset,
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
-
- /* The above dynamic offset cannot be computed statically at this
- point, but it will be possible to do so after RTL expansion is
- done. Record how many times we will need to add it. */
- if (flag_stack_usage_info)
- current_function_dynamic_alloc_count++;
-
- /* ??? Can we infer a minimum of STACK_BOUNDARY here? */
- size_align = BITS_PER_UNIT;
- }
-#endif /* SETJMP_VIA_SAVE_AREA */
-
/* Round the size to a multiple of the required stack alignment.
Since the stack if presumed to be rounded before this allocation,
this will maintain the required alignment.
frame_pointer_rtx. */
virtuals_instantiated = 1;
- /* See allocate_dynamic_stack_space for the rationale. */
-#ifdef SETJMP_VIA_SAVE_AREA
- if (flag_stack_usage_info && cfun->calls_setjmp)
- {
- int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
- dynamic_offset = (dynamic_offset + align - 1) / align * align;
- current_function_dynamic_stack_size
- += current_function_dynamic_alloc_count * dynamic_offset;
- }
-#endif
-
return 0;
}
/* Structure for saving state for a nested function.
Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
!ACCUMULATE_OUTGOING_ARGS, it contains the outgoing arguments. */
int pushed_stack_size;
- /* # of dynamic allocations in the function. */
- unsigned int dynamic_alloc_count : 31;
-
/* Nonzero if the amount of stack space allocated dynamically cannot
be bounded at compile-time. */
unsigned int has_unbounded_dynamic_stack_size : 1;
#define current_function_static_stack_size (cfun->su->static_stack_size)
#define current_function_dynamic_stack_size (cfun->su->dynamic_stack_size)
#define current_function_pushed_stack_size (cfun->su->pushed_stack_size)
-#define current_function_dynamic_alloc_count (cfun->su->dynamic_alloc_count)
#define current_function_has_unbounded_dynamic_stack_size \
(cfun->su->has_unbounded_dynamic_stack_size)
#define current_function_allocates_dynamic_stack_space \
/* Post reload partially redundant load elimination
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010
+ Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
static bool
bb_has_well_behaved_predecessors (basic_block bb)
{
+ unsigned int edge_count = EDGE_COUNT (bb->preds);
edge pred;
edge_iterator ei;
- if (EDGE_COUNT (bb->preds) == 0)
+ if (edge_count == 0
+ || (edge_count == 1 && (single_pred_edge (bb)->flags & EDGE_ABNORMAL)))
return false;
FOR_EACH_EDGE (pred, ei, bb->preds)