asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize);
/* save CPU registers */
- for (regno = 0; regno <= PC_REGNUM; regno++)
+ for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++)
if (df_regs_ever_live_p (regno) && ! call_used_regs[regno])
if (! ((regno == FRAME_POINTER_REGNUM)
&& frame_pointer_needed))
k = 2*j;
/* change fp -> r5 due to the compile error on libgcc2.c */
- for (i = PC_REGNUM ; i >= 0 ; i--)
+ for (i = PC_REGNUM ; i >= R0_REGNUM ; i--)
if (df_regs_ever_live_p (i) && ! call_used_regs[i])
fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n",
(-fsize-2*j--)&0xffff, reg_names[i]);
return (fromfloat != tofloat);
}
+/* Return the class number of the smallest class containing
+ reg number REGNO. */
+enum reg_class
+pdp11_regno_reg_class (int regno)
+{
+ if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
+ return GENERAL_REGS;
+ else if (regno > AC3_REGNUM)
+ return NO_LOAD_FPU_REGS;
+ else if (regno >= AC0_REGNUM)
+ return LOAD_FPU_REGS;
+ else if (regno & 1)
+ return MUL_REGS;
+ else
+ return GENERAL_REGS;
+}
+
+
+static int
+pdp11_sp_frame_offset (void)
+{
+ int offset = 0, regno;
+ offset = get_frame_size();
+ for (regno = 0; regno <= PC_REGNUM; regno++)
+ if (df_regs_ever_live_p (regno) && ! call_used_regs[regno])
+ offset += 2;
+ for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++)
+ if (df_regs_ever_live_p (regno) && ! call_used_regs[regno])
+ offset += 8;
+
+ return offset;
+}
+
+/* Return the offset between two registers, one to be eliminated, and the other
+ its replacement, at the start of a routine. */
+
+int
+pdp11_initial_elimination_offset (int from, int to)
+{
+ int spoff;
+
+ if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+ return 4;
+ else if (from == FRAME_POINTER_REGNUM
+ && to == HARD_FRAME_POINTER_REGNUM)
+ return 0;
+ else
+ {
+ gcc_assert (to == STACK_POINTER_REGNUM);
+
+ /* Get the size of the register save area. */
+ spoff = pdp11_sp_frame_offset ();
+ if (from == FRAME_POINTER_REGNUM)
+ return spoff;
+
+ gcc_assert (from == ARG_POINTER_REGNUM);
+
+ /* If there is a frame pointer, that is saved too. */
+ if (frame_pointer_needed)
+ spoff += 2;
+
+ /* Account for the saved PC in the function call. */
+ return spoff + 2;
+ }
+}
/* A copy of output_addr_const modified for pdp11 expression syntax.
output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
reg 5 = fp; not necessarily!
*/
-/* don't let them touch fp regs for the time being !*/
-
#define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 1, 1, \
- 0, 0, 0, 0, 0, 0 }
+ 0, 0, 0, 0, 0, 0, 1, 1 }
/* don't know about fp */
#define CALL_USED_REGISTERS \
{1, 1, 0, 0, 0, 0, 1, 1, \
- 0, 0, 0, 0, 0, 0 }
+ 0, 0, 0, 0, 0, 0, 1, 1 }
/* Make sure everything's fine if we *don't* have an FPU.
if (!TARGET_FPU) \
{ \
COPY_HARD_REG_SET (x, reg_class_contents[(int)FPU_REGS]); \
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++ ) \
+ for (i = R0_REGNUM; i < FIRST_PSEUDO_REGISTER; i++ ) \
if (TEST_HARD_REG_BIT (x, i)) \
fixed_regs[i] = call_used_regs[i] = 1; \
} \
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
-/* Base register for access to arguments of the function. */
-#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM
-
/* Register in which static-chain is passed to a function. */
/* ??? - i don't want to give up a reg for this! */
#define STATIC_CHAIN_REGNUM 4
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
-#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0x00ff}, {0x0f00}, {0x3000}, {0x3f00}, {0x3fff}}
+#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0xc0ff}, {0x0f00}, {0x3000}, {0x3f00}, {0xffff}}
/* The same information, inverted:
Return the class number of the smallest class containing
reg number REGNO. This could be a conditional expression
or could index an array. */
-#define REGNO_REG_CLASS(REGNO) \
-((REGNO) >= AC0_REGNUM ? \
- ((REGNO) <= AC3_REGNUM ? LOAD_FPU_REGS : \
- NO_LOAD_FPU_REGS) : \
- (((REGNO) & 1) ? MUL_REGS : GENERAL_REGS))
-
+#define REGNO_REG_CLASS(REGNO) pdp11_regno_reg_class (REGNO)
/* The class value for index registers, and the one for base regs. */
#define INDEX_REG_CLASS GENERAL_REGS
stack */
extern int current_first_parm_offset;
-/* Offset of first parameter from the argument pointer register value.
- For the pdp11, this is nonzero to account for the return address.
- 1 - return address
- 2 - frame pointer, if needed
-
-*/
-#define FIRST_PARM_OFFSET(FNDECL) ((frame_pointer_needed) ? 4 : 2)
+/* Offset of first parameter from the argument pointer register value. */
+#define FIRST_PARM_OFFSET(FNDECL) 0
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
#define EXIT_IGNORE_STACK 1
-#define INITIAL_FRAME_POINTER_OFFSET(DEPTH_VAR) \
-{ \
- int offset, regno; \
- offset = get_frame_size(); \
- for (regno = 0; regno <= PC_REGNUM; regno++) \
- if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) \
- offset += 2; \
- for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++) \
- if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) \
- offset += 8; \
- /* offset -= 2; no fp on stack frame */ \
- (DEPTH_VAR) = offset; \
-}
-
+/* Definitions for register eliminations.
+
+ This is an array of structures. Each structure initializes one pair
+ of eliminable registers. The "from" register number is given first,
+ followed by "to". Eliminations of the same "from" register are listed
+ in order of preference.
+
+ There are two registers that can always be eliminated on the pdp11.
+ The frame pointer and the arg pointer can be replaced by either the
+ hard frame pointer or to the stack pointer, depending upon the
+ circumstances. The hard frame pointer is not used before reload and
+ so it is not eligible for elimination. */
+
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ ((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
+
\f
/* Addressing modes, and classification of registers for them. */
Since they use reg_renumber, they are safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
-#define REGNO_OK_FOR_INDEX_P(REGNO) \
- ((REGNO) <= PC_REGNUM || (unsigned) reg_renumber[REGNO] <= PC_REGNUM)
#define REGNO_OK_FOR_BASE_P(REGNO) \
- ((REGNO) <= PC_REGNUM || (unsigned) reg_renumber[REGNO] <= PC_REGNUM)
+ ((REGNO) <= PC_REGNUM || (unsigned) reg_renumber[REGNO] <= PC_REGNUM || \
+ (REGNO) == ARG_POINTER_REGNUM || (REGNO) == FRAME_POINTER_REGNUM)
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P (REGNO)
/* Now macros that check whether X is a register and also,
strictly, whether it is in a specified class.
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \
- "ac0", "ac1", "ac2", "ac3", "ac4", "ac5" }
+ "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap" }
/* Globalizing directive for a label. */
#define GLOBAL_ASM_OP "\t.globl "