((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. */
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;
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
{ MASK_ISA, MASK_V9},
};
const struct cpu_table *cpu;
+ unsigned int i;
int fpu;
#ifdef SUBTARGET_OVERRIDE_OPTIONS
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. */
/* 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. */
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)
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);
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)
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. */
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.
&& (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;
&& 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);
}
}
\f
+/* 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. */
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;
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. */
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. */
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
void
sparc_expand_prologue (void)
{
+ HOST_WIDE_INT size;
rtx insn;
int i;
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));
}
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
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);
}
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));
}
}
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. */
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
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;
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));
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. */
{
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 ();
}
/* 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,
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 ());
}
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
/* 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__} \
%{!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. */
{ "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 }, \
/* 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
{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, \
{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, \
{{ 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; \
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
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. */
\f
/* 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))
-\f
/* We need 2 words, so we can save the stack pointer and the return register
of the function containing a non-local goto target. */
-
#define STACK_SAVEAREA_MODE(LEVEL) \
((LEVEL) == SAVE_NONLOCAL ? (TARGET_ARCH64 ? TImode : DImode) : Pmode)
/* Length in units of the trampoline for entering a nested function. */
-
#define TRAMPOLINE_SIZE (TARGET_ARCH64 ? 32 : 16)
/* Alignment required for trampolines, in bits. */
-
#define TRAMPOLINE_ALIGNMENT 128
\f
/* Generate RTL to flush the register windows so as to make arbitrary frames
available. */
-#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
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 \
+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
#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