diff options
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/sparc/sparc-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 23 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.h | 10 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 171 |
4 files changed, 94 insertions, 111 deletions
diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index c1bbab7..ccf1657 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -60,6 +60,7 @@ extern bool constant_address_p (rtx); 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 *); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index d65ced0..d5d043d 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -387,7 +387,6 @@ static rtx sparc_builtin_saveregs (void); 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); @@ -464,6 +463,7 @@ static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; 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); @@ -650,8 +650,12 @@ static const struct default_options sparc_option_optimization_table[] = #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 @@ -3770,7 +3774,7 @@ gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3) /* Emit code to load the GOT register. */ -static void +void load_got_register (void) { /* In PIC mode, this will retrieve pic_offset_table_rtx. */ @@ -9801,7 +9805,7 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) /* Implement TARGET_FRAME_POINTER_REQUIRED. */ -bool +static bool sparc_frame_pointer_required (void) { return !(current_function_is_leaf && only_leaf_regs_used ()); @@ -9812,11 +9816,18 @@ sparc_frame_pointer_required (void) 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 diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index ad354e8..67189ec 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -1384,11 +1384,19 @@ do { \ #define EPILOGUE_USES(REGNO) ((REGNO) == 31 \ || (crtl->calls_eh_return && (REGNO) == 1)) +/* 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 /* Generate RTL to flush the register windows so as to make arbitrary frames available. */ diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 5e16179..e6342ec 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -1,7 +1,7 @@ ;; 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. @@ -70,7 +70,6 @@ (UNSPECV_FLUSHW 1) (UNSPECV_GOTO 2) (UNSPECV_FLUSH 4) - (UNSPECV_SETJMP 5) (UNSPECV_SAVEW 6) (UNSPECV_CAS 8) (UNSPECV_SWAP 9) @@ -6444,136 +6443,100 @@ "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. |