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>
* 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);
extern void order_regs_for_local_alloc (void);
extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int);
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 int check_pic (int);
extern int short_branch (int, int);
......
......@@ -287,21 +287,6 @@ const struct processor_costs *sparc_costs = &cypress_costs;
((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic)
#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.
HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
eliminate it. You must use -fomit-frame-pointer to get that. */
......@@ -341,28 +326,46 @@ char sparc_leaf_regs[] =
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. */
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,
so that the SPARC leaf function optimization can be applied.
Private version of current_function_uses_only_leaf_regs, see
sparc_expand_prologue for the rationale. */
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. */
bool prologue_data_valid_p;
};
#define sparc_leaf_function_p cfun->machine->leaf_function_p
#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p
/* Register we pretend to think the frame pointer is allocated to.
Normally, this is %fp, but if we are in a leaf procedure, this
is %sp+"something". We record "something" separately as it may
be too big for reg+constant addressing. */
static rtx frame_base_reg;
static HOST_WIDE_INT frame_base_offset;
#define sparc_frame_size cfun->machine->frame_size
#define sparc_apparent_frame_size cfun->machine->apparent_frame_size
#define sparc_frame_base_reg cfun->machine->frame_base_reg
#define sparc_frame_base_offset cfun->machine->frame_base_offset
#define sparc_n_global_fp_regs cfun->machine->n_global_fp_regs
#define sparc_leaf_function_p cfun->machine->leaf_function_p
#define sparc_save_local_in_regs_p cfun->machine->save_local_in_regs_p
#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p
/* 1 if the next opcode is to be specially indented. */
int sparc_indent_opcode = 0;
......@@ -387,8 +390,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 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_epilogue (FILE *, HOST_WIDE_INT);
#ifdef TARGET_SOLARIS
......@@ -764,6 +765,7 @@ sparc_option_override (void)
{ MASK_ISA, MASK_V9},
};
const struct cpu_table *cpu;
unsigned int i;
int fpu;
#ifdef SUBTARGET_OVERRIDE_OPTIONS
......@@ -808,6 +810,14 @@ sparc_option_override (void)
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 */
/* Set the default CPU. */
......@@ -2769,9 +2779,11 @@ eligible_for_restore_insn (rtx trial, bool return_p)
/* If we have the 'return' instruction, anything that does not use
local or output registers and can go into a delay slot wins. */
else if (return_p && TARGET_V9 && ! epilogue_renumber (&pat, 1)
&& (get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE))
else if (return_p
&& TARGET_V9
&& !epilogue_renumber (&pat, 1)
&& get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE)
return 1;
/* The 'restore src1,src2,dest' pattern for SImode. */
......@@ -2806,8 +2818,7 @@ eligible_for_restore_insn (rtx trial, bool return_p)
return 0;
}
/* Return nonzero if TRIAL can go into the function return's
delay slot. */
/* Return nonzero if TRIAL can go into the function return's delay slot. */
int
eligible_for_return_delay (rtx trial)
......@@ -2825,10 +2836,10 @@ eligible_for_return_delay (rtx trial)
if (crtl->calls_eh_return)
return 0;
/* In the case of a true leaf function, anything can go into the slot. */
if (sparc_leaf_function_p)
return get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE;
/* In the case of a leaf or flat function, anything can go into the slot. */
if (sparc_leaf_function_p || TARGET_FLAT)
return
get_attr_in_uncond_branch_delay (trial) == IN_UNCOND_BRANCH_DELAY_TRUE;
pat = PATTERN (trial);
......@@ -2843,15 +2854,14 @@ eligible_for_return_delay (rtx trial)
with FP_REGS. */
if (REGNO (SET_DEST (pat)) >= 32)
return (TARGET_V9
&& ! epilogue_renumber (&pat, 1)
&& (get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE));
&& !epilogue_renumber (&pat, 1)
&& get_attr_in_uncond_branch_delay (trial)
== IN_UNCOND_BRANCH_DELAY_TRUE);
return eligible_for_restore_insn (trial, true);
}
/* Return nonzero if TRIAL can go into the sibling call's
delay slot. */
/* Return nonzero if TRIAL can go into the sibling call's delay slot. */
int
eligible_for_sibcall_delay (rtx trial)
......@@ -2866,7 +2876,7 @@ eligible_for_sibcall_delay (rtx 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,
we have to restore %o7 in the delay slot. */
......@@ -3117,11 +3127,15 @@ legitimate_pic_operand_p (rtx x)
return true;
}
#define RTX_OK_FOR_OFFSET_P(X) \
(CONST_INT_P (X) && INTVAL (X) >= -0x1000 && INTVAL (X) < 0x1000 - 8)
#define RTX_OK_FOR_OFFSET_P(X, MODE) \
(CONST_INT_P (X) \
&& INTVAL (X) >= -0x1000 \
&& INTVAL (X) < (0x1000 - GET_MODE_SIZE (MODE)))
#define RTX_OK_FOR_OLO10_P(X) \
(CONST_INT_P (X) && INTVAL (X) >= -0x1000 && INTVAL (X) < 0xc00 - 8)
#define RTX_OK_FOR_OLO10_P(X, MODE) \
(CONST_INT_P (X) \
&& INTVAL (X) >= -0x1000 \
&& INTVAL (X) < (0xc00 - GET_MODE_SIZE (MODE)))
/* Handle the TARGET_LEGITIMATE_ADDRESS_P target hook.
......@@ -3163,7 +3177,7 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
&& (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
|| ((REG_P (rs1)
|| GET_CODE (rs1) == SUBREG)
&& RTX_OK_FOR_OFFSET_P (rs2)))
&& RTX_OK_FOR_OFFSET_P (rs2, mode)))
{
imm1 = rs2;
rs2 = NULL;
......@@ -3193,7 +3207,7 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
&& GET_CODE (rs1) == LO_SUM
&& TARGET_ARCH64
&& ! TARGET_CM_MEDMID
&& RTX_OK_FOR_OLO10_P (rs2))
&& RTX_OK_FOR_OLO10_P (rs2, mode))
{
rs2 = NULL;
imm1 = XEXP (rs1, 1);
......@@ -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
during the reload pass and also by sparc_expand_prologue. */
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
+ REG_PARM_STACK_SPACE (current_function_decl));
int n_regs = 0; /* N_REGS is the number of 4-byte regs saved thus far. */
int i;
HOST_WIDE_INT frame_size, apparent_frame_size;
int args_size, n_global_fp_regs = 0;
bool save_local_in_regs_p = false;
unsigned int i;
if (TARGET_ARCH64)
{
for (i = 0; i < 8; i++)
if (df_regs_ever_live_p (i) && ! call_used_regs[i])
n_regs += 2;
}
/* If the function allocates dynamic stack space, the dynamic offset is
computed early and contains REG_PARM_STACK_SPACE, so we need to cope. */
if (leaf_function && !cfun->calls_alloca)
args_size = 0;
else
{
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;
}
args_size = crtl->outgoing_args_size + REG_PARM_STACK_SPACE (cfun->decl);
for (i = 32; i < (TARGET_V9 ? 96 : 64); 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;
/* Calculate space needed for global registers. */
if (TARGET_ARCH64)
for (i = 0; i < 8; i++)
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. */
num_gfregs = n_regs;
/* In the flat window model, find out which local and in registers need to
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
&& n_regs == 0
&& size == 0
&& crtl->outgoing_args_size == 0)
actual_fsize = apparent_fsize = 0;
/* Calculate space needed for FP registers. */
for (i = 32; i < (TARGET_V9 ? 96 : 64); 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;
if (size == 0
&& n_global_fp_regs == 0
&& args_size == 0
&& !save_local_in_regs_p)
frame_size = apparent_frame_size = 0;
else
{
/* We subtract STARTING_FRAME_OFFSET, remember it's negative. */
apparent_fsize = (size - STARTING_FRAME_OFFSET + 7) & -8;
apparent_fsize += n_regs * 4;
actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8);
apparent_frame_size = (size - STARTING_FRAME_OFFSET + 7) & -8;
apparent_frame_size += n_global_fp_regs * 4;
/* 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.
If a SAVE must be done, or there is a stack-local variable,
the register window area must be allocated. */
if (! leaf_function_p || size > 0)
actual_fsize += FIRST_PARM_OFFSET (current_function_decl);
/* Set up values for use in prologue and epilogue. */
sparc_frame_size = frame_size;
sparc_apparent_frame_size = apparent_frame_size;
sparc_n_global_fp_regs = n_global_fp_regs;
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. */
......@@ -4342,43 +4435,66 @@ output_probe_stack_range (rtx reg1, rtx reg2)
return "";
}
/* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET
as needed. LOW should be double-word aligned for 32-bit registers.
Return the new OFFSET. */
/* Emit code to save/restore registers from LOW to HIGH at BASE+OFFSET as
needed. LOW is supposed to be double-word aligned for 32-bit registers.
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
#define SORR_RESTORE 1
typedef bool (*sorr_pred_t) (unsigned int, int);
typedef enum { SORR_NONE, SORR_ADVANCE, SORR_SAVE, SORR_RESTORE } sorr_act_t;
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;
int i;
if (TARGET_ARCH64 && high <= 32)
{
int fp_offset = -1;
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));
if (action == SORR_SAVE)
if (action_true == SORR_SAVE)
{
insn = emit_move_insn (mem, gen_rtx_REG (DImode, i));
RTX_FRAME_RELATED_P (insn) = 1;
}
else /* action == SORR_RESTORE */
emit_move_insn (gen_rtx_REG (DImode, i), mem);
else /* action_true == SORR_RESTORE */
{
/* 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;
}
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
{
for (i = low; i < high; i += 2)
{
bool reg0 = df_regs_ever_live_p (i) && ! call_used_regs[i];
bool reg1 = df_regs_ever_live_p (i+1) && ! call_used_regs[i+1];
bool reg0 = save_p (i, leaf_function);
bool reg1 = save_p (i + 1, leaf_function);
enum machine_mode mode;
int regno;
......@@ -4399,15 +4515,35 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
offset += 4;
}
else
continue;
{
if (action_false == SORR_ADVANCE)
offset += 8;
continue;
}
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));
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);
/* Always preserve double-word alignment. */
......@@ -4418,36 +4554,54 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
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
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;
rtx base;
if (offset < -4096 || offset + sparc_n_global_fp_regs * 4 > 4095)
{
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
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)));
base = emit_adjust_base_to_offset (base, offset);
offset = 0;
}
else
base = frame_base_reg;
offset = save_or_restore_regs (0, 8, base, offset, action);
save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action);
emit_save_or_restore_regs (16, 32, base, offset, sparc_leaf_function_p,
save_local_or_in_reg_p, action, SORR_ADVANCE);
}
/* Generate a save_register_window insn. */
......@@ -4461,6 +4615,39 @@ gen_save_register_window (rtx 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. */
static rtx
......@@ -4492,6 +4679,7 @@ gen_stack_pointer_dec (rtx decrement)
void
sparc_expand_prologue (void)
{
HOST_WIDE_INT size;
rtx insn;
int i;
......@@ -4520,70 +4708,52 @@ sparc_expand_prologue (void)
sparc_leaf_function_p
= optimize > 0 && current_function_is_leaf && only_leaf_regs_used ();
/* Need to use actual_fsize, since we are also allocating
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;
size = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
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)
sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, actual_fsize);
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
if (sparc_leaf_function_p)
{
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. */ ;
if (size == 0)
; /* do nothing. */
else if (sparc_leaf_function_p)
{
if (actual_fsize <= 4096)
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-actual_fsize)));
else if (actual_fsize <= 8192)
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)));
/* %sp is still the CFA register. */
RTX_FRAME_RELATED_P (insn) = 1;
insn
= emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
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 (-actual_fsize));
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 (-actual_fsize)));
gen_stack_pointer_inc (GEN_INT (-size)));
}
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
if (actual_fsize <= 4096)
insn = emit_insn (gen_save_register_window (GEN_INT (-actual_fsize)));
else if (actual_fsize <= 8192)
if (size <= 4096)
insn = emit_insn (gen_save_register_window (GEN_INT (-size)));
else if (size <= 8192)
{
insn = emit_insn (gen_save_register_window (GEN_INT (-4096)));
/* %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
{
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));
}
......@@ -4592,12 +4762,179 @@ sparc_expand_prologue (void)
RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
}
if (num_gfregs)
emit_save_or_restore_regs (SORR_SAVE);
if (sparc_leaf_function_p)
{
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. */
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;
}
/* 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
......@@ -4607,7 +4944,8 @@ static void
sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
/* 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);
}
......@@ -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. */
void
sparc_expand_epilogue (void)
sparc_expand_epilogue (bool for_eh)
{
if (num_gfregs)
emit_save_or_restore_regs (SORR_RESTORE);
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 (actual_fsize == 0)
/* do nothing. */ ;
if (size == 0 || for_eh)
; /* do nothing. */
else if (sparc_leaf_function_p)
{
if (actual_fsize <= 4096)
emit_insn (gen_stack_pointer_dec (GEN_INT (- actual_fsize)));
else if (actual_fsize <= 8192)
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 - actual_fsize)));
emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - size)));
}
else
{
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));
}
}
......@@ -4648,8 +5051,10 @@ bool
sparc_can_use_return_insn_p (void)
{
return sparc_prologue_data_valid_p
&& num_gfregs == 0
&& (actual_fsize == 0 || !sparc_leaf_function_p);
&& sparc_n_global_fp_regs == 0
&& 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. */
......@@ -4728,15 +5133,42 @@ output_restore (rtx pat)
const char *
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
register window, which frees us from dealing with the convoluted
/* This is a leaf or flat function so we don't have to bother restoring
the register window, which frees us from dealing with the convoluted
semantics of restore/return. We simply output the jump to the
return address and the insn in the delay slot (if any). */
gcc_assert (! crtl->calls_eh_return);
return "jmp\t%%o7+%)%#";
}
else
......@@ -4746,28 +5178,7 @@ output_return (rtx insn)
combined with the 'restore' instruction or put in the delay slot of
the 'return' instruction. */
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_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)
if (final_sequence)
{
rtx delay, pat;
......@@ -4815,10 +5226,10 @@ output_sibcall (rtx insn, rtx 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
register window. We simply output the jump to the function and
/* This is a leaf or flat function so we don't have to bother restoring
the register window. We simply output the jump to the function and
the insn in the delay slot (if any). */
gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence));
......@@ -9352,7 +9763,13 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
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
output_sibcall that we are in a leaf function. */
......@@ -9473,8 +9890,6 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
{
spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */
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 */
scratch = sparc_legitimize_pic_address (funexp, scratch);
seq = get_insns ();
......@@ -9593,8 +10008,10 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
}
/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
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
sparc_dwarf_handle_frame_unspec (const char *label,
rtx pattern ATTRIBUTE_UNUSED,
......@@ -9810,6 +10227,16 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
static bool
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 ());
}
......@@ -9880,6 +10307,14 @@ sparc_conditional_register_usage (void)
fixed_regs[4] = 1;
else if (fixed_regs[4] == 2)
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
......
......@@ -360,7 +360,6 @@ extern enum cmodel sparc_cmodel;
/* Common CPP definitions used by CPP_SPEC amongst the various targets
for handling -mcpu=xxx switches. */
#define CPP_CPU_SPEC "\
%{msoft-float:-D_SOFT_FLOAT} \
%{mcpu=sparclet:-D__sparclet__} %{mcpu=tsc701:-D__sparclet__} \
%{mcpu=sparclite:-D__sparclite__} \
%{mcpu=f930:-D__sparclite__} %{mcpu=f934:-D__sparclite__} \
......@@ -388,14 +387,18 @@ extern enum cmodel sparc_cmodel;
%{!m32:%{!m64:%(cpp_arch_default)}} \
"
/* Macro to distinguish endianness. */
#define CPP_ENDIAN_SPEC "\
%{mlittle-endian:-D__LITTLE_ENDIAN__}"
/* Macros to distinguish the endianness, window model and FP support. */
#define CPP_OTHER_SPEC "\
%{mlittle-endian:-D__LITTLE_ENDIAN__} \
%{mflat:-D_FLAT} \
%{msoft-float:-D_SOFT_FLOAT} \
"
/* Macros to distinguish the particular subtarget. */
#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
because it can't turn off the usual meaning of making debugging dumps. */
......@@ -464,7 +467,7 @@ extern enum cmodel sparc_cmodel;
{ "cpp_arch64", CPP_ARCH64_SPEC }, \
{ "cpp_arch_default", CPP_ARCH_DEFAULT_SPEC },\
{ "cpp_arch", CPP_ARCH_SPEC }, \
{ "cpp_endian", CPP_ENDIAN_SPEC }, \
{ "cpp_other", CPP_OTHER_SPEC }, \
{ "cpp_subtarget", CPP_SUBTARGET_SPEC }, \
{ "asm_cpu", ASM_CPU_SPEC }, \
{ "asm_cpu_default", ASM_CPU_DEFAULT_SPEC }, \
......@@ -687,7 +690,7 @@ extern enum cmodel sparc_cmodel;
/* Argument passing regs. */
#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
/* 1 for registers that have pervasive standard uses
......@@ -721,7 +724,7 @@ extern enum cmodel sparc_cmodel;
{1, 0, 2, 2, 2, 2, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 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, \
......@@ -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, \
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, \
......@@ -1223,13 +1226,11 @@ extern char leaf_reg_remap[];
{{ FRAME_POINTER_REGNUM, STACK_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) \
do { \
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 \
(OFFSET) = 0; \
(OFFSET) += SPARC_STACK_BIAS; \
......@@ -1247,7 +1248,7 @@ extern char leaf_reg_remap[];
Return OUT if register number OUT is not an outbound register. */
#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
C expression returns the register number as seen by the calling function
......@@ -1255,14 +1256,14 @@ extern char leaf_reg_remap[];
Return IN if register number IN is not an inbound register. */
#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
C expression returns true if the register is call-saved but is in the
register window. */
#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
untyped_call. */
......@@ -1373,35 +1374,27 @@ do { \
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
No definition is equivalent to always zero. */
functions that have frame pointers. */
#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
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)
/* Alignment required for trampolines, in bits. */
#define TRAMPOLINE_ALIGNMENT 128
/* Generate RTL to flush the register windows so as to make arbitrary frames
available. */
#define SETUP_FRAME_ADDRESSES() \
emit_insn (gen_flush_register_windows ())
#define SETUP_FRAME_ADDRESSES() \
do { \
if (!TARGET_FLAT) \
emit_insn (gen_flush_register_windows ());\
} while (0)
/* Given an rtx for the address of a frame,
return an rtx for the address of the word in the frame
......@@ -1428,9 +1421,10 @@ do { \
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
returns, and +12 for structure returns. */
#define RETURN_ADDR_REGNUM 31
#define RETURN_ADDR_RTX(count, frame) \
((count == -1) \
? gen_rtx_REG (Pmode, 31) \
? gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM) \
: gen_rtx_MEM (Pmode, \
memory_address (Pmode, plus_constant (frame, \
15 * UNITS_PER_WORD \
......@@ -1440,9 +1434,11 @@ do { \
+12, but always using +8 is close enough for frame unwind purposes.
Actually, just using %o7 is close enough for unwinding, but %o7+8
is something you can return to. */
#define INCOMING_RETURN_ADDR_REGNUM 15
#define INCOMING_RETURN_ADDR_RTX \
plus_constant (gen_rtx_REG (word_mode, 15), 8)
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (15)
plus_constant (gen_rtx_REG (word_mode, INCOMING_RETURN_ADDR_REGNUM), 8)
#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
for the current function. On sparc64, we have to account for the stack
......@@ -1450,9 +1446,17 @@ do { \
#define INCOMING_FRAME_SP_OFFSET SPARC_STACK_BIAS
/* 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_STACKADJ_RTX gen_rtx_REG (Pmode, 1) /* %g1 */
#define EH_RETURN_HANDLER_RTX gen_rtx_REG (Pmode, 31) /* %i7 */
#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_RETURN_REGNUM)
/* 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
is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is
......
......@@ -164,7 +164,7 @@
(define_attr "calls_eh_return" "false,true"
(symbol_ref "(crtl->calls_eh_return != 0
? CALLS_EH_RETURN_TRUE : CALLS_EH_RETURN_FALSE)"))
(define_attr "leaf_function" "false,true"
(symbol_ref "(current_function_uses_only_leaf_regs != 0
? LEAF_FUNCTION_TRUE : LEAF_FUNCTION_FALSE)"))
......@@ -173,6 +173,10 @@
(symbol_ref "(flag_delayed_branch != 0
? DELAYED_BRANCH_TRUE : DELAYED_BRANCH_FALSE)"))
(define_attr "flat" "false,true"
(symbol_ref "(TARGET_FLAT != 0
? FLAT_TRUE : FLAT_FALSE)"))
;; Length (in # of insns).
;; Beware that setting a length greater or equal to 3 for conditional branches
;; has a side-effect (see output_cbranch and output_v9branch).
......@@ -6265,7 +6269,10 @@
[(const_int 0)]
""
{
sparc_expand_prologue ();
if (TARGET_FLAT)
sparc_flat_expand_prologue ();
else
sparc_expand_prologue ();
DONE;
})
......@@ -6282,25 +6289,87 @@
(set (reg:P 14) (unspec_volatile:P [(reg:P 14)
(match_operand:P 0 "arith_operand" "rI")] UNSPECV_SAVEW))
(set (reg:P 31) (reg:P 15))]
""
"!TARGET_FLAT"
"save\t%%sp, %0, %%sp"
[(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"
[(return)]
""
{
sparc_expand_epilogue ();
if (TARGET_FLAT)
sparc_flat_expand_epilogue (false);
else
sparc_expand_epilogue (false);
})
(define_expand "sibcall_epilogue"
[(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;
})
(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"
[(return)]
"sparc_can_use_return_insn_p ()"
......@@ -6312,16 +6381,19 @@
"* return output_return (insn);"
[(set_attr "type" "return")
(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")
(const_int 2)
(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")
(if_then_else (eq_attr "delayed_branch" "true")
(const_int 2)
......@@ -6367,8 +6439,7 @@
if (! TARGET_ARCH64)
{
rtx rtnreg = gen_rtx_REG (SImode, (current_function_uses_only_leaf_regs
? 15 : 31));
rtx rtnreg = gen_rtx_REG (SImode, RETURN_ADDR_REGNUM);
rtx value = gen_reg_rtx (SImode);
/* Fetch the instruction where we will return to and see if it's an unimp
......@@ -6449,7 +6520,7 @@
{
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 */
operands[3] = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
})
(define_expand "restore_stack_nonlocal"
......@@ -6474,7 +6545,8 @@
/* 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 ());
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, hard_frame_pointer_rtx));
......
......@@ -33,6 +33,10 @@ msoft-float
Target RejectNegative InverseMask(FPU)
Do not use hardware FP
mflat
Target Report Mask(FLAT)
Use flat register window model
munaligned-doubles
Target Report Mask(UNALIGNED_DOUBLES)
Assume possible double misalignment
......
......@@ -32,8 +32,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
echo '#define FLOAT' > fp-bit.c
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
MULTILIB_OPTIONS = msoft-float mcpu=v8
MULTILIB_DIRNAMES = soft v8
MULTILIB_OPTIONS = msoft-float mcpu=v8 mflat
MULTILIB_DIRNAMES = soft v8 flat
MULTILIB_MATCHES = msoft-float=mno-fpu
LIBGCC = stmp-multilib
......
......@@ -34,8 +34,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
# Multilibs for LEON
# LEON is a SPARC-V8, but the AT697 implementation has a bug in the
# V8-specific instructions.
MULTILIB_OPTIONS = mcpu=v7 msoft-float
MULTILIB_DIRNAMES = v7 soft
MULTILIB_OPTIONS = mcpu=v7 msoft-float mflat
MULTILIB_DIRNAMES = v7 soft flat
MULTILIB_MATCHES = mcpu?v7=mv7 msoft-float=mno-fpu
LIBGCC = stmp-multilib
......
......@@ -863,7 +863,7 @@ See RS/6000 and PowerPC Options.
-mtune=@var{cpu-type} @gol
-mcmodel=@var{code-model} @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
-mhard-quad-float -msoft-quad-float @gol
-mlittle-endian @gol
......@@ -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
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
@itemx -mhard-float
@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>
* gfortran.dg/coarray/sync_1.f90: New test for
......
......@@ -4,7 +4,7 @@
for leaf functions, the function was still leaf, but LEAF_REG_REMAP
returned -1 for some registers (like %o0). */
/* { dg-do compile } */
/* { dg-options "-O2 -g" } */
/* { dg-options "-O2 -g -mflat" { target sparc*-*-* } } */
void foo (char *a, char *b, char *c, char *d)
{
......
/* { dg-do compile } */
/* { dg-skip-if "no register windows" { *-*-* } { "-mflat" } { "" } } */
/* { dg-require-effective-target ilp32 } */
/* { 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)
toto (&res);
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 ()
{
......@@ -20,4 +21,4 @@ int bar2 ()
toto (&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>
* enable-execute-stack-empty.c: New file.
......
......@@ -27,6 +27,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#if defined(__arch64__)
#undef STACK_BIAS
#define STACK_BIAS 2047
/* 64-bit SPARC version */
#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
......@@ -49,7 +52,8 @@ sparc64_fallback_frame_state (struct _Unwind_Context *context,
fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
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);
fs->regs.cfa_how = CFA_REG_OFFSET;
fs->regs.cfa_reg = __builtin_dwarf_sp_column ();
......@@ -112,7 +116,16 @@ sparc64_frob_update_context (struct _Unwind_Context *context,
&& fs->regs.cfa_how == CFA_REG_OFFSET
&& fs->regs.cfa_offset != 0
&& !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
......
! 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
!
! This file is free software; you can redistribute it and/or modify it
......@@ -35,11 +35,22 @@
.type _init,#function
.align 4
_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
save %sp, -176, %sp
#else
save %sp, -96, %sp
#endif
#endif
.section ".fini"
......@@ -48,8 +59,19 @@ _init:
.type _fini,#function
.align 4
_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
save %sp, -176, %sp
#else
save %sp, -96, %sp
#endif
#endif
! 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
!
! This file is free software; you can redistribute it and/or modify it
......@@ -28,14 +28,36 @@
.section ".init"
.align 4
ret
#ifdef _FLAT
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
#endif
jmp %o7+8
nop
.section ".fini"
.align 4
ret
#ifdef _FLAT
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
#endif
jmp %o7+8
nop
! Th-th-th-that is all folks!
......@@ -164,7 +164,16 @@ sparc64_frob_update_context (struct _Unwind_Context *context,
&& fs->regs.cfa_how == CFA_REG_OFFSET
&& fs->regs.cfa_offset != 0
&& !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
......
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