Commit b11b0904 by Eric Botcazou Committed by Eric Botcazou

invoke.texi (SPARC options): Add -mflat.

gcc/
	* doc/invoke.texi (SPARC options): Add -mflat.
	* config/sparc/sparc.opt: Likewise.
	* config/sparc/sparc-protos.h (sparc_expand_epilogue): Add parameter.
	(sparc_flat_expand_prologue): Declare.
	(sparc_flat_expand_epilogue): Likewise.
	* config/sparc/sparc.h (CPP_CPU_SPEC): Do not handle -msoft-float.
	(CPP_ENDIAN_SPEC): Replace with...
	(CPP_OTHER_SPEC): ...this.  Also handle -mflat and -msoft-float.
	(CPP_SPEC): Adjust to above change.
	(EXTRA_SPECS): Likewise.
	(SPARC_INCOMING_INT_ARG_FIRST): Add TARGET_FLAT handling.
	(INCOMING_REGNO): Likewise.
	(OUTGOING_REGNO): Likewise.
	(LOCAL_REGNO): Likewise.
	(SETUP_FRAME_ADDRESSES): Likewise.
	(FIXED_REGISTERS): Set 0 for %fp.
	(CALL_USED_REGISTERS): Likewise.
	(INITIAL_ELIMINATION_OFFSET): Pass current_function_is_leaf.
	(EXIT_IGNORE_STACK): Define to 1 unconditionally.
	(RETURN_ADDR_REGNUM): Define.
	(RETURN_ADDR_RTX): Use it.
	(INCOMING_RETURN_ADDR_REGNUM): Define.
	(INCOMING_RETURN_ADDR_RTX): Use it.
	(DWARF_FRAME_RETURN_COLUMN): Likewise.
	(EH_RETURN_REGNUM): Define.
	(EH_RETURN_STACKADJ_RTX): Use it.
	(EH_RETURN_HANDLER_RTX): Delete.
	(EPILOGUE_USES): Use them and add TARGET_FLAT handling.
	* config/sparc/sparc.c (apparent_fsize, actual_fsize, num_gfregs):
	Delete.
	(struct machine_function): Add frame_size, apparent_frame_size,
	frame_base_reg, frame_base_offset, n_global_fp_regs and
	save_local_in_regs_p fields.
	(sparc_frame_size, sparc_apparent_frame_size, sparc_frame_base_reg,
	sparc_frame_base_offset, sparc_n_global_fp_regs,
	sparc_save_local_in_regs_p): New macros.
	(sparc_option_override): Error out if -fcall-saved-REG is specified
	for Out registers.
	(eligible_for_restore_insn): Fix formatting.
	(eligible_for_return_delay): Likewise.  Add TARGET_FLAT handling.
	(eligible_for_sibcall_delay): Likewise.
	(RTX_OK_FOR_OFFSET_P, RTX_OK_FOR_OLO10_P): Add MODE parameter.
	(sparc_legitimate_address_p): Adjust to above change.
	(save_global_or_fp_reg_p): New predicate.
	(return_addr_reg_needed_p): Likewise.
	(save_local_or_in_reg_p): Likewise.
	(sparc_compute_frame_size): Use them.  Add TARGET_FLAT handling.
	(SORR_SAVE, SORR_RESTORE): Delete.
	(sorr_pred_t): New typedef.
	(sorr_act_t): New enum.
	(save_or_restore_regs): Rename to...
	(emit_save_or_restore_regs): ...this.  Change type of LOW and HIGH
	parameters, remove ACTION parameter, add LEAF_FUNCTION_P, SAVE_P,
	ACTION_TRUE and ACTION_FALSE parameters.  Implement more general
	mechanism.  Add CFI information for double-word saves in 32-bit mode.
	(emit_adjust_base_to_offset): New function extracted from...
	(emit_save_or_restore_regs): ...this.  Rename the rest to...
	(emit_save_or_restore_regs_global_fp_regs): ...this.
	(emit_save_or_restore_regs_local_in_regs): New function.
	(gen_create_flat_frame_[123]): New functions.
	(sparc_expand_prologue): Use SIZE local variable.  Adjust.
	(sparc_flat_expand_prologue): New function.
	(sparc_asm_function_prologue): Add TARGET_FLAT handling.
	(sparc_expand_epilogue): Use SIZE local variable.  Adjust.
	(sparc_flat_expand_epilogue): New function.
	(sparc_can_use_return_insn_p): Add TARGET_FLAT handling.
	(output_return): Likewise.
	(output_sibcall): Likewise.
	(sparc_output_mi_thunk): Likewise.
	(sparc_frame_pointer_required): Likewise.
	(sparc_conditional_register_usage): If TARGET_FLAT, disable the leaf
	function optimization.
	* config/sparc/sparc.md (flat): New attribute.
	(prologue): Add TARGET_FLAT handling.
	(save_register_window): Disable if TARGET_FLAT.
	(create_flat_frame_[123]): New patterns.
	(epilogue): Add TARGET_FLAT handling.
	(sibcall_epilogue): Likewise.
	(eh_return): New expander.
	(eh_return_internal): New insn and splitter.
	(return_internal): Add TARGET_FLAT handling.
	(untyped_return): Remove bogus test and use RETURN_ADDR_REGNUM.
	(save_stack_nonlocal): Use RETURN_ADDR_REGNUM.
	(nonlocal_goto): Add TARGET_FLAT handling.
	* config/sparc/t-elf: Add -mflat multilib.
	* config/sparc/t-leon: Likewise.
libgcc/
	* config/sparc/linux-unwind.h (STACK_BIAS): Define.
	(sparc64_fallback_frame_state): Use it.
	(sparc64_frob_update_context): Further adjust context.
	* config/sparc/sol2-unwind.h (sparc64_frob_update_context): Likewise.
	* config/sparc/sol2-ci.S: Add TARGET_FLAT handling.
	* config/sparc/sol2-cn.S: Likewise.

Co-Authored-By: Laurent Rougé <laurent.rouge@menta.fr>

From-SVN: r174897
parent f5c01f5b
2011-06-10 Eric Botcazou <ebotcazou@adacore.com>
Laurent Roug <laurent.rouge@menta.fr>
* doc/invoke.texi (SPARC options): Add -mflat.
* config/sparc/sparc.opt: Likewise.
* config/sparc/sparc-protos.h (sparc_expand_epilogue): Add parameter.
(sparc_flat_expand_prologue): Declare.
(sparc_flat_expand_epilogue): Likewise.
* config/sparc/sparc.h (CPP_CPU_SPEC): Do not handle -msoft-float.
(CPP_ENDIAN_SPEC): Replace with...
(CPP_OTHER_SPEC): ...this. Also handle -mflat and -msoft-float.
(CPP_SPEC): Adjust to above change.
(EXTRA_SPECS): Likewise.
(SPARC_INCOMING_INT_ARG_FIRST): Add TARGET_FLAT handling.
(INCOMING_REGNO): Likewise.
(OUTGOING_REGNO): Likewise.
(LOCAL_REGNO): Likewise.
(SETUP_FRAME_ADDRESSES): Likewise.
(FIXED_REGISTERS): Set 0 for %fp.
(CALL_USED_REGISTERS): Likewise.
(INITIAL_ELIMINATION_OFFSET): Pass current_function_is_leaf.
(EXIT_IGNORE_STACK): Define to 1 unconditionally.
(RETURN_ADDR_REGNUM): Define.
(RETURN_ADDR_RTX): Use it.
(INCOMING_RETURN_ADDR_REGNUM): Define.
(INCOMING_RETURN_ADDR_RTX): Use it.
(DWARF_FRAME_RETURN_COLUMN): Likewise.
(EH_RETURN_REGNUM): Define.
(EH_RETURN_STACKADJ_RTX): Use it.
(EH_RETURN_HANDLER_RTX): Delete.
(EPILOGUE_USES): Use them and add TARGET_FLAT handling.
* config/sparc/sparc.c (apparent_fsize, actual_fsize, num_gfregs):
Delete.
(struct machine_function): Add frame_size, apparent_frame_size,
frame_base_reg, frame_base_offset, n_global_fp_regs and
save_local_in_regs_p fields.
(sparc_frame_size, sparc_apparent_frame_size, sparc_frame_base_reg,
sparc_frame_base_offset, sparc_n_global_fp_regs,
sparc_save_local_in_regs_p): New macros.
(sparc_option_override): Error out if -fcall-saved-REG is specified
for Out registers.
(eligible_for_restore_insn): Fix formatting.
(eligible_for_return_delay): Likewise. Add TARGET_FLAT handling.
(eligible_for_sibcall_delay): Likewise.
(RTX_OK_FOR_OFFSET_P, RTX_OK_FOR_OLO10_P): Add MODE parameter.
(sparc_legitimate_address_p): Adjust to above change.
(save_global_or_fp_reg_p): New predicate.
(return_addr_reg_needed_p): Likewise.
(save_local_or_in_reg_p): Likewise.
(sparc_compute_frame_size): Use them. Add TARGET_FLAT handling.
(SORR_SAVE, SORR_RESTORE): Delete.
(sorr_pred_t): New typedef.
(sorr_act_t): New enum.
(save_or_restore_regs): Rename to...
(emit_save_or_restore_regs): ...this. Change type of LOW and HIGH
parameters, remove ACTION parameter, add LEAF_FUNCTION_P, SAVE_P,
ACTION_TRUE and ACTION_FALSE parameters. Implement more general
mechanism. Add CFI information for double-word saves in 32-bit mode.
(emit_adjust_base_to_offset): New function extracted from...
(emit_save_or_restore_regs): ...this. Rename the rest to...
(emit_save_or_restore_regs_global_fp_regs): ...this.
(emit_save_or_restore_regs_local_in_regs): New function.
(gen_create_flat_frame_[123]): New functions.
(sparc_expand_prologue): Use SIZE local variable. Adjust.
(sparc_flat_expand_prologue): New function.
(sparc_asm_function_prologue): Add TARGET_FLAT handling.
(sparc_expand_epilogue): Use SIZE local variable. Adjust.
(sparc_flat_expand_epilogue): New function.
(sparc_can_use_return_insn_p): Add TARGET_FLAT handling.
(output_return): Likewise.
(output_sibcall): Likewise.
(sparc_output_mi_thunk): Likewise.
(sparc_frame_pointer_required): Likewise.
(sparc_conditional_register_usage): If TARGET_FLAT, disable the leaf
function optimization.
* config/sparc/sparc.md (flat): New attribute.
(prologue): Add TARGET_FLAT handling.
(save_register_window): Disable if TARGET_FLAT.
(create_flat_frame_[123]): New patterns.
(epilogue): Add TARGET_FLAT handling.
(sibcall_epilogue): Likewise.
(eh_return): New expander.
(eh_return_internal): New insn and splitter.
(return_internal): Add TARGET_FLAT handling.
(untyped_return): Remove bogus test and use RETURN_ADDR_REGNUM.
(save_stack_nonlocal): Use RETURN_ADDR_REGNUM.
(nonlocal_goto): Add TARGET_FLAT handling.
* config/sparc/t-elf: Add -mflat multilib.
* config/sparc/t-leon: Likewise.
2011-06-10 Jan Hubicka <jh@suse.cz> 2011-06-10 Jan Hubicka <jh@suse.cz>
* ipa-utils.c (searchc): Use cgraph_function_or_thunk_node. * ipa-utils.c (searchc): Use cgraph_function_or_thunk_node.
......
...@@ -38,7 +38,9 @@ extern enum direction function_arg_padding (enum machine_mode, const_tree); ...@@ -38,7 +38,9 @@ extern enum direction function_arg_padding (enum machine_mode, const_tree);
extern void order_regs_for_local_alloc (void); extern void order_regs_for_local_alloc (void);
extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int); extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int);
extern void sparc_expand_prologue (void); extern void sparc_expand_prologue (void);
extern void sparc_expand_epilogue (void); extern void sparc_flat_expand_prologue (void);
extern void sparc_expand_epilogue (bool);
extern void sparc_flat_expand_epilogue (bool);
extern bool sparc_can_use_return_insn_p (void); extern bool sparc_can_use_return_insn_p (void);
extern int check_pic (int); extern int check_pic (int);
extern int short_branch (int, int); extern int short_branch (int, int);
......
...@@ -287,21 +287,6 @@ const struct processor_costs *sparc_costs = &cypress_costs; ...@@ -287,21 +287,6 @@ const struct processor_costs *sparc_costs = &cypress_costs;
((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic) ((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic)
#endif #endif
/* Global variables for machine-dependent things. */
/* Size of frame. Need to know this to emit return insns from leaf procedures.
ACTUAL_FSIZE is set by sparc_compute_frame_size() which is called during the
reload pass. This is important as the value is later used for scheduling
(to see what can go in a delay slot).
APPARENT_FSIZE is the size of the stack less the register save area and less
the outgoing argument area. It is used when saving call preserved regs. */
static HOST_WIDE_INT apparent_fsize;
static HOST_WIDE_INT actual_fsize;
/* Number of live general or floating point registers needed to be
saved (as 4-byte quantities). */
static int num_gfregs;
/* Vector to say how input registers are mapped to output registers. /* Vector to say how input registers are mapped to output registers.
HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
eliminate it. You must use -fomit-frame-pointer to get that. */ eliminate it. You must use -fomit-frame-pointer to get that. */
...@@ -341,28 +326,46 @@ char sparc_leaf_regs[] = ...@@ -341,28 +326,46 @@ char sparc_leaf_regs[] =
struct GTY(()) machine_function struct GTY(()) machine_function
{ {
/* Size of the frame of the function. */
HOST_WIDE_INT frame_size;
/* Size of the frame of the function minus the register window save area
and the outgoing argument area. */
HOST_WIDE_INT apparent_frame_size;
/* Register we pretend the frame pointer is allocated to. Normally, this
is %fp, but if we are in a leaf procedure, this is (%sp + offset). We
record "offset" separately as it may be too big for (reg + disp). */
rtx frame_base_reg;
HOST_WIDE_INT frame_base_offset;
/* Some local-dynamic TLS symbol name. */ /* Some local-dynamic TLS symbol name. */
const char *some_ld_name; const char *some_ld_name;
/* Number of global or FP registers to be saved (as 4-byte quantities). */
int n_global_fp_regs;
/* True if the current function is leaf and uses only leaf regs, /* True if the current function is leaf and uses only leaf regs,
so that the SPARC leaf function optimization can be applied. so that the SPARC leaf function optimization can be applied.
Private version of current_function_uses_only_leaf_regs, see Private version of current_function_uses_only_leaf_regs, see
sparc_expand_prologue for the rationale. */ sparc_expand_prologue for the rationale. */
int leaf_function_p; int leaf_function_p;
/* True if the prologue saves local or in registers. */
bool save_local_in_regs_p;
/* True if the data calculated by sparc_expand_prologue are valid. */ /* True if the data calculated by sparc_expand_prologue are valid. */
bool prologue_data_valid_p; bool prologue_data_valid_p;
}; };
#define sparc_leaf_function_p cfun->machine->leaf_function_p #define sparc_frame_size cfun->machine->frame_size
#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p #define sparc_apparent_frame_size cfun->machine->apparent_frame_size
#define sparc_frame_base_reg cfun->machine->frame_base_reg
/* Register we pretend to think the frame pointer is allocated to. #define sparc_frame_base_offset cfun->machine->frame_base_offset
Normally, this is %fp, but if we are in a leaf procedure, this #define sparc_n_global_fp_regs cfun->machine->n_global_fp_regs
is %sp+"something". We record "something" separately as it may #define sparc_leaf_function_p cfun->machine->leaf_function_p
be too big for reg+constant addressing. */ #define sparc_save_local_in_regs_p cfun->machine->save_local_in_regs_p
static rtx frame_base_reg; #define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p
static HOST_WIDE_INT frame_base_offset;
/* 1 if the next opcode is to be specially indented. */ /* 1 if the next opcode is to be specially indented. */
int sparc_indent_opcode = 0; int sparc_indent_opcode = 0;
...@@ -387,8 +390,6 @@ static rtx sparc_builtin_saveregs (void); ...@@ -387,8 +390,6 @@ static rtx sparc_builtin_saveregs (void);
static int epilogue_renumber (rtx *, int); static int epilogue_renumber (rtx *, int);
static bool sparc_assemble_integer (rtx, unsigned int, int); static bool sparc_assemble_integer (rtx, unsigned int, int);
static int set_extends (rtx); static int set_extends (rtx);
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_asm_function_prologue (FILE *, HOST_WIDE_INT);
static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT); static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
#ifdef TARGET_SOLARIS #ifdef TARGET_SOLARIS
...@@ -764,6 +765,7 @@ sparc_option_override (void) ...@@ -764,6 +765,7 @@ sparc_option_override (void)
{ MASK_ISA, MASK_V9}, { MASK_ISA, MASK_V9},
}; };
const struct cpu_table *cpu; const struct cpu_table *cpu;
unsigned int i;
int fpu; int fpu;
#ifdef SUBTARGET_OVERRIDE_OPTIONS #ifdef SUBTARGET_OVERRIDE_OPTIONS
...@@ -808,6 +810,14 @@ sparc_option_override (void) ...@@ -808,6 +810,14 @@ sparc_option_override (void)
error ("-mcmodel= is not supported on 32 bit systems"); error ("-mcmodel= is not supported on 32 bit systems");
} }
/* Check that -fcall-saved-REG wasn't specified for out registers. */
for (i = 8; i < 16; i++)
if (!call_used_regs [i])
{
error ("-fcall-saved-REG is not supported for out registers");
call_used_regs [i] = 1;
}
fpu = target_flags & MASK_FPU; /* save current -mfpu status */ fpu = target_flags & MASK_FPU; /* save current -mfpu status */
/* Set the default CPU. */ /* Set the default CPU. */
...@@ -2769,9 +2779,11 @@ eligible_for_restore_insn (rtx trial, bool return_p) ...@@ -2769,9 +2779,11 @@ eligible_for_restore_insn (rtx trial, bool return_p)
/* If we have the 'return' instruction, anything that does not use /* If we have the 'return' instruction, anything that does not use
local or output registers and can go into a delay slot wins. */ local or output registers and can go into a delay slot wins. */
else if (return_p && TARGET_V9 && ! epilogue_renumber (&pat, 1) else if (return_p
&& (get_attr_in_uncond_branch_delay (trial) && TARGET_V9
== IN_UNCOND_BRANCH_DELAY_TRUE)) && !epilogue_renumber (&pat, 1)
&& get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE)
return 1; return 1;
/* The 'restore src1,src2,dest' pattern for SImode. */ /* The 'restore src1,src2,dest' pattern for SImode. */
...@@ -2806,8 +2818,7 @@ eligible_for_restore_insn (rtx trial, bool return_p) ...@@ -2806,8 +2818,7 @@ eligible_for_restore_insn (rtx trial, bool return_p)
return 0; return 0;
} }
/* Return nonzero if TRIAL can go into the function return's /* Return nonzero if TRIAL can go into the function return's delay slot. */
delay slot. */
int int
eligible_for_return_delay (rtx trial) eligible_for_return_delay (rtx trial)
...@@ -2825,10 +2836,10 @@ eligible_for_return_delay (rtx trial) ...@@ -2825,10 +2836,10 @@ eligible_for_return_delay (rtx trial)
if (crtl->calls_eh_return) if (crtl->calls_eh_return)
return 0; return 0;
/* In the case of a true leaf function, anything can go into the slot. */ /* In the case of a leaf or flat function, anything can go into the slot. */
if (sparc_leaf_function_p) if (sparc_leaf_function_p || TARGET_FLAT)
return get_attr_in_uncond_branch_delay (trial) return
== IN_UNCOND_BRANCH_DELAY_TRUE; get_attr_in_uncond_branch_delay (trial) == IN_UNCOND_BRANCH_DELAY_TRUE;
pat = PATTERN (trial); pat = PATTERN (trial);
...@@ -2843,15 +2854,14 @@ eligible_for_return_delay (rtx trial) ...@@ -2843,15 +2854,14 @@ eligible_for_return_delay (rtx trial)
with FP_REGS. */ with FP_REGS. */
if (REGNO (SET_DEST (pat)) >= 32) if (REGNO (SET_DEST (pat)) >= 32)
return (TARGET_V9 return (TARGET_V9
&& ! epilogue_renumber (&pat, 1) && !epilogue_renumber (&pat, 1)
&& (get_attr_in_uncond_branch_delay (trial) && get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE)); == IN_UNCOND_BRANCH_DELAY_TRUE);
return eligible_for_restore_insn (trial, true); return eligible_for_restore_insn (trial, true);
} }
/* Return nonzero if TRIAL can go into the sibling call's /* Return nonzero if TRIAL can go into the sibling call's delay slot. */
delay slot. */
int int
eligible_for_sibcall_delay (rtx trial) eligible_for_sibcall_delay (rtx trial)
...@@ -2866,7 +2876,7 @@ eligible_for_sibcall_delay (rtx trial) ...@@ -2866,7 +2876,7 @@ eligible_for_sibcall_delay (rtx trial)
pat = PATTERN (trial); pat = PATTERN (trial);
if (sparc_leaf_function_p) if (sparc_leaf_function_p || TARGET_FLAT)
{ {
/* If the tail call is done using the call instruction, /* If the tail call is done using the call instruction,
we have to restore %o7 in the delay slot. */ we have to restore %o7 in the delay slot. */
...@@ -3117,11 +3127,15 @@ legitimate_pic_operand_p (rtx x) ...@@ -3117,11 +3127,15 @@ legitimate_pic_operand_p (rtx x)
return true; return true;
} }
#define RTX_OK_FOR_OFFSET_P(X) \ #define RTX_OK_FOR_OFFSET_P(X, MODE) \
(CONST_INT_P (X) && INTVAL (X) >= -0x1000 && INTVAL (X) < 0x1000 - 8) (CONST_INT_P (X) \
&& INTVAL (X) >= -0x1000 \
&& INTVAL (X) < (0x1000 - GET_MODE_SIZE (MODE)))
#define RTX_OK_FOR_OLO10_P(X) \ #define RTX_OK_FOR_OLO10_P(X, MODE) \
(CONST_INT_P (X) && INTVAL (X) >= -0x1000 && INTVAL (X) < 0xc00 - 8) (CONST_INT_P (X) \
&& INTVAL (X) >= -0x1000 \
&& INTVAL (X) < (0xc00 - GET_MODE_SIZE (MODE)))
/* Handle the TARGET_LEGITIMATE_ADDRESS_P target hook. /* Handle the TARGET_LEGITIMATE_ADDRESS_P target hook.
...@@ -3163,7 +3177,7 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) ...@@ -3163,7 +3177,7 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
&& (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2))) && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
|| ((REG_P (rs1) || ((REG_P (rs1)
|| GET_CODE (rs1) == SUBREG) || GET_CODE (rs1) == SUBREG)
&& RTX_OK_FOR_OFFSET_P (rs2))) && RTX_OK_FOR_OFFSET_P (rs2, mode)))
{ {
imm1 = rs2; imm1 = rs2;
rs2 = NULL; rs2 = NULL;
...@@ -3193,7 +3207,7 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) ...@@ -3193,7 +3207,7 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
&& GET_CODE (rs1) == LO_SUM && GET_CODE (rs1) == LO_SUM
&& TARGET_ARCH64 && TARGET_ARCH64
&& ! TARGET_CM_MEDMID && ! TARGET_CM_MEDMID
&& RTX_OK_FOR_OLO10_P (rs2)) && RTX_OK_FOR_OLO10_P (rs2, mode))
{ {
rs2 = NULL; rs2 = NULL;
imm1 = XEXP (rs1, 1); imm1 = XEXP (rs1, 1);
...@@ -4104,59 +4118,138 @@ sparc_init_modes (void) ...@@ -4104,59 +4118,138 @@ sparc_init_modes (void)
} }
} }
/* Return whether REGNO, a global or FP register, must be saved/restored. */
static inline bool
save_global_or_fp_reg_p (unsigned int regno,
int leaf_function ATTRIBUTE_UNUSED)
{
return !call_used_regs[regno] && df_regs_ever_live_p (regno);
}
/* Return whether the return address register (%i7) is needed. */
static inline bool
return_addr_reg_needed_p (int leaf_function)
{
/* If it is live, for example because of __builtin_return_address (0). */
if (df_regs_ever_live_p (RETURN_ADDR_REGNUM))
return true;
/* Otherwise, it is needed as save register if %o7 is clobbered. */
if (!leaf_function
/* Loading the GOT register clobbers %o7. */
|| crtl->uses_pic_offset_table
|| df_regs_ever_live_p (INCOMING_RETURN_ADDR_REGNUM))
return true;
return false;
}
/* Return whether REGNO, a local or in register, must be saved/restored. */
static bool
save_local_or_in_reg_p (unsigned int regno, int leaf_function)
{
/* General case: call-saved registers live at some point. */
if (!call_used_regs[regno] && df_regs_ever_live_p (regno))
return true;
/* Frame pointer register (%fp) if needed. */
if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
return true;
/* Return address register (%i7) if needed. */
if (regno == RETURN_ADDR_REGNUM && return_addr_reg_needed_p (leaf_function))
return true;
/* PIC register (%l7) if needed. */
if (regno == PIC_OFFSET_TABLE_REGNUM && crtl->uses_pic_offset_table)
return true;
/* If the function accesses prior frames, the frame pointer and the return
address of the previous frame must be saved on the stack. */
if (crtl->accesses_prior_frames
&& (regno == HARD_FRAME_POINTER_REGNUM || regno == RETURN_ADDR_REGNUM))
return true;
return false;
}
/* Compute the frame size required by the function. This function is called /* Compute the frame size required by the function. This function is called
during the reload pass and also by sparc_expand_prologue. */ during the reload pass and also by sparc_expand_prologue. */
HOST_WIDE_INT HOST_WIDE_INT
sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p) sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function)
{ {
int outgoing_args_size = (crtl->outgoing_args_size HOST_WIDE_INT frame_size, apparent_frame_size;
+ REG_PARM_STACK_SPACE (current_function_decl)); int args_size, n_global_fp_regs = 0;
int n_regs = 0; /* N_REGS is the number of 4-byte regs saved thus far. */ bool save_local_in_regs_p = false;
int i; unsigned int i;
if (TARGET_ARCH64) /* If the function allocates dynamic stack space, the dynamic offset is
{ computed early and contains REG_PARM_STACK_SPACE, so we need to cope. */
for (i = 0; i < 8; i++) if (leaf_function && !cfun->calls_alloca)
if (df_regs_ever_live_p (i) && ! call_used_regs[i]) args_size = 0;
n_regs += 2;
}
else else
{ args_size = crtl->outgoing_args_size + REG_PARM_STACK_SPACE (cfun->decl);
for (i = 0; i < 8; i += 2)
if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
|| (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
n_regs += 2;
}
for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2) /* Calculate space needed for global registers. */
if ((df_regs_ever_live_p (i) && ! call_used_regs[i]) if (TARGET_ARCH64)
|| (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1])) for (i = 0; i < 8; i++)
n_regs += 2; if (save_global_or_fp_reg_p (i, 0))
n_global_fp_regs += 2;
else
for (i = 0; i < 8; i += 2)
if (save_global_or_fp_reg_p (i, 0) || save_global_or_fp_reg_p (i + 1, 0))
n_global_fp_regs += 2;
/* Set up values for use in prologue and epilogue. */ /* In the flat window model, find out which local and in registers need to
num_gfregs = n_regs; be saved. We don't reserve space in the current frame for them as they
will be spilled into the register window save area of the caller's frame.
However, as soon as we use this register window save area, we must create
that of the current frame to make it the live one. */
if (TARGET_FLAT)
for (i = 16; i < 32; i++)
if (save_local_or_in_reg_p (i, leaf_function))
{
save_local_in_regs_p = true;
break;
}
if (leaf_function_p /* Calculate space needed for FP registers. */
&& n_regs == 0 for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
&& size == 0 if (save_global_or_fp_reg_p (i, 0) || save_global_or_fp_reg_p (i + 1, 0))
&& crtl->outgoing_args_size == 0) n_global_fp_regs += 2;
actual_fsize = apparent_fsize = 0;
if (size == 0
&& n_global_fp_regs == 0
&& args_size == 0
&& !save_local_in_regs_p)
frame_size = apparent_frame_size = 0;
else else
{ {
/* We subtract STARTING_FRAME_OFFSET, remember it's negative. */ /* We subtract STARTING_FRAME_OFFSET, remember it's negative. */
apparent_fsize = (size - STARTING_FRAME_OFFSET + 7) & -8; apparent_frame_size = (size - STARTING_FRAME_OFFSET + 7) & -8;
apparent_fsize += n_regs * 4; apparent_frame_size += n_global_fp_regs * 4;
actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8);
/* We need to add the size of the outgoing argument area. */
frame_size = apparent_frame_size + ((args_size + 7) & -8);
/* And that of the register window save area. */
frame_size += FIRST_PARM_OFFSET (cfun->decl);
/* Finally, bump to the appropriate alignment. */
frame_size = SPARC_STACK_ALIGN (frame_size);
} }
/* Make sure nothing can clobber our register windows. /* Set up values for use in prologue and epilogue. */
If a SAVE must be done, or there is a stack-local variable, sparc_frame_size = frame_size;
the register window area must be allocated. */ sparc_apparent_frame_size = apparent_frame_size;
if (! leaf_function_p || size > 0) sparc_n_global_fp_regs = n_global_fp_regs;
actual_fsize += FIRST_PARM_OFFSET (current_function_decl); sparc_save_local_in_regs_p = save_local_in_regs_p;
return SPARC_STACK_ALIGN (actual_fsize); return frame_size;
} }
/* Output any necessary .register pseudo-ops. */ /* Output any necessary .register pseudo-ops. */
...@@ -4342,43 +4435,66 @@ output_probe_stack_range (rtx reg1, rtx reg2) ...@@ -4342,43 +4435,66 @@ output_probe_stack_range (rtx reg1, rtx reg2)
return ""; return "";
} }
/* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET /* Emit code to save/restore registers from LOW to HIGH at BASE+OFFSET as
as needed. LOW should be double-word aligned for 32-bit registers. needed. LOW is supposed to be double-word aligned for 32-bit registers.
Return the new OFFSET. */ SAVE_P decides whether a register must be saved/restored. ACTION_TRUE
is the action to be performed if SAVE_P returns true and ACTION_FALSE
the action to be performed if it returns false. Return the new offset. */
#define SORR_SAVE 0 typedef bool (*sorr_pred_t) (unsigned int, int);
#define SORR_RESTORE 1 typedef enum { SORR_NONE, SORR_ADVANCE, SORR_SAVE, SORR_RESTORE } sorr_act_t;
static int static int
save_or_restore_regs (int low, int high, rtx base, int offset, int action) emit_save_or_restore_regs (unsigned int low, unsigned int high, rtx base,
int offset, int leaf_function, sorr_pred_t save_p,
sorr_act_t action_true, sorr_act_t action_false)
{ {
unsigned int i;
rtx mem, insn; rtx mem, insn;
int i;
if (TARGET_ARCH64 && high <= 32) if (TARGET_ARCH64 && high <= 32)
{ {
int fp_offset = -1;
for (i = low; i < high; i++) for (i = low; i < high; i++)
{ {
if (df_regs_ever_live_p (i) && ! call_used_regs[i]) if (save_p (i, leaf_function))
{ {
mem = gen_frame_mem (DImode, plus_constant (base, offset)); mem = gen_frame_mem (DImode, plus_constant (base, offset));
if (action == SORR_SAVE) if (action_true == SORR_SAVE)
{ {
insn = emit_move_insn (mem, gen_rtx_REG (DImode, i)); insn = emit_move_insn (mem, gen_rtx_REG (DImode, i));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
} }
else /* action == SORR_RESTORE */ else /* action_true == SORR_RESTORE */
emit_move_insn (gen_rtx_REG (DImode, i), mem); {
/* The frame pointer must be restored last since its old
value may be used as base address for the frame. This
is problematic in 64-bit mode only because of the lack
of double-word load instruction. */
if (i == HARD_FRAME_POINTER_REGNUM)
fp_offset = offset;
else
emit_move_insn (gen_rtx_REG (DImode, i), mem);
}
offset += 8; offset += 8;
} }
else if (action_false == SORR_ADVANCE)
offset += 8;
}
if (fp_offset >= 0)
{
mem = gen_frame_mem (DImode, plus_constant (base, fp_offset));
emit_move_insn (hard_frame_pointer_rtx, mem);
} }
} }
else else
{ {
for (i = low; i < high; i += 2) for (i = low; i < high; i += 2)
{ {
bool reg0 = df_regs_ever_live_p (i) && ! call_used_regs[i]; bool reg0 = save_p (i, leaf_function);
bool reg1 = df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]; bool reg1 = save_p (i + 1, leaf_function);
enum machine_mode mode; enum machine_mode mode;
int regno; int regno;
...@@ -4399,15 +4515,35 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action) ...@@ -4399,15 +4515,35 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
offset += 4; offset += 4;
} }
else else
continue; {
if (action_false == SORR_ADVANCE)
offset += 8;
continue;
}
mem = gen_frame_mem (mode, plus_constant (base, offset)); mem = gen_frame_mem (mode, plus_constant (base, offset));
if (action == SORR_SAVE) if (action_true == SORR_SAVE)
{ {
insn = emit_move_insn (mem, gen_rtx_REG (mode, regno)); insn = emit_move_insn (mem, gen_rtx_REG (mode, regno));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
if (mode == DImode)
{
rtx set1, set2;
mem = gen_frame_mem (SImode, plus_constant (base, offset));
set1 = gen_rtx_SET (VOIDmode, mem,
gen_rtx_REG (SImode, regno));
RTX_FRAME_RELATED_P (set1) = 1;
mem
= gen_frame_mem (SImode, plus_constant (base, offset + 4));
set2 = gen_rtx_SET (VOIDmode, mem,
gen_rtx_REG (SImode, regno + 1));
RTX_FRAME_RELATED_P (set2) = 1;
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, set1, set2)));
}
} }
else /* action == SORR_RESTORE */ else /* action_true == SORR_RESTORE */
emit_move_insn (gen_rtx_REG (mode, regno), mem); emit_move_insn (gen_rtx_REG (mode, regno), mem);
/* Always preserve double-word alignment. */ /* Always preserve double-word alignment. */
...@@ -4418,36 +4554,54 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action) ...@@ -4418,36 +4554,54 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
return offset; return offset;
} }
/* Emit code to save call-saved registers. */ /* Emit code to adjust BASE to OFFSET. Return the new base. */
static rtx
emit_adjust_base_to_offset (rtx base, int offset)
{
/* ??? This might be optimized a little as %g1 might already have a
value close enough that a single add insn will do. */
/* ??? Although, all of this is probably only a temporary fix because
if %g1 can hold a function result, then sparc_expand_epilogue will
lose (the result will be clobbered). */
rtx new_base = gen_rtx_REG (Pmode, 1);
emit_move_insn (new_base, GEN_INT (offset));
emit_insn (gen_rtx_SET (VOIDmode,
new_base, gen_rtx_PLUS (Pmode, base, new_base)));
return new_base;
}
/* Emit code to save/restore call-saved global and FP registers. */
static void static void
emit_save_or_restore_regs (int action) emit_save_or_restore_global_fp_regs (rtx base, int offset, sorr_act_t action)
{ {
HOST_WIDE_INT offset; if (offset < -4096 || offset + sparc_n_global_fp_regs * 4 > 4095)
rtx base; {
base = emit_adjust_base_to_offset (base, offset);
offset = 0;
}
offset = frame_base_offset - apparent_fsize; offset
= emit_save_or_restore_regs (0, 8, base, offset, 0,
save_global_or_fp_reg_p, action, SORR_NONE);
emit_save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, 0,
save_global_or_fp_reg_p, action, SORR_NONE);
}
if (offset < -4096 || offset + num_gfregs * 4 > 4095) /* Emit code to save/restore call-saved local and in registers. */
static void
emit_save_or_restore_local_in_regs (rtx base, int offset, sorr_act_t action)
{
if (offset < -4096 || offset + 16 * UNITS_PER_WORD > 4095)
{ {
/* ??? This might be optimized a little as %g1 might already have a base = emit_adjust_base_to_offset (base, offset);
value close enough that a single add insn will do. */
/* ??? Although, all of this is probably only a temporary fix
because if %g1 can hold a function result, then
sparc_expand_epilogue will lose (the result will be
clobbered). */
base = gen_rtx_REG (Pmode, 1);
emit_move_insn (base, GEN_INT (offset));
emit_insn (gen_rtx_SET (VOIDmode,
base,
gen_rtx_PLUS (Pmode, frame_base_reg, base)));
offset = 0; offset = 0;
} }
else
base = frame_base_reg;
offset = save_or_restore_regs (0, 8, base, offset, action); emit_save_or_restore_regs (16, 32, base, offset, sparc_leaf_function_p,
save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action); save_local_or_in_reg_p, action, SORR_ADVANCE);
} }
/* Generate a save_register_window insn. */ /* Generate a save_register_window insn. */
...@@ -4461,6 +4615,39 @@ gen_save_register_window (rtx increment) ...@@ -4461,6 +4615,39 @@ gen_save_register_window (rtx increment)
return gen_save_register_windowsi (increment); return gen_save_register_windowsi (increment);
} }
/* Generate a create_flat_frame_1 insn. */
static rtx
gen_create_flat_frame_1 (rtx increment)
{
if (TARGET_ARCH64)
return gen_create_flat_frame_1di (increment);
else
return gen_create_flat_frame_1si (increment);
}
/* Generate a create_flat_frame_2 insn. */
static rtx
gen_create_flat_frame_2 (rtx increment)
{
if (TARGET_ARCH64)
return gen_create_flat_frame_2di (increment);
else
return gen_create_flat_frame_2si (increment);
}
/* Generate a create_flat_frame_3 insn. */
static rtx
gen_create_flat_frame_3 (rtx increment)
{
if (TARGET_ARCH64)
return gen_create_flat_frame_3di (increment);
else
return gen_create_flat_frame_3si (increment);
}
/* Generate an increment for the stack pointer. */ /* Generate an increment for the stack pointer. */
static rtx static rtx
...@@ -4492,6 +4679,7 @@ gen_stack_pointer_dec (rtx decrement) ...@@ -4492,6 +4679,7 @@ gen_stack_pointer_dec (rtx decrement)
void void
sparc_expand_prologue (void) sparc_expand_prologue (void)
{ {
HOST_WIDE_INT size;
rtx insn; rtx insn;
int i; int i;
...@@ -4520,70 +4708,52 @@ sparc_expand_prologue (void) ...@@ -4520,70 +4708,52 @@ sparc_expand_prologue (void)
sparc_leaf_function_p sparc_leaf_function_p
= optimize > 0 && current_function_is_leaf && only_leaf_regs_used (); = optimize > 0 && current_function_is_leaf && only_leaf_regs_used ();
/* Need to use actual_fsize, since we are also allocating size = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
space for our callee (and our own register save area). */
actual_fsize
= sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
/* Advertise that the data calculated just above are now valid. */
sparc_prologue_data_valid_p = true;
if (flag_stack_usage_info) if (flag_stack_usage_info)
current_function_static_stack_size = actual_fsize; current_function_static_stack_size = size;
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && actual_fsize) if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, actual_fsize); sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
if (sparc_leaf_function_p) if (size == 0)
{ ; /* do nothing. */
frame_base_reg = stack_pointer_rtx;
frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
}
else
{
frame_base_reg = hard_frame_pointer_rtx;
frame_base_offset = SPARC_STACK_BIAS;
}
if (actual_fsize == 0)
/* do nothing. */ ;
else if (sparc_leaf_function_p) else if (sparc_leaf_function_p)
{ {
if (actual_fsize <= 4096) if (size <= 4096)
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-actual_fsize))); insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-size)));
else if (actual_fsize <= 8192) else if (size <= 8192)
{ {
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096))); insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
/* %sp is still the CFA register. */ /* %sp is still the CFA register. */
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
insn insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
= emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
} }
else else
{ {
rtx reg = gen_rtx_REG (Pmode, 1); rtx reg = gen_rtx_REG (Pmode, 1);
emit_move_insn (reg, GEN_INT (-actual_fsize)); emit_move_insn (reg, GEN_INT (-size));
insn = emit_insn (gen_stack_pointer_inc (reg)); insn = emit_insn (gen_stack_pointer_inc (reg));
add_reg_note (insn, REG_FRAME_RELATED_EXPR, add_reg_note (insn, REG_FRAME_RELATED_EXPR,
gen_stack_pointer_inc (GEN_INT (-actual_fsize))); gen_stack_pointer_inc (GEN_INT (-size)));
} }
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
} }
else else
{ {
if (actual_fsize <= 4096) if (size <= 4096)
insn = emit_insn (gen_save_register_window (GEN_INT (-actual_fsize))); insn = emit_insn (gen_save_register_window (GEN_INT (-size)));
else if (actual_fsize <= 8192) else if (size <= 8192)
{ {
insn = emit_insn (gen_save_register_window (GEN_INT (-4096))); insn = emit_insn (gen_save_register_window (GEN_INT (-4096)));
/* %sp is not the CFA register anymore. */ /* %sp is not the CFA register anymore. */
emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize))); emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
} }
else else
{ {
rtx reg = gen_rtx_REG (Pmode, 1); rtx reg = gen_rtx_REG (Pmode, 1);
emit_move_insn (reg, GEN_INT (-actual_fsize)); emit_move_insn (reg, GEN_INT (-size));
insn = emit_insn (gen_save_register_window (reg)); insn = emit_insn (gen_save_register_window (reg));
} }
...@@ -4592,12 +4762,179 @@ sparc_expand_prologue (void) ...@@ -4592,12 +4762,179 @@ sparc_expand_prologue (void)
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1; RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
} }
if (num_gfregs) if (sparc_leaf_function_p)
emit_save_or_restore_regs (SORR_SAVE); {
sparc_frame_base_reg = stack_pointer_rtx;
sparc_frame_base_offset = size + SPARC_STACK_BIAS;
}
else
{
sparc_frame_base_reg = hard_frame_pointer_rtx;
sparc_frame_base_offset = SPARC_STACK_BIAS;
}
if (sparc_n_global_fp_regs > 0)
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
sparc_frame_base_offset
- sparc_apparent_frame_size,
SORR_SAVE);
/* Load the GOT register if needed. */ /* Load the GOT register if needed. */
if (crtl->uses_pic_offset_table) if (crtl->uses_pic_offset_table)
load_got_register (); load_got_register ();
/* Advertise that the data calculated just above are now valid. */
sparc_prologue_data_valid_p = true;
}
/* Expand the function prologue. The prologue is responsible for reserving
storage for the frame, saving the call-saved registers and loading the
GOT register if needed. */
void
sparc_flat_expand_prologue (void)
{
HOST_WIDE_INT size;
rtx insn;
int i;
sparc_leaf_function_p = optimize > 0 && current_function_is_leaf;
size = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
if (flag_stack_usage_info)
current_function_static_stack_size = size;
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
if (sparc_save_local_in_regs_p)
emit_save_or_restore_local_in_regs (stack_pointer_rtx, SPARC_STACK_BIAS,
SORR_SAVE);
if (size == 0)
; /* do nothing. */
else if (frame_pointer_needed)
{
if (size <= 4096)
{
if (return_addr_reg_needed_p (sparc_leaf_function_p))
insn = emit_insn (gen_create_flat_frame_1 (GEN_INT (-size)));
else
insn = emit_insn (gen_create_flat_frame_2 (GEN_INT (-size)));
RTX_FRAME_RELATED_P (insn) = 1;
for (i=0; i < XVECLEN (PATTERN (insn), 0); i++)
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
}
else
{
rtx reg = gen_rtx_REG (Pmode, 1), note;
emit_move_insn (reg, GEN_INT (-size));
if (return_addr_reg_needed_p (sparc_leaf_function_p))
{
insn = emit_insn (gen_create_flat_frame_1 (reg));
note
= gen_rtx_PARALLEL (VOIDmode,
gen_rtvec
(3, copy_rtx
(XVECEXP (PATTERN (insn), 0, 0)),
gen_stack_pointer_inc
(GEN_INT (-size)),
copy_rtx
(XVECEXP (PATTERN (insn), 0, 2))));
}
else
{
insn = emit_insn (gen_create_flat_frame_2 (reg));
note
= gen_rtx_PARALLEL (VOIDmode,
gen_rtvec
(2, copy_rtx
(XVECEXP (PATTERN (insn), 0, 0)),
gen_stack_pointer_inc
(GEN_INT (-size))));
}
RTX_FRAME_RELATED_P (insn) = 1;
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
for (i=0; i < XVECLEN (note, 0); i++)
RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
}
}
else if (return_addr_reg_needed_p (sparc_leaf_function_p))
{
if (size <= 4096)
{
insn = emit_insn (gen_create_flat_frame_3 (GEN_INT (-size)));
RTX_FRAME_RELATED_P (insn) = 1;
for (i=0; i < XVECLEN (PATTERN (insn), 0); i++)
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
}
else
{
rtx reg = gen_rtx_REG (Pmode, 1), note;
emit_move_insn (reg, GEN_INT (-size));
insn = emit_insn (gen_create_flat_frame_3 (reg));
note
= gen_rtx_PARALLEL (VOIDmode,
gen_rtvec
(2, gen_stack_pointer_inc (GEN_INT (-size)),
copy_rtx
(XVECEXP (PATTERN (insn), 0, 1))));
RTX_FRAME_RELATED_P (insn) = 1;
add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
for (i=0; i < XVECLEN (note, 0); i++)
RTX_FRAME_RELATED_P (XVECEXP (note, 0, i)) = 1;
}
}
else
{
if (size <= 4096)
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-size)));
else if (size <= 8192)
{
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
}
else
{
rtx reg = gen_rtx_REG (Pmode, 1);
emit_move_insn (reg, GEN_INT (-size));
insn = emit_insn (gen_stack_pointer_inc (reg));
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
gen_stack_pointer_inc (GEN_INT (-size)));
}
RTX_FRAME_RELATED_P (insn) = 1;
}
/* Make sure nothing is scheduled until after the frame is established. */
emit_insn (gen_blockage ());
if (frame_pointer_needed)
{
sparc_frame_base_reg = hard_frame_pointer_rtx;
sparc_frame_base_offset = SPARC_STACK_BIAS;
}
else
{
sparc_frame_base_reg = stack_pointer_rtx;
sparc_frame_base_offset = size + SPARC_STACK_BIAS;
}
if (sparc_n_global_fp_regs > 0)
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
sparc_frame_base_offset
- sparc_apparent_frame_size,
SORR_SAVE);
/* Load the GOT register if needed. */
if (crtl->uses_pic_offset_table)
load_got_register ();
/* Advertise that the data calculated just above are now valid. */
sparc_prologue_data_valid_p = true;
} }
/* This function generates the assembly code for function entry, which boils /* This function generates the assembly code for function entry, which boils
...@@ -4607,7 +4944,8 @@ static void ...@@ -4607,7 +4944,8 @@ static void
sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{ {
/* Check that the assumption we made in sparc_expand_prologue is valid. */ /* Check that the assumption we made in sparc_expand_prologue is valid. */
gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs); if (!TARGET_FLAT)
gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs);
sparc_output_scratch_registers (file); sparc_output_scratch_registers (file);
} }
...@@ -4616,26 +4954,91 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ...@@ -4616,26 +4954,91 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
We emit all the instructions except the return or the call. */ We emit all the instructions except the return or the call. */
void void
sparc_expand_epilogue (void) sparc_expand_epilogue (bool for_eh)
{ {
if (num_gfregs) HOST_WIDE_INT size = sparc_frame_size;
emit_save_or_restore_regs (SORR_RESTORE);
if (sparc_n_global_fp_regs > 0)
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
sparc_frame_base_offset
- sparc_apparent_frame_size,
SORR_RESTORE);
if (actual_fsize == 0) if (size == 0 || for_eh)
/* do nothing. */ ; ; /* do nothing. */
else if (sparc_leaf_function_p) else if (sparc_leaf_function_p)
{ {
if (actual_fsize <= 4096) if (size <= 4096)
emit_insn (gen_stack_pointer_dec (GEN_INT (- actual_fsize))); emit_insn (gen_stack_pointer_dec (GEN_INT (-size)));
else if (actual_fsize <= 8192) else if (size <= 8192)
{ {
emit_insn (gen_stack_pointer_dec (GEN_INT (-4096))); emit_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - actual_fsize))); emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - size)));
} }
else else
{ {
rtx reg = gen_rtx_REG (Pmode, 1); rtx reg = gen_rtx_REG (Pmode, 1);
emit_move_insn (reg, GEN_INT (-actual_fsize)); emit_move_insn (reg, GEN_INT (-size));
emit_insn (gen_stack_pointer_dec (reg));
}
}
}
/* Expand the function epilogue, either normal or part of a sibcall.
We emit all the instructions except the return or the call. */
void
sparc_flat_expand_epilogue (bool for_eh)
{
HOST_WIDE_INT size = sparc_frame_size;
if (sparc_n_global_fp_regs > 0)
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
sparc_frame_base_offset
- sparc_apparent_frame_size,
SORR_RESTORE);
/* If we have a frame pointer, we'll need both to restore it before the
frame is destroyed and use its current value in destroying the frame.
Since we don't have an atomic way to do that in the flat window model,
we save the current value into a temporary register (%g1). */
if (frame_pointer_needed && !for_eh)
emit_move_insn (gen_rtx_REG (Pmode, 1), hard_frame_pointer_rtx);
if (return_addr_reg_needed_p (sparc_leaf_function_p))
emit_move_insn (gen_rtx_REG (Pmode, INCOMING_RETURN_ADDR_REGNUM),
gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM));
if (sparc_save_local_in_regs_p)
emit_save_or_restore_local_in_regs (sparc_frame_base_reg,
sparc_frame_base_offset,
SORR_RESTORE);
if (size == 0 || for_eh)
; /* do nothing. */
else if (frame_pointer_needed)
{
/* Make sure the frame is destroyed after everything else is done. */
emit_insn (gen_blockage ());
emit_move_insn (stack_pointer_rtx, gen_rtx_REG (Pmode, 1));
}
else
{
/* Likewise. */
emit_insn (gen_blockage ());
if (size <= 4096)
emit_insn (gen_stack_pointer_dec (GEN_INT (-size)));
else if (size <= 8192)
{
emit_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - size)));
}
else
{
rtx reg = gen_rtx_REG (Pmode, 1);
emit_move_insn (reg, GEN_INT (-size));
emit_insn (gen_stack_pointer_dec (reg)); emit_insn (gen_stack_pointer_dec (reg));
} }
} }
...@@ -4648,8 +5051,10 @@ bool ...@@ -4648,8 +5051,10 @@ bool
sparc_can_use_return_insn_p (void) sparc_can_use_return_insn_p (void)
{ {
return sparc_prologue_data_valid_p return sparc_prologue_data_valid_p
&& num_gfregs == 0 && sparc_n_global_fp_regs == 0
&& (actual_fsize == 0 || !sparc_leaf_function_p); && TARGET_FLAT
? (sparc_frame_size == 0 && !sparc_save_local_in_regs_p)
: (sparc_frame_size == 0 || !sparc_leaf_function_p);
} }
/* This function generates the assembly code for function exit. */ /* This function generates the assembly code for function exit. */
...@@ -4728,15 +5133,42 @@ output_restore (rtx pat) ...@@ -4728,15 +5133,42 @@ output_restore (rtx pat)
const char * const char *
output_return (rtx insn) output_return (rtx insn)
{ {
if (sparc_leaf_function_p) if (crtl->calls_eh_return)
{
/* If the function uses __builtin_eh_return, the eh_return
machinery occupies the delay slot. */
gcc_assert (!final_sequence);
if (flag_delayed_branch)
{
if (!TARGET_FLAT && TARGET_V9)
fputs ("\treturn\t%i7+8\n", asm_out_file);
else
{
if (!TARGET_FLAT)
fputs ("\trestore\n", asm_out_file);
fputs ("\tjmp\t%o7+8\n", asm_out_file);
}
fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
}
else
{
if (!TARGET_FLAT)
fputs ("\trestore\n", asm_out_file);
fputs ("\tadd\t%sp, %g1, %sp\n", asm_out_file);
fputs ("\tjmp\t%o7+8\n\t nop\n", asm_out_file);
}
}
else if (sparc_leaf_function_p || TARGET_FLAT)
{ {
/* This is a leaf function so we don't have to bother restoring the /* This is a leaf or flat function so we don't have to bother restoring
register window, which frees us from dealing with the convoluted the register window, which frees us from dealing with the convoluted
semantics of restore/return. We simply output the jump to the semantics of restore/return. We simply output the jump to the
return address and the insn in the delay slot (if any). */ return address and the insn in the delay slot (if any). */
gcc_assert (! crtl->calls_eh_return);
return "jmp\t%%o7+%)%#"; return "jmp\t%%o7+%)%#";
} }
else else
...@@ -4746,28 +5178,7 @@ output_return (rtx insn) ...@@ -4746,28 +5178,7 @@ output_return (rtx insn)
combined with the 'restore' instruction or put in the delay slot of combined with the 'restore' instruction or put in the delay slot of
the 'return' instruction. */ the 'return' instruction. */
if (crtl->calls_eh_return) if (final_sequence)
{
/* If the function uses __builtin_eh_return, the eh_return
machinery occupies the delay slot. */
gcc_assert (! final_sequence);
if (flag_delayed_branch)
{
if (TARGET_V9)
fputs ("\treturn\t%i7+8\n", asm_out_file);
else
fputs ("\trestore\n\tjmp\t%o7+8\n", asm_out_file);
fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
}
else
{
fputs ("\trestore\n\tadd\t%sp, %g1, %sp\n", asm_out_file);
fputs ("\tjmp\t%o7+8\n\t nop\n", asm_out_file);
}
}
else if (final_sequence)
{ {
rtx delay, pat; rtx delay, pat;
...@@ -4815,10 +5226,10 @@ output_sibcall (rtx insn, rtx call_operand) ...@@ -4815,10 +5226,10 @@ output_sibcall (rtx insn, rtx call_operand)
operands[0] = call_operand; operands[0] = call_operand;
if (sparc_leaf_function_p) if (sparc_leaf_function_p || TARGET_FLAT)
{ {
/* This is a leaf function so we don't have to bother restoring the /* This is a leaf or flat function so we don't have to bother restoring
register window. We simply output the jump to the function and the register window. We simply output the jump to the function and
the insn in the delay slot (if any). */ the insn in the delay slot (if any). */
gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence)); gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence));
...@@ -9352,7 +9763,13 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, ...@@ -9352,7 +9763,13 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
emit_note (NOTE_INSN_PROLOGUE_END); emit_note (NOTE_INSN_PROLOGUE_END);
if (flag_delayed_branch) if (TARGET_FLAT)
{
sparc_leaf_function_p = 1;
int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
}
else if (flag_delayed_branch)
{ {
/* We will emit a regular sibcall below, so we need to instruct /* We will emit a regular sibcall below, so we need to instruct
output_sibcall that we are in a leaf function. */ output_sibcall that we are in a leaf function. */
...@@ -9473,8 +9890,6 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, ...@@ -9473,8 +9890,6 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
{ {
spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */ spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */
start_sequence (); start_sequence ();
/* Delay emitting the GOT helper function because it needs to
change the section and we are emitting assembly code. */
load_got_register (); /* clobbers %o7 */ load_got_register (); /* clobbers %o7 */
scratch = sparc_legitimize_pic_address (funexp, scratch); scratch = sparc_legitimize_pic_address (funexp, scratch);
seq = get_insns (); seq = get_insns ();
...@@ -9593,8 +10008,10 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) ...@@ -9593,8 +10008,10 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
} }
/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook. /* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
This is called from dwarf2out.c to emit call frame instructions This is called from dwarf2out.c to emit call frame instructions
for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */ for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
static void static void
sparc_dwarf_handle_frame_unspec (const char *label, sparc_dwarf_handle_frame_unspec (const char *label,
rtx pattern ATTRIBUTE_UNUSED, rtx pattern ATTRIBUTE_UNUSED,
...@@ -9810,6 +10227,16 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval) ...@@ -9810,6 +10227,16 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
static bool static bool
sparc_frame_pointer_required (void) sparc_frame_pointer_required (void)
{ {
/* If the stack pointer is dynamically modified in the function, it cannot
serve as the frame pointer. */
if (cfun->calls_alloca)
return true;
/* In flat mode, that's it. */
if (TARGET_FLAT)
return false;
/* Otherwise, the frame pointer is required if the function isn't leaf. */
return !(current_function_is_leaf && only_leaf_regs_used ()); return !(current_function_is_leaf && only_leaf_regs_used ());
} }
...@@ -9880,6 +10307,14 @@ sparc_conditional_register_usage (void) ...@@ -9880,6 +10307,14 @@ sparc_conditional_register_usage (void)
fixed_regs[4] = 1; fixed_regs[4] = 1;
else if (fixed_regs[4] == 2) else if (fixed_regs[4] == 2)
fixed_regs[4] = 0; fixed_regs[4] = 0;
if (TARGET_FLAT)
{
int regno;
/* Disable leaf functions. */
memset (sparc_leaf_regs, 0, FIRST_PSEUDO_REGISTER);
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
leaf_reg_remap [regno] = regno;
}
} }
/* Implement TARGET_PREFERRED_RELOAD_CLASS /* Implement TARGET_PREFERRED_RELOAD_CLASS
......
...@@ -360,7 +360,6 @@ extern enum cmodel sparc_cmodel; ...@@ -360,7 +360,6 @@ extern enum cmodel sparc_cmodel;
/* Common CPP definitions used by CPP_SPEC amongst the various targets /* Common CPP definitions used by CPP_SPEC amongst the various targets
for handling -mcpu=xxx switches. */ for handling -mcpu=xxx switches. */
#define CPP_CPU_SPEC "\ #define CPP_CPU_SPEC "\
%{msoft-float:-D_SOFT_FLOAT} \
%{mcpu=sparclet:-D__sparclet__} %{mcpu=tsc701:-D__sparclet__} \ %{mcpu=sparclet:-D__sparclet__} %{mcpu=tsc701:-D__sparclet__} \
%{mcpu=sparclite:-D__sparclite__} \ %{mcpu=sparclite:-D__sparclite__} \
%{mcpu=f930:-D__sparclite__} %{mcpu=f934:-D__sparclite__} \ %{mcpu=f930:-D__sparclite__} %{mcpu=f934:-D__sparclite__} \
...@@ -388,14 +387,18 @@ extern enum cmodel sparc_cmodel; ...@@ -388,14 +387,18 @@ extern enum cmodel sparc_cmodel;
%{!m32:%{!m64:%(cpp_arch_default)}} \ %{!m32:%{!m64:%(cpp_arch_default)}} \
" "
/* Macro to distinguish endianness. */ /* Macros to distinguish the endianness, window model and FP support. */
#define CPP_ENDIAN_SPEC "\ #define CPP_OTHER_SPEC "\
%{mlittle-endian:-D__LITTLE_ENDIAN__}" %{mlittle-endian:-D__LITTLE_ENDIAN__} \
%{mflat:-D_FLAT} \
%{msoft-float:-D_SOFT_FLOAT} \
"
/* Macros to distinguish the particular subtarget. */ /* Macros to distinguish the particular subtarget. */
#define CPP_SUBTARGET_SPEC "" #define CPP_SUBTARGET_SPEC ""
#define CPP_SPEC "%(cpp_cpu) %(cpp_arch) %(cpp_endian) %(cpp_subtarget)" #define CPP_SPEC \
"%(cpp_cpu) %(cpp_arch) %(cpp_endian) %(cpp_other) %(cpp_subtarget)"
/* This used to translate -dalign to -malign, but that is no good /* This used to translate -dalign to -malign, but that is no good
because it can't turn off the usual meaning of making debugging dumps. */ because it can't turn off the usual meaning of making debugging dumps. */
...@@ -464,7 +467,7 @@ extern enum cmodel sparc_cmodel; ...@@ -464,7 +467,7 @@ extern enum cmodel sparc_cmodel;
{ "cpp_arch64", CPP_ARCH64_SPEC }, \ { "cpp_arch64", CPP_ARCH64_SPEC }, \
{ "cpp_arch_default", CPP_ARCH_DEFAULT_SPEC },\ { "cpp_arch_default", CPP_ARCH_DEFAULT_SPEC },\
{ "cpp_arch", CPP_ARCH_SPEC }, \ { "cpp_arch", CPP_ARCH_SPEC }, \
{ "cpp_endian", CPP_ENDIAN_SPEC }, \ { "cpp_other", CPP_OTHER_SPEC }, \
{ "cpp_subtarget", CPP_SUBTARGET_SPEC }, \ { "cpp_subtarget", CPP_SUBTARGET_SPEC }, \
{ "asm_cpu", ASM_CPU_SPEC }, \ { "asm_cpu", ASM_CPU_SPEC }, \
{ "asm_cpu_default", ASM_CPU_DEFAULT_SPEC }, \ { "asm_cpu_default", ASM_CPU_DEFAULT_SPEC }, \
...@@ -687,7 +690,7 @@ extern enum cmodel sparc_cmodel; ...@@ -687,7 +690,7 @@ extern enum cmodel sparc_cmodel;
/* Argument passing regs. */ /* Argument passing regs. */
#define SPARC_OUTGOING_INT_ARG_FIRST 8 #define SPARC_OUTGOING_INT_ARG_FIRST 8
#define SPARC_INCOMING_INT_ARG_FIRST 24 #define SPARC_INCOMING_INT_ARG_FIRST (TARGET_FLAT ? 8 : 24)
#define SPARC_FP_ARG_FIRST 32 #define SPARC_FP_ARG_FIRST 32
/* 1 for registers that have pervasive standard uses /* 1 for registers that have pervasive standard uses
...@@ -721,7 +724,7 @@ extern enum cmodel sparc_cmodel; ...@@ -721,7 +724,7 @@ extern enum cmodel sparc_cmodel;
{1, 0, 2, 2, 2, 2, 1, 1, \ {1, 0, 2, 2, 2, 2, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 0, \ 0, 0, 0, 0, 0, 0, 1, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 1, 1, \ 0, 0, 0, 0, 0, 0, 0, 1, \
\ \
0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \
...@@ -746,7 +749,7 @@ extern enum cmodel sparc_cmodel; ...@@ -746,7 +749,7 @@ extern enum cmodel sparc_cmodel;
{1, 1, 1, 1, 1, 1, 1, 1, \ {1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, \
0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 1, 1, \ 0, 0, 0, 0, 0, 0, 0, 1, \
\ \
1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, \
...@@ -1223,13 +1226,11 @@ extern char leaf_reg_remap[]; ...@@ -1223,13 +1226,11 @@ extern char leaf_reg_remap[];
{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ {{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM} } { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM} }
/* We always pretend that this is a leaf function because if it's not,
there's no point in trying to eliminate the frame pointer. If it
is a leaf function, we guessed right! */
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
do { \ do { \
if ((TO) == STACK_POINTER_REGNUM) \ if ((TO) == STACK_POINTER_REGNUM) \
(OFFSET) = sparc_compute_frame_size (get_frame_size (), 1); \ (OFFSET) = sparc_compute_frame_size (get_frame_size (), \
current_function_is_leaf); \
else \ else \
(OFFSET) = 0; \ (OFFSET) = 0; \
(OFFSET) += SPARC_STACK_BIAS; \ (OFFSET) += SPARC_STACK_BIAS; \
...@@ -1247,7 +1248,7 @@ extern char leaf_reg_remap[]; ...@@ -1247,7 +1248,7 @@ extern char leaf_reg_remap[];
Return OUT if register number OUT is not an outbound register. */ Return OUT if register number OUT is not an outbound register. */
#define INCOMING_REGNO(OUT) \ #define INCOMING_REGNO(OUT) \
(((OUT) < 8 || (OUT) > 15) ? (OUT) : (OUT) + 16) ((TARGET_FLAT || (OUT) < 8 || (OUT) > 15) ? (OUT) : (OUT) + 16)
/* Define this macro if the target machine has "register windows". This /* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the calling function C expression returns the register number as seen by the calling function
...@@ -1255,14 +1256,14 @@ extern char leaf_reg_remap[]; ...@@ -1255,14 +1256,14 @@ extern char leaf_reg_remap[];
Return IN if register number IN is not an inbound register. */ Return IN if register number IN is not an inbound register. */
#define OUTGOING_REGNO(IN) \ #define OUTGOING_REGNO(IN) \
(((IN) < 24 || (IN) > 31) ? (IN) : (IN) - 16) ((TARGET_FLAT || (IN) < 24 || (IN) > 31) ? (IN) : (IN) - 16)
/* Define this macro if the target machine has register windows. This /* Define this macro if the target machine has register windows. This
C expression returns true if the register is call-saved but is in the C expression returns true if the register is call-saved but is in the
register window. */ register window. */
#define LOCAL_REGNO(REGNO) \ #define LOCAL_REGNO(REGNO) \
((REGNO) >= 16 && (REGNO) <= 31) (!TARGET_FLAT && (REGNO) >= 16 && (REGNO) <= 31)
/* Define the size of space to allocate for the return value of an /* Define the size of space to allocate for the return value of an
untyped_call. */ untyped_call. */
...@@ -1373,35 +1374,27 @@ do { \ ...@@ -1373,35 +1374,27 @@ do { \
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in the stack pointer does not matter. The value is tested only in
functions that have frame pointers. functions that have frame pointers. */
No definition is equivalent to always zero. */ #define EXIT_IGNORE_STACK 1
#define EXIT_IGNORE_STACK \
(get_frame_size () != 0 \
|| cfun->calls_alloca || crtl->outgoing_args_size)
/* Define registers used by the epilogue and return instruction. */
#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 /* We need 2 words, so we can save the stack pointer and the return register
of the function containing a non-local goto target. */ of the function containing a non-local goto target. */
#define STACK_SAVEAREA_MODE(LEVEL) \ #define STACK_SAVEAREA_MODE(LEVEL) \
((LEVEL) == SAVE_NONLOCAL ? (TARGET_ARCH64 ? TImode : DImode) : Pmode) ((LEVEL) == SAVE_NONLOCAL ? (TARGET_ARCH64 ? TImode : DImode) : Pmode)
/* Length in units of the trampoline for entering a nested function. */ /* Length in units of the trampoline for entering a nested function. */
#define TRAMPOLINE_SIZE (TARGET_ARCH64 ? 32 : 16) #define TRAMPOLINE_SIZE (TARGET_ARCH64 ? 32 : 16)
/* Alignment required for trampolines, in bits. */ /* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT 128 #define TRAMPOLINE_ALIGNMENT 128
/* Generate RTL to flush the register windows so as to make arbitrary frames /* Generate RTL to flush the register windows so as to make arbitrary frames
available. */ available. */
#define SETUP_FRAME_ADDRESSES() \ #define SETUP_FRAME_ADDRESSES() \
emit_insn (gen_flush_register_windows ()) do { \
if (!TARGET_FLAT) \
emit_insn (gen_flush_register_windows ());\
} while (0)
/* Given an rtx for the address of a frame, /* Given an rtx for the address of a frame,
return an rtx for the address of the word in the frame return an rtx for the address of the word in the frame
...@@ -1428,9 +1421,10 @@ do { \ ...@@ -1428,9 +1421,10 @@ do { \
farther back is in the register window save area at [%fp+60]. */ farther back is in the register window save area at [%fp+60]. */
/* ??? This ignores the fact that the actual return address is +8 for normal /* ??? This ignores the fact that the actual return address is +8 for normal
returns, and +12 for structure returns. */ returns, and +12 for structure returns. */
#define RETURN_ADDR_REGNUM 31
#define RETURN_ADDR_RTX(count, frame) \ #define RETURN_ADDR_RTX(count, frame) \
((count == -1) \ ((count == -1) \
? gen_rtx_REG (Pmode, 31) \ ? gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM) \
: gen_rtx_MEM (Pmode, \ : gen_rtx_MEM (Pmode, \
memory_address (Pmode, plus_constant (frame, \ memory_address (Pmode, plus_constant (frame, \
15 * UNITS_PER_WORD \ 15 * UNITS_PER_WORD \
...@@ -1440,9 +1434,11 @@ do { \ ...@@ -1440,9 +1434,11 @@ do { \
+12, but always using +8 is close enough for frame unwind purposes. +12, but always using +8 is close enough for frame unwind purposes.
Actually, just using %o7 is close enough for unwinding, but %o7+8 Actually, just using %o7 is close enough for unwinding, but %o7+8
is something you can return to. */ is something you can return to. */
#define INCOMING_RETURN_ADDR_REGNUM 15
#define INCOMING_RETURN_ADDR_RTX \ #define INCOMING_RETURN_ADDR_RTX \
plus_constant (gen_rtx_REG (word_mode, 15), 8) plus_constant (gen_rtx_REG (word_mode, INCOMING_RETURN_ADDR_REGNUM), 8)
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (15) #define DWARF_FRAME_RETURN_COLUMN \
DWARF_FRAME_REGNUM (INCOMING_RETURN_ADDR_REGNUM)
/* The offset from the incoming value of %sp to the top of the stack frame /* The offset from the incoming value of %sp to the top of the stack frame
for the current function. On sparc64, we have to account for the stack for the current function. On sparc64, we have to account for the stack
...@@ -1450,9 +1446,17 @@ do { \ ...@@ -1450,9 +1446,17 @@ do { \
#define INCOMING_FRAME_SP_OFFSET SPARC_STACK_BIAS #define INCOMING_FRAME_SP_OFFSET SPARC_STACK_BIAS
/* Describe how we implement __builtin_eh_return. */ /* Describe how we implement __builtin_eh_return. */
#define EH_RETURN_REGNUM 1
#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 24 : INVALID_REGNUM) #define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 24 : INVALID_REGNUM)
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 1) /* %g1 */ #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_RETURN_REGNUM)
#define EH_RETURN_HANDLER_RTX gen_rtx_REG (Pmode, 31) /* %i7 */
/* Define registers used by the epilogue and return instruction. */
#define EPILOGUE_USES(REGNO) \
((REGNO) == RETURN_ADDR_REGNUM \
|| (TARGET_FLAT \
&& epilogue_completed \
&& (REGNO) == INCOMING_RETURN_ADDR_REGNUM) \
|| (crtl->calls_eh_return && (REGNO) == EH_RETURN_REGNUM))
/* Select a format to encode pointers in exception handling data. CODE /* Select a format to encode pointers in exception handling data. CODE
is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
......
...@@ -164,7 +164,7 @@ ...@@ -164,7 +164,7 @@
(define_attr "calls_eh_return" "false,true" (define_attr "calls_eh_return" "false,true"
(symbol_ref "(crtl->calls_eh_return != 0 (symbol_ref "(crtl->calls_eh_return != 0
? CALLS_EH_RETURN_TRUE : CALLS_EH_RETURN_FALSE)")) ? CALLS_EH_RETURN_TRUE : CALLS_EH_RETURN_FALSE)"))
(define_attr "leaf_function" "false,true" (define_attr "leaf_function" "false,true"
(symbol_ref "(current_function_uses_only_leaf_regs != 0 (symbol_ref "(current_function_uses_only_leaf_regs != 0
? LEAF_FUNCTION_TRUE : LEAF_FUNCTION_FALSE)")) ? LEAF_FUNCTION_TRUE : LEAF_FUNCTION_FALSE)"))
...@@ -173,6 +173,10 @@ ...@@ -173,6 +173,10 @@
(symbol_ref "(flag_delayed_branch != 0 (symbol_ref "(flag_delayed_branch != 0
? DELAYED_BRANCH_TRUE : DELAYED_BRANCH_FALSE)")) ? DELAYED_BRANCH_TRUE : DELAYED_BRANCH_FALSE)"))
(define_attr "flat" "false,true"
(symbol_ref "(TARGET_FLAT != 0
? FLAT_TRUE : FLAT_FALSE)"))
;; Length (in # of insns). ;; Length (in # of insns).
;; Beware that setting a length greater or equal to 3 for conditional branches ;; Beware that setting a length greater or equal to 3 for conditional branches
;; has a side-effect (see output_cbranch and output_v9branch). ;; has a side-effect (see output_cbranch and output_v9branch).
...@@ -6265,7 +6269,10 @@ ...@@ -6265,7 +6269,10 @@
[(const_int 0)] [(const_int 0)]
"" ""
{ {
sparc_expand_prologue (); if (TARGET_FLAT)
sparc_flat_expand_prologue ();
else
sparc_expand_prologue ();
DONE; DONE;
}) })
...@@ -6282,25 +6289,87 @@ ...@@ -6282,25 +6289,87 @@
(set (reg:P 14) (unspec_volatile:P [(reg:P 14) (set (reg:P 14) (unspec_volatile:P [(reg:P 14)
(match_operand:P 0 "arith_operand" "rI")] UNSPECV_SAVEW)) (match_operand:P 0 "arith_operand" "rI")] UNSPECV_SAVEW))
(set (reg:P 31) (reg:P 15))] (set (reg:P 31) (reg:P 15))]
"" "!TARGET_FLAT"
"save\t%%sp, %0, %%sp" "save\t%%sp, %0, %%sp"
[(set_attr "type" "savew")]) [(set_attr "type" "savew")])
;; Likewise for the "create flat frame" insns. We need to use special insns
;; because %fp cannot be clobbered until after the frame is established (so
;; that it contains the live register window save area) and %i7 changed with
;; a simple move as it is a fixed register and the move would be eliminated.
(define_insn "create_flat_frame_1<P:mode>"
[(set (reg:P 30) (reg:P 14))
(set (reg:P 14) (plus:P (reg:P 14)
(match_operand:P 0 "arith_operand" "rI")))
(set (reg:P 31) (reg:P 15))]
"TARGET_FLAT"
"add\t%%sp, %0, %%sp\n\tsub\t%%sp, %0, %%fp\n\tmov\t%%o7, %%i7"
[(set_attr "type" "multi")
(set_attr "length" "3")])
(define_insn "create_flat_frame_2<P:mode>"
[(set (reg:P 30) (reg:P 14))
(set (reg:P 14) (plus:P (reg:P 14)
(match_operand:P 0 "arith_operand" "rI")))]
"TARGET_FLAT"
"add\t%%sp, %0, %%sp\n\tsub\t%%sp, %0, %%fp"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_insn "create_flat_frame_3<P:mode>"
[(set (reg:P 14) (plus:P (reg:P 14)
(match_operand:P 0 "arith_operand" "rI")))
(set (reg:P 31) (reg:P 15))]
"TARGET_FLAT"
"add\t%%sp, %0, %%sp\n\tmov\t%%o7, %%i7"
[(set_attr "type" "multi")
(set_attr "length" "2")])
(define_expand "epilogue" (define_expand "epilogue"
[(return)] [(return)]
"" ""
{ {
sparc_expand_epilogue (); if (TARGET_FLAT)
sparc_flat_expand_epilogue (false);
else
sparc_expand_epilogue (false);
}) })
(define_expand "sibcall_epilogue" (define_expand "sibcall_epilogue"
[(return)] [(return)]
"" ""
{ {
sparc_expand_epilogue (); if (TARGET_FLAT)
sparc_flat_expand_epilogue (false);
else
sparc_expand_epilogue (false);
DONE;
})
(define_expand "eh_return"
[(use (match_operand 0 "general_operand" ""))]
""
{
emit_move_insn (gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM), operands[0]);
emit_jump_insn (gen_eh_return_internal ());
emit_barrier ();
DONE; DONE;
}) })
(define_insn_and_split "eh_return_internal"
[(eh_return)]
""
"#"
"epilogue_completed"
[(return)]
{
if (TARGET_FLAT)
sparc_flat_expand_epilogue (true);
else
sparc_expand_epilogue (true);
})
(define_expand "return" (define_expand "return"
[(return)] [(return)]
"sparc_can_use_return_insn_p ()" "sparc_can_use_return_insn_p ()"
...@@ -6312,16 +6381,19 @@ ...@@ -6312,16 +6381,19 @@
"* return output_return (insn);" "* return output_return (insn);"
[(set_attr "type" "return") [(set_attr "type" "return")
(set (attr "length") (set (attr "length")
(cond [(eq_attr "leaf_function" "true") (cond [(eq_attr "calls_eh_return" "true")
(if_then_else (eq_attr "delayed_branch" "true")
(if_then_else (ior (eq_attr "isa" "v9")
(eq_attr "flat" "true"))
(const_int 2)
(const_int 3))
(if_then_else (eq_attr "flat" "true")
(const_int 3)
(const_int 4)))
(ior (eq_attr "leaf_function" "true") (eq_attr "flat" "true"))
(if_then_else (eq_attr "empty_delay_slot" "true") (if_then_else (eq_attr "empty_delay_slot" "true")
(const_int 2) (const_int 2)
(const_int 1)) (const_int 1))
(eq_attr "calls_eh_return" "true")
(if_then_else (eq_attr "delayed_branch" "true")
(if_then_else (eq_attr "isa" "v9")
(const_int 2)
(const_int 3))
(const_int 4))
(eq_attr "empty_delay_slot" "true") (eq_attr "empty_delay_slot" "true")
(if_then_else (eq_attr "delayed_branch" "true") (if_then_else (eq_attr "delayed_branch" "true")
(const_int 2) (const_int 2)
...@@ -6367,8 +6439,7 @@ ...@@ -6367,8 +6439,7 @@
if (! TARGET_ARCH64) if (! TARGET_ARCH64)
{ {
rtx rtnreg = gen_rtx_REG (SImode, (current_function_uses_only_leaf_regs rtx rtnreg = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM);
? 15 : 31));
rtx value = gen_reg_rtx (SImode); rtx value = gen_reg_rtx (SImode);
/* Fetch the instruction where we will return to and see if it's an unimp /* Fetch the instruction where we will return to and see if it's an unimp
...@@ -6449,7 +6520,7 @@ ...@@ -6449,7 +6520,7 @@
{ {
operands[0] = adjust_address_nv (operands[0], Pmode, 0); operands[0] = adjust_address_nv (operands[0], Pmode, 0);
operands[2] = adjust_address_nv (operands[0], Pmode, GET_MODE_SIZE (Pmode)); operands[2] = adjust_address_nv (operands[0], Pmode, GET_MODE_SIZE (Pmode));
operands[3] = gen_rtx_REG (Pmode, 31); /* %i7 */ operands[3] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
}) })
(define_expand "restore_stack_nonlocal" (define_expand "restore_stack_nonlocal"
...@@ -6474,7 +6545,8 @@ ...@@ -6474,7 +6545,8 @@
/* We need to flush all the register windows so that their contents will /* We need to flush all the register windows so that their contents will
be re-synchronized by the restore insn of the target function. */ be re-synchronized by the restore insn of the target function. */
emit_insn (gen_flush_register_windows ()); if (!TARGET_FLAT)
emit_insn (gen_flush_register_windows ());
emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode))); emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx)); emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
......
...@@ -33,6 +33,10 @@ msoft-float ...@@ -33,6 +33,10 @@ msoft-float
Target RejectNegative InverseMask(FPU) Target RejectNegative InverseMask(FPU)
Do not use hardware FP Do not use hardware FP
mflat
Target Report Mask(FLAT)
Use flat register window model
munaligned-doubles munaligned-doubles
Target Report Mask(UNALIGNED_DOUBLES) Target Report Mask(UNALIGNED_DOUBLES)
Assume possible double misalignment Assume possible double misalignment
......
...@@ -32,8 +32,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c ...@@ -32,8 +32,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
echo '#define FLOAT' > fp-bit.c echo '#define FLOAT' > fp-bit.c
cat $(srcdir)/config/fp-bit.c >> fp-bit.c cat $(srcdir)/config/fp-bit.c >> fp-bit.c
MULTILIB_OPTIONS = msoft-float mcpu=v8 MULTILIB_OPTIONS = msoft-float mcpu=v8 mflat
MULTILIB_DIRNAMES = soft v8 MULTILIB_DIRNAMES = soft v8 flat
MULTILIB_MATCHES = msoft-float=mno-fpu MULTILIB_MATCHES = msoft-float=mno-fpu
LIBGCC = stmp-multilib LIBGCC = stmp-multilib
......
...@@ -34,8 +34,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c ...@@ -34,8 +34,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
# Multilibs for LEON # Multilibs for LEON
# LEON is a SPARC-V8, but the AT697 implementation has a bug in the # LEON is a SPARC-V8, but the AT697 implementation has a bug in the
# V8-specific instructions. # V8-specific instructions.
MULTILIB_OPTIONS = mcpu=v7 msoft-float MULTILIB_OPTIONS = mcpu=v7 msoft-float mflat
MULTILIB_DIRNAMES = v7 soft MULTILIB_DIRNAMES = v7 soft flat
MULTILIB_MATCHES = mcpu?v7=mv7 msoft-float=mno-fpu MULTILIB_MATCHES = mcpu?v7=mv7 msoft-float=mno-fpu
LIBGCC = stmp-multilib LIBGCC = stmp-multilib
......
...@@ -863,7 +863,7 @@ See RS/6000 and PowerPC Options. ...@@ -863,7 +863,7 @@ See RS/6000 and PowerPC Options.
-mtune=@var{cpu-type} @gol -mtune=@var{cpu-type} @gol
-mcmodel=@var{code-model} @gol -mcmodel=@var{code-model} @gol
-m32 -m64 -mapp-regs -mno-app-regs @gol -m32 -m64 -mapp-regs -mno-app-regs @gol
-mfaster-structs -mno-faster-structs @gol -mfaster-structs -mno-faster-structs -mflat -mno-flat @gol
-mfpu -mno-fpu -mhard-float -msoft-float @gol -mfpu -mno-fpu -mhard-float -msoft-float @gol
-mhard-quad-float -msoft-quad-float @gol -mhard-quad-float -msoft-quad-float @gol
-mlittle-endian @gol -mlittle-endian @gol
...@@ -17043,6 +17043,19 @@ To be fully SVR4 ABI compliant at the cost of some performance loss, ...@@ -17043,6 +17043,19 @@ To be fully SVR4 ABI compliant at the cost of some performance loss,
specify @option{-mno-app-regs}. You should compile libraries and system specify @option{-mno-app-regs}. You should compile libraries and system
software with this option. software with this option.
@item -mflat
@itemx -mno-flat
@opindex mflat
@opindex mno-flat
With @option{-mflat}, the compiler does not generate save/restore instructions
and uses a ``flat'' or single register window model. This model is compatible
with the regular register window model. The local registers and the input
registers (0--5) are still treated as ``call-saved'' registers and will be
saved on the stack as needed.
With @option{-mno-flat} (the default), the compiler generates save/restore
instructions (except for leaf functions). This is the normal operating mode.
@item -mfpu @item -mfpu
@itemx -mhard-float @itemx -mhard-float
@opindex mfpu @opindex mfpu
......
2011-06-10 Eric Botcazou <ebotcazou@adacore.com>
Laurent Roug <laurent.rouge@menta.fr>
* gcc.dg/20020503-1.c: Add back -mflat option on the SPARC.
* gcc.target/sparc/sparc-ret.c: Skip if -mflat is passed.
2011-06-10 Daniel Carrera <dcarrera@gmail.com> 2011-06-10 Daniel Carrera <dcarrera@gmail.com>
* gfortran.dg/coarray/sync_1.f90: New test for * gfortran.dg/coarray/sync_1.f90: New test for
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
for leaf functions, the function was still leaf, but LEAF_REG_REMAP for leaf functions, the function was still leaf, but LEAF_REG_REMAP
returned -1 for some registers (like %o0). */ returned -1 for some registers (like %o0). */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O2 -g" } */ /* { dg-options "-O2 -g -mflat" { target sparc*-*-* } } */
void foo (char *a, char *b, char *c, char *d) void foo (char *a, char *b, char *c, char *d)
{ {
......
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-skip-if "no register windows" { *-*-* } { "-mflat" } { "" } } */
/* { dg-require-effective-target ilp32 } */ /* { dg-require-effective-target ilp32 } */
/* { dg-options "-mcpu=ultrasparc -O" } */ /* { dg-options "-mcpu=ultrasparc -O" } */
...@@ -11,7 +12,7 @@ int bar (int a, int b, int c, int d, int e, int f, int g, int h) ...@@ -11,7 +12,7 @@ int bar (int a, int b, int c, int d, int e, int f, int g, int h)
toto (&res); toto (&res);
return h; return h;
} }
/* { dg-final { global compiler_flags; if ![string match "*-m64 *" $compiler_flags] { scan-assembler "return\[ \t\]*%i7\\+8\n\[^\n\]*ld\[ \t\]*\\\[%sp\\+96\\\]" } } } */ /* { dg-final { scan-assembler "return\[ \t\]*%i7\\+8\n\[^\n\]*ld\[ \t\]*\\\[%sp\\+96\\\]" } } */
int bar2 () int bar2 ()
{ {
...@@ -20,4 +21,4 @@ int bar2 () ...@@ -20,4 +21,4 @@ int bar2 ()
toto (&res); toto (&res);
return res; return res;
} }
/* { dg-final { global compiler_flags; if ![string match "*-m64 *" $compiler_flags] { scan-assembler "return\[ \t\]*%i7\\+8\n\[^\n\]*nop" } } } */ /* { dg-final { scan-assembler "return\[ \t\]*%i7\\+8\n\[^\n\]*nop" } } */
2011-06-10 Eric Botcazou <ebotcazou@adacore.com>
* config/sparc/linux-unwind.h (STACK_BIAS): Define.
(sparc64_fallback_frame_state): Use it.
(sparc64_frob_update_context): Further adjust context.
* config/sparc/sol2-unwind.h (sparc64_frob_update_context): Likewise.
* config/sparc/sol2-ci.S: Add TARGET_FLAT handling.
* config/sparc/sol2-cn.S: Likewise.
2011-06-09 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> 2011-06-09 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* enable-execute-stack-empty.c: New file. * enable-execute-stack-empty.c: New file.
......
...@@ -27,6 +27,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -27,6 +27,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#if defined(__arch64__) #if defined(__arch64__)
#undef STACK_BIAS
#define STACK_BIAS 2047
/* 64-bit SPARC version */ /* 64-bit SPARC version */
#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state #define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
...@@ -49,7 +52,8 @@ sparc64_fallback_frame_state (struct _Unwind_Context *context, ...@@ -49,7 +52,8 @@ sparc64_fallback_frame_state (struct _Unwind_Context *context,
fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4); fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
new_cfa = *(long *)(this_cfa + regs_off + (14 * 8)); new_cfa = *(long *)(this_cfa + regs_off + (14 * 8));
new_cfa += 2047; /* Stack bias */ /* The frame address is %sp + STACK_BIAS in 64-bit mode. */
new_cfa += STACK_BIAS;
fpu_save = *(long *)(this_cfa + fpu_save_off); fpu_save = *(long *)(this_cfa + fpu_save_off);
fs->regs.cfa_how = CFA_REG_OFFSET; fs->regs.cfa_how = CFA_REG_OFFSET;
fs->regs.cfa_reg = __builtin_dwarf_sp_column (); fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
...@@ -112,7 +116,16 @@ sparc64_frob_update_context (struct _Unwind_Context *context, ...@@ -112,7 +116,16 @@ sparc64_frob_update_context (struct _Unwind_Context *context,
&& fs->regs.cfa_how == CFA_REG_OFFSET && fs->regs.cfa_how == CFA_REG_OFFSET
&& fs->regs.cfa_offset != 0 && fs->regs.cfa_offset != 0
&& !fs->signal_frame) && !fs->signal_frame)
context->cfa -= 2047; {
long i;
context->cfa -= STACK_BIAS;
for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
_Unwind_SetGRPtr (context, i,
_Unwind_GetGRPtr (context, i) - STACK_BIAS);
}
} }
#else #else
......
! crti.s for solaris 2.0. ! crti.s for solaris 2.0.
! Copyright (C) 1992, 2008, 2009 Free Software Foundation, Inc. ! Copyright (C) 1992, 2008, 2009, 2011 Free Software Foundation, Inc.
! Written By David Vinayak Henkel-Wallace, June 1992 ! Written By David Vinayak Henkel-Wallace, June 1992
! !
! This file is free software; you can redistribute it and/or modify it ! This file is free software; you can redistribute it and/or modify it
...@@ -35,11 +35,22 @@ ...@@ -35,11 +35,22 @@
.type _init,#function .type _init,#function
.align 4 .align 4
_init: _init:
#ifdef _FLAT
#ifdef __sparcv9
stx %i7, [%sp+2167]
add %sp, -176, %sp
#else
st %i7, [%sp+60]
add %sp, -96, %sp
#endif
mov %o7, %i7
#else
#ifdef __sparcv9 #ifdef __sparcv9
save %sp, -176, %sp save %sp, -176, %sp
#else #else
save %sp, -96, %sp save %sp, -96, %sp
#endif #endif
#endif
.section ".fini" .section ".fini"
...@@ -48,8 +59,19 @@ _init: ...@@ -48,8 +59,19 @@ _init:
.type _fini,#function .type _fini,#function
.align 4 .align 4
_fini: _fini:
#ifdef _FLAT
#ifdef __sparcv9
stx %i7, [%sp+2167]
add %sp, -176, %sp
#else
st %i7, [%sp+60]
add %sp, -96, %sp
#endif
mov %o7, %i7
#else
#ifdef __sparcv9 #ifdef __sparcv9
save %sp, -176, %sp save %sp, -176, %sp
#else #else
save %sp, -96, %sp save %sp, -96, %sp
#endif #endif
#endif
! crtn.s for solaris 2.0. ! crtn.s for solaris 2.0.
! Copyright (C) 1992, 2008, 2009 Free Software Foundation, Inc. ! Copyright (C) 1992, 2008, 2009, 2011 Free Software Foundation, Inc.
! Written By David Vinayak Henkel-Wallace, June 1992 ! Written By David Vinayak Henkel-Wallace, June 1992
! !
! This file is free software; you can redistribute it and/or modify it ! This file is free software; you can redistribute it and/or modify it
...@@ -28,14 +28,36 @@ ...@@ -28,14 +28,36 @@
.section ".init" .section ".init"
.align 4 .align 4
#ifdef _FLAT
ret mov %i7, %o7
#ifdef __sparcv9
ldx [%sp+2343], %i7
sub %sp, -176, %sp
#else
ld [%sp+156], %i7
sub %sp, -96, %sp
#endif
#else
restore restore
#endif
jmp %o7+8
nop
.section ".fini" .section ".fini"
.align 4 .align 4
#ifdef _FLAT
ret mov %i7, %o7
#ifdef __sparcv9
ldx [%sp+2343], %i7
sub %sp, -176, %sp
#else
ld [%sp+156], %i7
sub %sp, -96, %sp
#endif
#else
restore restore
#endif
jmp %o7+8
nop
! Th-th-th-that is all folks! ! Th-th-th-that is all folks!
...@@ -164,7 +164,16 @@ sparc64_frob_update_context (struct _Unwind_Context *context, ...@@ -164,7 +164,16 @@ sparc64_frob_update_context (struct _Unwind_Context *context,
&& fs->regs.cfa_how == CFA_REG_OFFSET && fs->regs.cfa_how == CFA_REG_OFFSET
&& fs->regs.cfa_offset != 0 && fs->regs.cfa_offset != 0
&& !fs->signal_frame) && !fs->signal_frame)
context->cfa -= STACK_BIAS; {
long i;
context->cfa -= STACK_BIAS;
for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
if (fs->regs.reg[i].how == REG_SAVED_OFFSET)
_Unwind_SetGRPtr (context, i,
_Unwind_GetGRPtr (context, i) - STACK_BIAS);
}
} }
#else #else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment