/* Count the number of .file directives, so that .loc is up to date. */
int num_source_filenames = 0;
-/* Count of the number of functions created so far, in order to make
- unique labels for omitting the frame pointer. */
-int number_functions_processed = 0;
-
/* Count the number of sdb related labels are generated (to find block
start and end boundaries). */
int sdb_label_count = 0;
\f
/*
- * If the frame pointer has been eliminated, the offset for an auto
- * or argument will be based on the stack pointer. But this is not
- * what the debugger expects--it needs to find an offset off of the
- * frame pointer (whether it exists or not). So here we turn all
- * offsets into those based on the (possibly virtual) frame pointer.
+ * The MIPS debug format wants all automatic variables and arguments
+ * to be in terms of the virtual frame pointer (stack pointer before
+ * any adjustment in the function), while the MIPS 3.0 linker wants
+ * the frame pointer to be the stack pointer after the initial
+ * adjustment. So, we do the adjustment here. The arg pointer (which
+ * is eliminated) points to the virtual frame pointer, while the frame
+ * pointer (which may be eliminated) points to the stack pointer after
+ * the initial adjustments.
*/
int
if (!offset)
offset = INTVAL (offset2);
- if (reg == stack_pointer_rtx)
+ if (reg == stack_pointer_rtx || reg == frame_pointer_rtx)
{
int frame_size = (!current_frame_info.initialized)
? compute_frame_size (get_frame_size ())
offset = offset - frame_size;
}
-
- /* Any other register is, we hope, either the frame pointer,
- or a pseudo equivalent to the frame pointer. (Assign_parms
- copies the arg pointer to a pseudo if ARG_POINTER_REGNUM is
- equal to FRAME_POINTER_REGNUM, so references off of the
- arg pointer are all off a pseudo.) Seems like all we can
- do is to just return OFFSET and hope for the best. */
+ else if (reg != arg_pointer_rtx)
+ abort_with_insn (addr, "mips_debugger_offset called with non stack/frame/arg pointer.");
return offset;
}
break;
case REG:
+ if (REGNO (addr) == ARG_POINTER_REGNUM)
+ abort_with_insn (addr, "Arg pointer not eliminated.");
+
fprintf (file, "0(%s)", reg_names [REGNO (addr)]);
break;
if (!CONSTANT_P (offset))
abort_with_insn (addr, "PRINT_OPERAND_ADDRESS, illegal insn #2");
+ if (REGNO (reg) == ARG_POINTER_REGNUM)
+ abort_with_insn (addr, "Arg pointer not eliminated.");
+
output_addr_const (file, offset);
fprintf (file, "(%s)", reg_names [REGNO (reg)]);
}
| GP save for V.4 abi |
| |
+-----------------------+
- | |
- | local variables |
- | |
- +-----------------------+
| |
| fp register save |
| |
| |
+-----------------------+
| |
+ | local variables |
+ | |
+ +-----------------------+
+ | |
| alloca allocations |
| |
+-----------------------+
int fp_inc; /* 1 or 2 depending on the size of fp regs */
int fp_bits; /* bitmask to use for each fp register */
- extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0)
- -STARTING_FRAME_OFFSET);
-
- var_size = MIPS_STACK_ALIGN (size);
- args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
- total_size = var_size + args_size + extra_size;
gp_reg_size = 0;
fp_reg_size = 0;
mask = 0;
fmask = 0;
+ extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0));
+ var_size = MIPS_STACK_ALIGN (size);
+ args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
+
+ /* The MIPS 3.0 linker does not like functions that dynamically
+ allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
+ looks like we are trying to create a second frame pointer to the
+ function, so allocate some stack space to make it happy. */
+
+ if (args_size == 0 && current_function_calls_alloca)
+ args_size = 4*UNITS_PER_WORD;
+
+ total_size = var_size + args_size + extra_size;
/* Calculate space needed for gp registers. */
for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
if (mask)
{
- unsigned long offset = args_size + gp_reg_size - UNITS_PER_WORD;
+ unsigned long offset = args_size + var_size + gp_reg_size - UNITS_PER_WORD;
current_frame_info.gp_sp_offset = offset;
current_frame_info.gp_save_offset = offset - total_size;
}
if (fmask)
{
- unsigned long offset = args_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
+ unsigned long offset = args_size + var_size + gp_reg_rounded + fp_reg_size - 2*UNITS_PER_WORD;
current_frame_info.fp_sp_offset = offset;
current_frame_info.fp_save_offset = offset - total_size + UNITS_PER_WORD;
}
int size;
{
int tsize = current_frame_info.total_size;
- int vframe;
- int vreg;
ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
ASM_OUTPUT_SOURCE_LINE (file, DECL_SOURCE_LINE (current_function_decl));
if (tsize > 0 && TARGET_ABICALLS)
fprintf (file, "\t.cprestore %d\n", tsize + STARTING_FRAME_OFFSET);
- if (frame_pointer_needed)
- {
- vframe = 0;
- vreg = FRAME_POINTER_REGNUM;
- }
- else
- {
- vframe = tsize;
- vreg = STACK_POINTER_REGNUM;
- }
-
fprintf (file, "\t.frame\t%s,%d,%s\t\t# vars= %d, regs= %d/%d, args = %d, extra= %d\n",
- reg_names[ vreg ],
- vframe,
+ reg_names[ (frame_pointer_needed) ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM ],
+ tsize,
reg_names[31 + GP_REG_FIRST],
current_frame_info.var_size,
current_frame_info.num_gp,
mips_expand_prologue ()
{
int regno;
- int size;
int tsize;
tree fndecl = current_function_decl; /* current... is tooo long */
tree fntype = TREE_TYPE (fndecl);
}
}
- size = MIPS_STACK_ALIGN (get_frame_size ());
- tsize = compute_frame_size (size);
-
+ tsize = compute_frame_size (get_frame_size ());
if (tsize > 0)
{
rtx tsize_rtx = GEN_INT (tsize);
save_restore_insns (TRUE);
if (frame_pointer_needed)
- emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, tsize_rtx));
+ emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
}
}
fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
if (frame_pointer_needed)
- {
- char *fp_str = reg_names[FRAME_POINTER_REGNUM];
- if (tsize > 32767)
- fprintf (file,"\tsubu\t%s,%s,%s\t\t# sp not trusted here\n",
- sp_str, fp_str, t1_str);
- else
- fprintf (file,"\tsubu\t%s,%s,%d\t\t# sp not trusted here\n",
- sp_str, fp_str, tsize);
- }
+ fprintf (file, "\tmove\t%s,%s\t\t\t# sp not trusted here\n",
+ sp_str, reg_names[FRAME_POINTER_REGNUM]);
save_restore (file, "lw", "ld", "l.d");
int num_gp_regs = current_frame_info.gp_reg_size / 4;
int num_fp_regs = current_frame_info.fp_reg_size / 8;
int num_regs = num_gp_regs + num_fp_regs;
+ char *name = current_function_name;
+
+ if (name[0] == '*')
+ name++;
dslots_load_total += num_regs;
fprintf (stderr,
"%-20s fp=%c leaf=%c alloca=%c setjmp=%c stack=%4ld arg=%3ld reg=%2d/%d delay=%3d/%3dL %3d/%3dJ refs=%3d/%3d/%3d",
- current_function_name,
+ name,
(frame_pointer_needed) ? 'y' : 'n',
((current_frame_info.mask & (1 << 31)) != 0) ? 'n' : 'y',
(current_function_calls_alloca) ? 'y' : 'n',
mips_load_reg = (rtx)0;
mips_load_reg2 = (rtx)0;
current_frame_info = zero_frame_info;
- number_functions_processed++;
/* Restore the output file if optimizing the GP (optimizing the GP causes
the text to be diverted to a tempfile, so that data decls come before
if (tsize > 0)
{
if (frame_pointer_needed)
- emit_insn (gen_subsi3 (stack_pointer_rtx, frame_pointer_rtx, tsize_rtx));
+ emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
save_restore_insns (FALSE);
\n mips-tfile %{v*: -v} \
%{K: -I %b.o~} \
%{!K: %{save-temps: -I %b.o~}} \
- %{c:%W{o*}%{!o*:-o %b.o}}%{!c:-o %u.o} \
+ %{c:%W{o*}%{!o*:-o %b.o}}%{!c:-o %U.o} \
%{.s:%i} %{!.s:%g.s}}}"
#endif
\f
/* Print subsidiary information on the compiler version in use. */
-#define MIPS_VERSION "[AL 1.1, MM 23]"
+#define MIPS_VERSION "[AL 1.1, MM 24]"
#ifndef MACHINE_TYPE
#define MACHINE_TYPE "BSD Mips"
#define SDB_GENERATE_FAKE(BUFFER, NUMBER) \
sprintf ((BUFFER), ".%dfake", (NUMBER));
-/* Correct the offset of automatic variables and arguments
- if the frame pointer has been eliminated. */
+/* Correct the offset of automatic variables and arguments. Note that
+ the MIPS debug format wants all automatic variables and arguments
+ to be in terms of the virtual frame pointer (stack pointer before
+ any adjustment in the function), while the MIPS 3.0 linker wants
+ the frame pointer to be the stack pointer after the initial
+ adjustment. */
#define DEBUGGER_AUTO_OFFSET(X) mips_debugger_offset (X, 0)
#define DEBUGGER_ARG_OFFSET(OFFSET, X) mips_debugger_offset (X, OFFSET)
#define FRAME_POINTER_REQUIRED (current_function_calls_alloca)
/* Base register for access to arguments of the function. */
-#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM
+#define ARG_POINTER_REGNUM GP_REG_FIRST
/* Register in which static-chain is passed to a function. */
#define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 2)
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
-#define FRAME_GROWS_DOWNWARD
+/* #define FRAME_GROWS_DOWNWARD */
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
of the first local allocated. */
-#define STARTING_FRAME_OFFSET (-8)
+#define STARTING_FRAME_OFFSET current_function_outgoing_args_size
+
+/* Offset from the stack pointer register to an item dynamically
+ allocated on the stack, e.g., by `alloca'.
+
+ The default value for this macro is `STACK_POINTER_OFFSET' plus the
+ length of the outgoing arguments. The default is correct for most
+ machines. See `function.c' for details.
+
+ The MIPS 3.0 linker does not like functions that dynamically
+ allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
+ looks like we are trying to create a second frame pointer to the
+ function, so allocate some stack space to make it happy. */
+
+#define STACK_DYNAMIC_OFFSET(FUNDECL) \
+ ((current_function_outgoing_args_size == 0 && current_function_calls_alloca) \
+ ? 4*UNITS_PER_WORD \
+ : current_function_outgoing_args_size)
/* Structure to be filled in by compute_frame_size with register
save masks, and offsets for the current function. */
as of the start of the function body. This depends on the layout
of the fixed parts of the stack frame and on how registers are saved. */
-#define INITIAL_FRAME_POINTER_OFFSET(VAR) \
- ((VAR) = compute_frame_size (get_frame_size ()))
+/* #define INITIAL_FRAME_POINTER_OFFSET(VAR) \
+ ((VAR) = compute_frame_size (get_frame_size ())) */
+
+/* If defined, this macro specifies a table of register pairs used to
+ eliminate unneeded registers that point into the stack frame. If
+ it is not defined, the only elimination attempted by the compiler
+ is to replace references to the frame pointer with references to
+ the stack pointer.
+
+ The definition of this macro is a list of structure
+ initializations, each of which specifies an original and
+ replacement register.
+
+ On some machines, the position of the argument pointer is not
+ known until the compilation is completed. In such a case, a
+ separate hard register must be used for the argument pointer.
+ This register can be eliminated by replacing it with either the
+ frame pointer or the argument pointer, depending on whether or not
+ the frame pointer has been eliminated.
+
+ In this case, you might specify:
+ #define ELIMINABLE_REGS \
+ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+ Note that the elimination of the argument pointer with the stack
+ pointer is specified first since that is the preferred elimination. */
+
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+
+/* A C expression that returns non-zero if the compiler is allowed to
+ try to replace register number FROM-REG with register number
+ TO-REG. This macro need only be defined if `ELIMINABLE_REGS' is
+ defined, and will usually be the constant 1, since most of the
+ cases preventing register elimination are things that the compiler
+ already knows about. */
+
+#define CAN_ELIMINATE(FROM, TO) \
+ (!frame_pointer_needed \
+ || ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM))
+
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It
+ specifies the initial difference between the specified pair of
+ registers. This macro must be defined if `ELIMINABLE_REGS' is
+ defined. */
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+{ compute_frame_size (get_frame_size ()); \
+ if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) = 0; \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM) \
+ (OFFSET) = current_frame_info.total_size; \
+ else if ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) = current_frame_info.total_size; \
+ else \
+ abort (); \
+}
+
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
(get_attr_dslot (INSN) == DSLOT_NO \
&& get_attr_length (INSN) == 1 \
&& ! reg_mentioned_p (stack_pointer_rtx, PATTERN (INSN)) \
- && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (INSN)))
+ && ! reg_mentioned_p (frame_pointer_rtx, PATTERN (INSN)) \
+ && ! reg_mentioned_p (arg_pointer_rtx, PATTERN (INSN)))
/* Tell prologue and epilogue if register REGNO should be saved / restored. */
#define MUST_SAVE_REGISTER(regno) \
((regs_ever_live[regno] && !call_used_regs[regno]) \
|| (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) \
- || (regno == 31 && regs_ever_live[31]))
+ || (regno == (GP_REG_FIRST + 31) && regs_ever_live[GP_REG_FIRST + 31]))
/* ALIGN FRAMES on double word boundaries */
-#define MIPS_STACK_ALIGN(LOC) (((LOC)+7) & 0xfffffff8)
+#define MIPS_STACK_ALIGN(LOC) (((LOC)+7) & ~7)
\f
/* Output assembler code to FILE to increment profiler label # LABELNO
$Lb[0-9]+ Begin blocks for MIPS debug support
$Lc[0-9]+ Label for use in s<xx> operation.
$Le[0-9]+ End blocks for MIPS debug support
- $Lp\..+ Half-pic labels.
- $Ls[0-9]+ FP-SP difference if -fomit-frame-pointer */
+ $Lp\..+ Half-pic labels. */
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME.