Commit 8662b2ba by Richard Henderson Committed by Richard Henderson

pdp11.md (define_c_enum "unspecv"): New.

	* config/pdp11/pdp11.md (define_c_enum "unspecv"): New.
	(prologue, epilogue): New.
	(return, *rts): New.
	(blockage, setd, seti): New.
	* config/pdp11/pdp11.c (TARGET_ASM_FUNCTION_PROLOGUE): Remove.
	(TARGET_ASM_FUNCTION_EPILOGUE): Remove.
	(pdp11_saved_regno): New.
	(pdp11_expand_prologue): Rename from pdp11_output_function_prologue;
	generate rtl instead of text.
	(pdp11_expand_epilogue): Similarly from pdp11_output_function_epilogue.
	(pdp11_sp_frame_offset): Export.  Use pdp11_saved_regno.
	* config/pdp11/pdp11-protos.h: Update.

From-SVN: r176082
parent 28b21ebb
2011-07-09 Richard Henderson <rth@redhat.com> 2011-07-09 Richard Henderson <rth@redhat.com>
* config/pdp11/pdp11.md (define_c_enum "unspecv"): New.
(prologue, epilogue): New.
(return, *rts): New.
(blockage, setd, seti): New.
* config/pdp11/pdp11.c (TARGET_ASM_FUNCTION_PROLOGUE): Remove.
(TARGET_ASM_FUNCTION_EPILOGUE): Remove.
(pdp11_saved_regno): New.
(pdp11_expand_prologue): Rename from pdp11_output_function_prologue;
generate rtl instead of text.
(pdp11_expand_epilogue): Similarly from pdp11_output_function_epilogue.
(pdp11_sp_frame_offset): Export. Use pdp11_saved_regno.
* config/pdp11/pdp11-protos.h: Update.
2011-07-09 Richard Henderson <rth@redhat.com>
* config/rs6000/rs6000.c (rs6000_output_function_prologue): Don't * config/rs6000/rs6000.c (rs6000_output_function_prologue): Don't
try to insert an rtl prologue here. try to insert an rtl prologue here.
(rs6000_output_function_epilogue): Similarly. (rs6000_output_function_epilogue): Similarly.
......
...@@ -38,6 +38,7 @@ typedef enum { no_action, dec_before, inc_after } pdp11_action; ...@@ -38,6 +38,7 @@ typedef enum { no_action, dec_before, inc_after } pdp11_action;
typedef enum { little, either, big } pdp11_partorder; typedef enum { little, either, big } pdp11_partorder;
extern bool pdp11_expand_operands (rtx *, rtx [][2], int, extern bool pdp11_expand_operands (rtx *, rtx [][2], int,
pdp11_action *, pdp11_partorder); pdp11_action *, pdp11_partorder);
extern int pdp11_sp_frame_offset (void);
extern int pdp11_initial_elimination_offset (int, int); extern int pdp11_initial_elimination_offset (int, int);
extern enum reg_class pdp11_regno_reg_class (int); extern enum reg_class pdp11_regno_reg_class (int);
...@@ -45,3 +46,5 @@ extern enum reg_class pdp11_regno_reg_class (int); ...@@ -45,3 +46,5 @@ extern enum reg_class pdp11_regno_reg_class (int);
extern void output_ascii (FILE *, const char *, int); extern void output_ascii (FILE *, const char *, int);
extern void pdp11_asm_output_var (FILE *, const char *, int, int, bool); extern void pdp11_asm_output_var (FILE *, const char *, int, int, bool);
extern void pdp11_expand_prologue (void);
extern void pdp11_expand_epilogue (void);
...@@ -141,8 +141,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED, ...@@ -141,8 +141,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
static const char *singlemove_string (rtx *); static const char *singlemove_string (rtx *);
static bool pdp11_assemble_integer (rtx, unsigned int, int); static bool pdp11_assemble_integer (rtx, unsigned int, int);
static void pdp11_output_function_prologue (FILE *, HOST_WIDE_INT);
static void pdp11_output_function_epilogue (FILE *, HOST_WIDE_INT);
static bool pdp11_rtx_costs (rtx, int, int, int *, bool); static bool pdp11_rtx_costs (rtx, int, int, int *, bool);
static bool pdp11_return_in_memory (const_tree, const_tree); static bool pdp11_return_in_memory (const_tree, const_tree);
static rtx pdp11_function_value (const_tree, const_tree, bool); static rtx pdp11_function_value (const_tree, const_tree, bool);
...@@ -166,11 +164,6 @@ static bool pdp11_legitimate_constant_p (enum machine_mode, rtx); ...@@ -166,11 +164,6 @@ static bool pdp11_legitimate_constant_p (enum machine_mode, rtx);
#undef TARGET_ASM_INTEGER #undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER pdp11_assemble_integer #define TARGET_ASM_INTEGER pdp11_assemble_integer
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE pdp11_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE pdp11_output_function_epilogue
#undef TARGET_ASM_OPEN_PAREN #undef TARGET_ASM_OPEN_PAREN
#define TARGET_ASM_OPEN_PAREN "[" #define TARGET_ASM_OPEN_PAREN "["
#undef TARGET_ASM_CLOSE_PAREN #undef TARGET_ASM_CLOSE_PAREN
...@@ -227,95 +220,92 @@ static bool pdp11_legitimate_constant_p (enum machine_mode, rtx); ...@@ -227,95 +220,92 @@ static bool pdp11_legitimate_constant_p (enum machine_mode, rtx);
#undef TARGET_LEGITIMATE_CONSTANT_P #undef TARGET_LEGITIMATE_CONSTANT_P
#define TARGET_LEGITIMATE_CONSTANT_P pdp11_legitimate_constant_p #define TARGET_LEGITIMATE_CONSTANT_P pdp11_legitimate_constant_p
/* /* A helper function to determine if REGNO should be saved in the
stream is a stdio stream to output the code to. current function's stack frame. */
size is an int: how many units of temporary storage to allocate.
Refer to the array `regs_ever_live' to determine which registers
to save; `regs_ever_live[I]' is nonzero if register number I
is ever used in the function. This macro is responsible for
knowing which registers should not be saved even if used.
*/
static void static inline bool
pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size) pdp11_saved_regno (unsigned regno)
{ {
HOST_WIDE_INT fsize = ((size) + 1) & ~1; return !call_used_regs[regno] && df_regs_ever_live_p (regno);
int regno; }
int via_ac = -1;
fprintf (stream, /* Expand the function prologue. */
"\n\t; /* function prologue %s*/\n",
current_function_name ());
/* if we are outputting code for main, void
the switch FPU to right mode if TARGET_FPU */ pdp11_expand_prologue (void)
if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU) {
HOST_WIDE_INT fsize = get_frame_size ();
unsigned regno;
rtx x, via_ac = NULL;
/* If we are outputting code for main, the switch FPU to the
right mode if TARGET_FPU. */
if (MAIN_NAME_P (DECL_NAME (current_function_decl)) && TARGET_FPU)
{ {
fprintf(stream, emit_insn (gen_setd ());
"\t;/* switch cpu to double float, single integer */\n"); emit_insn (gen_seti ());
fprintf(stream, "\tsetd\n");
fprintf(stream, "\tseti\n\n");
} }
if (frame_pointer_needed) if (frame_pointer_needed)
{
fprintf(stream, "\tmov r5, -(sp)\n");
fprintf(stream, "\tmov sp, r5\n");
}
else
{ {
/* DON'T SAVE FP */ x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
x = gen_frame_mem (Pmode, x);
emit_move_insn (x, hard_frame_pointer_rtx);
emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
} }
/* make frame */ /* Make frame. */
if (fsize) if (fsize)
asm_fprintf (stream, "\tsub $%#wo, sp\n", fsize);
/* save CPU registers */
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))
fprintf (stream, "\tmov %s, -(sp)\n", reg_names[regno]);
/* fpu regs saving */
/* via_ac specifies the ac to use for saving ac4, ac5 */
via_ac = -1;
for (regno = AC0_REGNUM; regno <= AC5_REGNUM ; regno++)
{ {
/* ac0 - ac3 */ emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx,
if (LOAD_FPU_REG_P(regno) GEN_INT (-fsize)));
&& df_regs_ever_live_p (regno)
&& ! call_used_regs[regno]) /* Prevent frame references via the frame pointer from being
{ scheduled before the frame is allocated. */
fprintf (stream, "\tstd %s, -(sp)\n", reg_names[regno]); if (frame_pointer_needed)
via_ac = regno; emit_insn (gen_blockage ());
}
/* maybe make ac4, ac5 call used regs?? */
/* ac4 - ac5 */
if (NO_LOAD_FPU_REG_P(regno)
&& df_regs_ever_live_p (regno)
&& ! call_used_regs[regno])
{
gcc_assert (via_ac != -1);
fprintf (stream, "\tldd %s, %s\n",
reg_names[regno], reg_names[via_ac]);
fprintf (stream, "\tstd %s, -(sp)\n", reg_names[via_ac]);
}
} }
fprintf (stream, "\t;/* end of prologue */\n\n"); /* Save CPU registers. */
for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++)
if (pdp11_saved_regno (regno)
&& (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
{
x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
x = gen_frame_mem (Pmode, x);
emit_move_insn (x, gen_rtx_REG (Pmode, regno));
}
/* Save FPU registers. */
for (regno = AC0_REGNUM; regno <= AC3_REGNUM; regno++)
if (pdp11_saved_regno (regno))
{
x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
x = gen_frame_mem (DFmode, x);
via_ac = gen_rtx_REG (DFmode, regno);
emit_move_insn (x, via_ac);
}
/* ??? Maybe make ac4, ac5 call used regs?? */
for (regno = AC4_REGNUM; regno <= AC5_REGNUM; regno++)
if (pdp11_saved_regno (regno))
{
gcc_assert (via_ac != NULL);
emit_move_insn (via_ac, gen_rtx_REG (DFmode, regno));
x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
x = gen_frame_mem (DFmode, x);
emit_move_insn (x, via_ac);
}
} }
/* /* The function epilogue should not depend on the current stack pointer!
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only. This is mandatory because It should use the frame pointer only. This is mandatory because
of alloca; we also take advantage of it to omit stack adjustments of alloca; we also take advantage of it to omit stack adjustments
before returning. */ before returning. */
/* maybe we can make leaf functions faster by switching to the /* Maybe we can make leaf functions faster by switching to the
second register file - this way we don't have to save regs! second register file - this way we don't have to save regs!
leaf functions are ~ 50% of all functions (dynamically!) leaf functions are ~ 50% of all functions (dynamically!)
...@@ -328,109 +318,127 @@ pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size) ...@@ -328,109 +318,127 @@ pdp11_output_function_prologue (FILE *stream, HOST_WIDE_INT size)
maybe as option if you want to generate code for kernel mode? */ maybe as option if you want to generate code for kernel mode? */
static void void
pdp11_output_function_epilogue (FILE *stream, HOST_WIDE_INT size) pdp11_expand_epilogue (void)
{ {
HOST_WIDE_INT fsize = ((size) + 1) & ~1; HOST_WIDE_INT fsize = get_frame_size ();
int i, j, k; unsigned regno;
rtx x, reg, via_ac = NULL;
int via_ac; if (pdp11_saved_regno (AC4_REGNUM) || pdp11_saved_regno (AC5_REGNUM))
{
fprintf (stream, "\n\t; /*function epilogue */\n"); /* Find a temporary with which to restore AC4/5. */
for (regno = AC0_REGNUM; regno <= AC3_REGNUM; regno++)
if (pdp11_saved_regno (regno))
{
via_ac = gen_rtx_REG (DFmode, regno);
break;
}
}
if (frame_pointer_needed) /* If possible, restore registers via pops. */
{ if (!frame_pointer_needed || current_function_sp_is_unchanging)
/* hope this is safe - m68k does it also .... */ {
df_set_regs_ever_live (FRAME_POINTER_REGNUM, false); /* Restore registers via pops. */
for (i = PC_REGNUM, j = 0 ; i >= 0 ; i--) for (regno = AC5_REGNUM; regno >= AC0_REGNUM; regno--)
if (df_regs_ever_live_p (i) && ! call_used_regs[i]) if (pdp11_saved_regno (regno))
j++; {
x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
/* remember # of pushed bytes for CPU regs */ x = gen_frame_mem (DFmode, x);
k = 2*j; reg = gen_rtx_REG (DFmode, regno);
/* change fp -> r5 due to the compile error on libgcc2.c */ if (LOAD_FPU_REG_P (regno))
for (i = PC_REGNUM ; i >= R0_REGNUM ; i--) emit_move_insn (reg, x);
if (df_regs_ever_live_p (i) && ! call_used_regs[i]) else
fprintf(stream, "\tmov %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", {
(-fsize-2*j--)&0xffff, reg_names[i]); emit_move_insn (via_ac, x);
emit_move_insn (reg, via_ac);
/* get ACs */ }
via_ac = AC5_REGNUM; }
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--) for (regno = PC_REGNUM; regno >= R0_REGNUM + 2; regno--)
if (df_regs_ever_live_p (i) && ! call_used_regs[i]) if (pdp11_saved_regno (regno)
{ && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
via_ac = i; {
k += 8; x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
} x = gen_frame_mem (Pmode, x);
emit_move_insn (gen_rtx_REG (Pmode, regno), x);
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--) }
{ }
if (LOAD_FPU_REG_P(i) else
&& df_regs_ever_live_p (i) {
&& ! call_used_regs[i]) /* Restore registers via moves. */
{ /* ??? If more than a few registers need to be restored, it's smaller
fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", to generate a pointer through which we can emit pops. Consider
(-fsize-k)&0xffff, reg_names[i]); that moves cost 2*NREG words and pops cost NREG+3 words. This
k -= 8; means that the crossover is NREG=3.
}
Possible registers to use are:
if (NO_LOAD_FPU_REG_P(i) (1) The first call-saved general register. This register will
&& df_regs_ever_live_p (i) be restored with the last pop.
&& ! call_used_regs[i]) (2) R1, if it's not used as a return register.
{ (3) FP itself. This option may result in +4 words, since we
gcc_assert (LOAD_FPU_REG_P(via_ac)); may need two add imm,rn instructions instead of just one.
This also has the downside that we're not representing
fprintf(stream, "\tldd %#" HOST_WIDE_INT_PRINT "o(r5), %s\n", the unwind info in any way, so during the epilogue the
(-fsize-k)&0xffff, reg_names[via_ac]); debugger may get lost. */
fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
k -= 8; HOST_WIDE_INT ofs = -pdp11_sp_frame_offset ();
}
} for (regno = AC5_REGNUM; regno >= AC0_REGNUM; regno--)
if (pdp11_saved_regno (regno))
fprintf(stream, "\tmov r5, sp\n"); {
fprintf (stream, "\tmov (sp)+, r5\n"); x = plus_constant (hard_frame_pointer_rtx, ofs);
} x = gen_frame_mem (DFmode, x);
else reg = gen_rtx_REG (DFmode, regno);
{
via_ac = AC5_REGNUM; if (LOAD_FPU_REG_P (regno))
emit_move_insn (reg, x);
/* get ACs */ else
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--) {
if (df_regs_ever_live_p (i) && ! call_used_regs[i]) emit_move_insn (via_ac, x);
via_ac = i; emit_move_insn (reg, via_ac);
}
for (i = AC5_REGNUM; i >= AC0_REGNUM; i--) ofs += 8;
}
for (regno = PC_REGNUM; regno >= R0_REGNUM + 2; regno--)
if (pdp11_saved_regno (regno)
&& (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
{
x = plus_constant (hard_frame_pointer_rtx, ofs);
x = gen_frame_mem (Pmode, x);
emit_move_insn (gen_rtx_REG (Pmode, regno), x);
ofs += 2;
}
}
/* Deallocate the stack frame. */
if (fsize)
{
/* Prevent frame references via any pointer from being
scheduled after the frame is deallocated. */
emit_insn (gen_blockage ());
if (frame_pointer_needed)
{ {
if (LOAD_FPU_REG_P(i) /* We can deallocate the frame with a single move. */
&& df_regs_ever_live_p (i) emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
&& ! call_used_regs[i])
fprintf(stream, "\tldd (sp)+, %s\n", reg_names[i]);
if (NO_LOAD_FPU_REG_P(i)
&& df_regs_ever_live_p (i)
&& ! call_used_regs[i])
{
gcc_assert (LOAD_FPU_REG_P(via_ac));
fprintf(stream, "\tldd (sp)+, %s\n", reg_names[via_ac]);
fprintf(stream, "\tstd %s, %s\n", reg_names[via_ac], reg_names[i]);
}
} }
else
emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (fsize)));
}
for (i = PC_REGNUM; i >= 0; i--) if (frame_pointer_needed)
if (df_regs_ever_live_p (i) && !call_used_regs[i]) {
fprintf(stream, "\tmov (sp)+, %s\n", reg_names[i]); x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
x = gen_frame_mem (Pmode, x);
if (fsize) emit_move_insn (hard_frame_pointer_rtx, x);
fprintf((stream), "\tadd $%#" HOST_WIDE_INT_PRINT "o, sp\n", }
(fsize)&0xffff);
} emit_jump_insn (gen_return ());
fprintf (stream, "\trts pc\n");
fprintf (stream, "\t;/* end of epilogue*/\n\n\n");
} }
/* Return the best assembler insn template /* Return the best assembler insn template
...@@ -1570,16 +1578,16 @@ pdp11_regno_reg_class (int regno) ...@@ -1570,16 +1578,16 @@ pdp11_regno_reg_class (int regno)
} }
static int int
pdp11_sp_frame_offset (void) pdp11_sp_frame_offset (void)
{ {
int offset = 0, regno; int offset = 0, regno;
offset = get_frame_size(); offset = get_frame_size();
for (regno = 0; regno <= PC_REGNUM; regno++) for (regno = 0; regno <= PC_REGNUM; regno++)
if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) if (pdp11_saved_regno (regno))
offset += 2; offset += 2;
for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++) for (regno = AC0_REGNUM; regno <= AC5_REGNUM; regno++)
if (df_regs_ever_live_p (regno) && ! call_used_regs[regno]) if (pdp11_saved_regno (regno))
offset += 8; offset += 8;
return offset; return offset;
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
(include "predicates.md") (include "predicates.md")
(include "constraints.md") (include "constraints.md")
(define_c_enum "unspecv"
[
UNSPECV_BLOCKAGE
UNSPECV_SETD
UNSPECV_SETI
])
(define_constants (define_constants
[ [
;; Register numbers ;; Register numbers
...@@ -104,6 +111,50 @@ ...@@ -104,6 +111,50 @@
;; define function units ;; define function units
;; Prologue and epilogue support.
(define_expand "prologue"
[(const_int 0)]
""
{
pdp11_expand_prologue ();
DONE;
})
(define_expand "epilogue"
[(const_int 0)]
""
{
pdp11_expand_epilogue ();
DONE;
})
(define_expand "return"
[(return)]
"reload_completed && !frame_pointer_needed && pdp11_sp_frame_offset () == 0"
"")
(define_insn "*rts"
[(return)]
""
"rts pc")
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
""
""
[(set_attr "length" "0")])
(define_insn "setd"
[(unspec_volatile [(const_int 0)] UNSPECV_SETD)]
""
"setd")
(define_insn "seti"
[(unspec_volatile [(const_int 0)] UNSPECV_SETI)]
""
"seti")
;; arithmetic - values here immediately when next insn issued ;; arithmetic - values here immediately when next insn issued
;; or does it mean the number of cycles after this insn was issued? ;; or does it mean the number of cycles after this insn was issued?
;; how do I say that fpu insns use cpu also? (pre-interaction phase) ;; how do I say that fpu insns use cpu also? (pre-interaction phase)
......
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