Commit 040c5757 by Richard Henderson Committed by Richard Henderson

mn10300: tidy pic address loading

There's little reason to greatly complicate things by splitting
the pic_load patterns and using complex rtl to make it work out.
Instead, use the %= marker to generate unique numbers and emit
the entire load_pic sequence at once.

At the same time, collect all references to outgoing_args_size
into mn10300_frame_size, and all computations of register save
area size into mn10300_initial_offset.

From-SVN: r169012
parent bad41521
2011-01-19 Richard Henderson <rth@redhat.com>
* config/mn10300/mn10300.c (mn10300_unspec_int_label_counter): Remove.
(mn10300_asm_output_addr_const_extra): Don't handle UNSPEC_INT_LABEL.
(mn10300_legitimate_constant_p): Likewise.
(mn10300_can_use_return_insn): Use mn10300_initial_offset.
(mn10300_frame_size): New.
(mn10300_expand_prologue): Use it.
(mn10300_expand_epilogue): Likewise.
(mn10300_initial_offset): Likewise.
* config/mn10300/mn10300-protos.h: Update.
* config/mn10300/mn10300.h (mn10300_unspec_int_label_counter): Remove.
* config/mn10300/mn10300.md (UNSPEC_INT_LABEL): Remove.
(prologue, epilogue, return_internal): Tidy output code.
(mn10300_store_multiple_operation, return): Likewise.
(int_label, pop_pic_reg, GOTaddr2picreg): Remove.
(am33_loadPC, mn10300_loadPC, call_next_insn): Remove.
(add_GOT_to_pic_reg, add_GOT_to_any_reg): Remove.
(load_pic, am33_load_pic): New.
(mn10300_load_pic0, mn10300_load_pic1): New.
* config/mn10300/mn10300-modes.def (CCZN, CCZNC): New modes.
* config/mn10300/mn10300.c (CC_FLAG_Z): New.
(CC_FLAG_N, CC_FLAG_C, CC_FLAG_V): New.
......
......@@ -49,6 +49,7 @@ extern int mn10300_can_use_return_insn (void);
extern void mn10300_expand_prologue (void);
extern void mn10300_expand_epilogue (void);
extern int mn10300_initial_offset (int, int);
extern int mn10300_frame_size (void);
#undef Mmode
#undef Cstar
......
......@@ -44,10 +44,6 @@
#include "target-def.h"
#include "df.h"
/* This is used by GOTaddr2picreg to uniquely identify
UNSPEC_INT_LABELs. */
int mn10300_unspec_int_label_counter;
/* This is used in the am33_2.0-linux-gnu port, in which global symbol
names are not prefixed by underscores, to tell whether to prefix a
label with a plus sign or not, so that the assembler can tell
......@@ -544,10 +540,6 @@ mn10300_asm_output_addr_const_extra (FILE *file, rtx x)
{
switch (XINT (x, 1))
{
case UNSPEC_INT_LABEL:
asm_fprintf (file, ".%LLIL" HOST_WIDE_INT_PRINT_DEC,
INTVAL (XVECEXP (x, 0, 0)));
break;
case UNSPEC_PIC:
/* GLOBAL_OFFSET_TABLE or local symbols, no suffix. */
output_addr_const (file, XVECEXP (x, 0, 0));
......@@ -634,24 +626,7 @@ mn10300_print_reg_list (FILE *file, int mask)
int
mn10300_can_use_return_insn (void)
{
/* size includes the fixed stack space needed for function calls. */
int size = get_frame_size () + crtl->outgoing_args_size;
/* And space for the return pointer. */
size += crtl->outgoing_args_size ? 4 : 0;
return (reload_completed
&& size == 0
&& !df_regs_ever_live_p (2)
&& !df_regs_ever_live_p (3)
&& !df_regs_ever_live_p (6)
&& !df_regs_ever_live_p (7)
&& !df_regs_ever_live_p (14)
&& !df_regs_ever_live_p (15)
&& !df_regs_ever_live_p (16)
&& !df_regs_ever_live_p (17)
&& fp_regs_to_save () == 0
&& !frame_pointer_needed);
return !mn10300_initial_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM);
}
/* Returns the set of live, callee-saved registers as a bitmask. The
......@@ -760,11 +735,7 @@ mn10300_gen_multiple_store (unsigned int mask)
void
mn10300_expand_prologue (void)
{
HOST_WIDE_INT size;
/* SIZE includes the fixed stack space needed for function calls. */
size = get_frame_size () + crtl->outgoing_args_size;
size += (crtl->outgoing_args_size ? 4 : 0);
HOST_WIDE_INT size = mn10300_frame_size ();
/* If we use any of the callee-saved registers, save them now. */
mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
......@@ -1017,17 +988,13 @@ mn10300_expand_prologue (void)
GEN_INT (-size))));
if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
emit_insn (gen_GOTaddr2picreg ());
emit_insn (gen_load_pic ());
}
void
mn10300_expand_epilogue (void)
{
HOST_WIDE_INT size;
/* SIZE includes the fixed stack space needed for function calls. */
size = get_frame_size () + crtl->outgoing_args_size;
size += (crtl->outgoing_args_size ? 4 : 0);
HOST_WIDE_INT size = mn10300_frame_size ();
if (TARGET_AM33_2 && fp_regs_to_save ())
{
......@@ -1442,54 +1409,37 @@ mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
}
int
mn10300_frame_size (void)
{
/* size includes the fixed stack space needed for function calls. */
int size = get_frame_size () + crtl->outgoing_args_size;
/* And space for the return pointer. */
size += crtl->outgoing_args_size ? 4 : 0;
return size;
}
int
mn10300_initial_offset (int from, int to)
{
int diff = 0;
gcc_assert (from == ARG_POINTER_REGNUM || from == FRAME_POINTER_REGNUM);
gcc_assert (to == FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM);
if (to == STACK_POINTER_REGNUM)
diff = mn10300_frame_size ();
/* The difference between the argument pointer and the frame pointer
is the size of the callee register save area. */
if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
if (from == ARG_POINTER_REGNUM)
{
if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
|| df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
|| df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
|| df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
|| fp_regs_to_save ()
|| frame_pointer_needed)
return REG_SAVE_BYTES
+ 4 * fp_regs_to_save ();
else
return 0;
diff += REG_SAVE_BYTES;
diff += 4 * fp_regs_to_save ();
}
/* The difference between the argument pointer and the stack pointer is
the sum of the size of this function's frame, the callee register save
area, and the fixed stack space needed for function calls (if any). */
if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
{
if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
|| df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
|| df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
|| df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
|| fp_regs_to_save ()
|| frame_pointer_needed)
return (get_frame_size () + REG_SAVE_BYTES
+ 4 * fp_regs_to_save ()
+ (crtl->outgoing_args_size
? crtl->outgoing_args_size + 4 : 0));
else
return (get_frame_size ()
+ (crtl->outgoing_args_size
? crtl->outgoing_args_size + 4 : 0));
}
/* The difference between the frame pointer and stack pointer is the sum
of the size of this function's frame and the fixed stack space needed
for function calls (if any). */
if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return (get_frame_size ()
+ (crtl->outgoing_args_size
? crtl->outgoing_args_size + 4 : 0));
gcc_unreachable ();
return diff;
}
/* Worker function for TARGET_RETURN_IN_MEMORY. */
......@@ -2087,7 +2037,6 @@ mn10300_legitimate_constant_p (rtx x)
{
switch (XINT (x, 1))
{
case UNSPEC_INT_LABEL:
case UNSPEC_PIC:
case UNSPEC_GOT:
case UNSPEC_GOTOFF:
......
......@@ -53,8 +53,6 @@
} \
while (0)
extern GTY(()) int mn10300_unspec_int_label_counter;
enum processor_type
{
PROCESSOR_MN10300,
......
......@@ -31,7 +31,6 @@
(MDR_REG 50)
(CC_REG 51)
(UNSPEC_INT_LABEL 0)
(UNSPEC_PIC 1)
(UNSPEC_GOT 2)
(UNSPEC_GOTOFF 3)
......@@ -294,7 +293,6 @@
(match_operand:SI 1 "impossible_plus_operand" ""))
(clobber (match_operand:SI 2 "register_operand" "=&A"))]
""
"
{
rtx dest, scratch, other;
......@@ -336,16 +334,7 @@
emit_move_insn (dest, scratch);
}
DONE;
}")
(define_insn "pop_pic_reg"
[(set (reg:SI PIC_REG)
(mem:SI (post_inc:SI (reg:SI SP_REG))))]
"reload_completed"
"movm (sp),[a2]"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 44) (const_int 33)))]
)
})
(define_expand "movsi"
[(set (match_operand:SI 0 "nonimmediate_operand")
......@@ -1141,13 +1130,10 @@
(define_expand "builtin_setjmp_receiver"
[(match_operand 0 "" "")]
"flag_pic"
"
{
if (flag_pic)
emit_insn (gen_GOTaddr2picreg ());
emit_insn (gen_load_pic ());
DONE;
}")
})
(define_expand "casesi"
[(match_operand:SI 0 "register_operand")
......@@ -1612,16 +1598,14 @@
(define_expand "prologue"
[(const_int 0)]
""
"mn10300_expand_prologue (); DONE;")
{ mn10300_expand_prologue (); DONE; }
)
(define_expand "epilogue"
[(return)]
""
"
{
mn10300_expand_epilogue ();
DONE;
}")
{ mn10300_expand_epilogue (); DONE; }
)
(define_insn "return_internal"
[(const_int 2)
......@@ -1638,13 +1622,12 @@
(match_operand:SI 0 "const_int_operand" "i")
(return)]
""
"*
{
fputs (\"\\tret \", asm_out_file);
mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
return \"\";
}"
{
fputs ("\tret ", asm_out_file);
mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
return "";
}
;; Assumes that there will be no more than 8 regs to pop
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 1414) (const_int 1313)))]
......@@ -1655,15 +1638,14 @@
[(match_parallel 0 "mn10300_store_multiple_operation"
[(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand 1 "" "")))])]
""
"*
{
fputs (\"\\tmovm \", asm_out_file);
mn10300_print_reg_list (asm_out_file,
mn10300_store_multiple_operation (operands[0],
VOIDmode));
fprintf (asm_out_file, \",(sp)\\n\");
return \"\";
}"
{
fputs ("\tmovm ", asm_out_file);
mn10300_print_reg_list (asm_out_file,
mn10300_store_multiple_operation (operands[0],
VOIDmode));
fprintf (asm_out_file, ",(sp)\n");
return "";
}
;; Assume that no more than 8 registers will be pushed.
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 99) (const_int 88)))]
......@@ -1672,116 +1654,67 @@
(define_insn "return"
[(return)]
"mn10300_can_use_return_insn ()"
"*
{
rtx next = next_active_insn (insn);
if (next
&& JUMP_P (next)
&& GET_CODE (PATTERN (next)) == RETURN)
return \"\";
else
return \"rets\";
}"
"rets"
[(set_attr "timings" "66")]
)
(define_expand "int_label"
[(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
"" "")
(define_expand "GOTaddr2picreg"
[(match_dup 0)]
"" "
(define_expand "load_pic"
[(const_int 0)]
"flag_pic"
{
/* It would be nice to be able to have int_label keep track of the
counter and all, but if we add C code to it, we'll get an insn
back, and we just want the pattern. */
operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
if (TARGET_AM33)
emit_insn (gen_am33_loadPC (operands[0]));
emit_insn (gen_am33_load_pic (pic_offset_table_rtx));
else if (mn10300_frame_size () == 0)
emit_insn (gen_mn10300_load_pic0 (pic_offset_table_rtx));
else
emit_insn (gen_mn10300_loadPC (operands[0]));
emit_insn (gen_add_GOT_to_pic_reg (copy_rtx (operands[0])));
emit_insn (gen_mn10300_load_pic1 (pic_offset_table_rtx));
DONE;
}
")
})
(define_insn "am33_loadPC"
[(parallel
[(set (reg:SI PIC_REG) (pc))
(use (match_operand 0 "" ""))])]
(define_insn "am33_load_pic"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI [(const_int 0)] UNSPEC_GOT))
(clobber (reg:CC CC_REG))]
"TARGET_AM33"
"%0:\;mov pc,a2"
{
operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
return ".LPIC%=:\;mov pc,%0\;add %1-(.LPIC%=-.),%0";
}
[(set_attr "timings" "33")]
)
(define_insn_and_split "mn10300_loadPC"
[(parallel
[(set (reg:SI PIC_REG) (pc))
(use (match_operand 0 "" ""))])]
"! TARGET_AM33"
"#"
"&& reload_completed"
[(match_operand 0 "" "")]
{
rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
int need_stack_space = (get_frame_size () == 0
&& crtl->outgoing_args_size == 0);
if (need_stack_space)
emit_insn (gen_addsi3 (sp_reg, sp_reg, GEN_INT (-4)));
emit_insn (gen_call_next_insn (operands[0]));
if (need_stack_space)
emit_insn (gen_pop_pic_reg ());
else
emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
DONE;
}
;; Load pic register with push/pop of stack.
(define_insn "mn10300_load_pic0"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI [(const_int 0)] UNSPEC_GOT))
(clobber (reg:SI MDR_REG))
(clobber (reg:CC CC_REG))]
""
{
operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
return ("add -4,sp\;"
"calls .LPIC%=\n"
".LPIC%=:\;"
"movm (sp),[%0]\;"
"add %1-(.LPIC%=-.),%0");
}
[(set_attr "timings" "88")]
)
(define_insn "call_next_insn"
[(parallel
[(set (mem:SI (reg:SI SP_REG)) (pc))
(use (match_operand 0 "" ""))])]
"reload_completed"
"calls %0\;%0:"
[(set_attr "timings" "44")]
)
(define_expand "add_GOT_to_pic_reg"
[(parallel [(set (reg:SI PIC_REG)
(plus:SI
(reg:SI PIC_REG)
(const:SI
(unspec:SI [(minus:SI
(match_dup 1)
(const (minus:SI
(const (match_operand:SI 0 "" ""))
(pc))))
] UNSPEC_PIC))))
(clobber (reg:CC CC_REG))
])
]
""
"operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
)
(define_expand "add_GOT_to_any_reg"
[(parallel [(set (match_operand:SI 0 "" "")
(plus:SI
(match_operand:SI 1 "" "")
(const
(unspec [(minus:SI
(match_dup 3)
(const (minus:SI
(const (match_operand:SI 2 "" ""))
(pc))))
] UNSPEC_PIC))))
(clobber (reg:CC CC_REG))
])
]
;; Load pic register re-using existing stack space.
(define_insn "mn10300_load_pic1"
[(set (match_operand:SI 0 "register_operand" "=a")
(unspec:SI [(const_int 0)] UNSPEC_GOT))
(clobber (mem:SI (reg:SI SP_REG)))
(clobber (reg:SI MDR_REG))
(clobber (reg:CC CC_REG))]
""
"operands[3] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
{
operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
return ("calls .LPIC%=\n"
".LPIC%=:\;"
"mov (sp),%0\;"
"add %1-(.LPIC%=-.),%0");
}
[(set_attr "timings" "66")]
)
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