mn10300.c (expand_prologue): Rework so that eliminating the frame pointer produces faster/smaller code.

* mn10300/mn10300.c (expand_prologue): Rework so that eliminating
        the frame pointer produces faster/smaller code.
        (expand_epilogue): Likewise.
        (initial_offset): New function for argument pointer and frame pointer
        elimination.
        * mn10300/mn10300.h (FIRST_PSEUDO_REGISTER): Bump to 10.
        (FIXED_REGISTERS): Add argument pointer register, it's a fake fixed
        register.
        (CALL_USED_REGISTERS, REG_ALLOC_ORDER): Corresponding changes.
        (REGNO_REG_CLASS, REG_CLASS_CONTENTS): Likewise.
        (REG_OK_FOR_BASE_P, REGISTER_NAMES): Likewise.
        (reg_class, REG_CLASS_NAMES): Delete unwanted DATA_OR_SP_REGS class.
        (PREFERRED_OUTPUT_RELOAD_CLASS): Define.
        (FIRST_PARM_OFFSET): No longer include register save area in
        computation.
        (STACK_POINTER_REGNUM): Is now register 9.
        (ARG_POINTER_REGNUM): Is now register 8.
        (FRAME_POINTER_REQUIRED): Refine.
        (ELIMINABLE_REGS, INITIAL_ELIMINATION_OFFSET): Define.
        (CAN_DEUG_WITHOUT_FP): Define.
        * mn10300/mn10300.md (return_internal): Break into two patterns.

        * mn10300/mn10300.h (CONST_OK_FOR_LETTER_P): Handle 'M' too.
        (REGISTER_MOVE_COST): Fix errors and refine.

        * mn10300/mn10300.c (notice_update_cc): SET_ZN_C0 insns leave the
        overflow bit in an unuseable state.  Rename CC_SET to CC_TST.
        * mn10300/mn10300.md (cc attributes): "set" is gone, replaced by
        "tst".  Update attributes on various insns.

        * mn10300/mn10300.md: Improve sign and zero extension instructions.
        (ashlsi3): Improve.  Handle address registers too.
        (add peephole): Combine two consecutive adjustments of a register
        into a single adjustment.

From-SVN: r13700
This commit is contained in:
Jeff Law 1997-03-11 17:25:59 -07:00
parent e9b1360b49
commit 777fbf098d
3 changed files with 186 additions and 88 deletions

View File

@ -213,14 +213,18 @@ expand_prologue ()
{
unsigned int size = get_frame_size ();
/* For simplicity, we just movm all the callee saved registers to
the stack with one instruction, then set up the frame pointer
(if needed), and finally allocate the new stack. */
emit_insn (gen_store_movm ());
/* And now store all the registers onto the stack with a
single two byte instruction. */
if (regs_ever_live[2] || regs_ever_live[3]
|| regs_ever_live[6] || regs_ever_live[7]
|| frame_pointer_needed)
emit_insn (gen_store_movm ());
/* Now put the frame pointer into the frame pointer register. */
if (frame_pointer_needed)
emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
/* Allocate stack for this frame. */
if (size)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
@ -246,8 +250,23 @@ expand_epilogue ()
size = 0;
}
/* Deallocate remaining stack, restore registers and return. And return. */
emit_jump_insn (gen_return_internal (GEN_INT (size)));
/* For simplicity, we just movm all the callee saved registers to
the stack with one instruction.
?!? Only save registers which are actually used. Reduces
stack requireents and is faster. */
if (regs_ever_live[2] || regs_ever_live[3]
|| regs_ever_live[6] || regs_ever_live[7]
|| frame_pointer_needed)
emit_jump_insn (gen_return_internal_regs (GEN_INT (size)));
else
{
if (size)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (size)));
emit_jump_insn (gen_return_internal ());
}
}
/* Update the condition code from the insn. */
@ -275,14 +294,13 @@ notice_update_cc (body, insn)
V is always set to 0. C may or may not be set to 0 but that's ok
because alter_cond will change tests to use EQ/NE. */
CC_STATUS_INIT;
cc_status.flags |= CC_NO_OVERFLOW;
cc_status.flags |= CC_NO_OVERFLOW | CC_OVERFLOW_UNUSABLE;
cc_status.value1 = recog_operand[0];
break;
case CC_SET:
case CC_TST:
/* The insn sets all the condition codes, except v is bogus. */
CC_STATUS_INIT;
cc_status.flags |= CC_OVERFLOW_UNUSABLE;
cc_status.value1 = recog_operand[0];
break;
@ -334,27 +352,45 @@ secondary_reload_class (class, mode, in)
/* We can't directly load sp + const_int into a data register;
we must use an address register as an intermediate. */
if (class == DATA_REGS
if (class != SP_REGS
&& class != ADDRESS_REGS
&& class != SP_OR_ADDRESS_REGS
&& (in == stack_pointer_rtx
|| (GET_CODE (in) == PLUS
&& XEXP (in, 0) == stack_pointer_rtx)))
return ADDRESS_REGS;
/* Get the true register. */
if (GET_CODE (in) == REG)
{
regno = REGNO (in);
if (regno >= FIRST_PSEUDO_REGISTER)
regno = true_regnum (in);
}
/* We can't copy directly from a data register into the stack
pointer. */
if (class == SP_REGS
&& GET_CODE (in) == REG
&& regno < 4)
&& (XEXP (in, 0) == stack_pointer_rtx
|| XEXP (in, 1) == stack_pointer_rtx))))
return ADDRESS_REGS;
/* Otherwise assume no secondary reloads are needed. */
return NO_REGS;
}
int
initial_offset (from, to)
int from, to;
{
if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
{
if (regs_ever_live[2] || regs_ever_live[3]
|| regs_ever_live[6] || regs_ever_live[7]
|| frame_pointer_needed)
return 20;
else
return 4;
}
if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
{
if (regs_ever_live[2] || regs_ever_live[3]
|| regs_ever_live[6] || regs_ever_live[7]
|| frame_pointer_needed)
return get_frame_size () + 20;
else
return get_frame_size () + 4;
}
if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return get_frame_size ();
abort ();
}

View File

@ -131,13 +131,13 @@ extern int target_flags;
All registers that the compiler knows about must be given numbers,
even those that are not normally considered general registers. */
#define FIRST_PSEUDO_REGISTER 9
#define FIRST_PSEUDO_REGISTER 10
/* 1 for registers that have pervasive standard uses
and are not available for the register allocator. */
#define FIXED_REGISTERS \
{ 0, 0, 0, 0, 0, 0, 0, 0, 1}
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}
/* 1 for registers not available across function calls.
These must include the FIXED_REGISTERS and also any
@ -148,10 +148,10 @@ extern int target_flags;
like. */
#define CALL_USED_REGISTERS \
{ 1, 1, 0, 0, 1, 1, 0, 0, 1}
{ 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}
#define REG_ALLOC_ORDER \
{ 0, 1, 4, 5, 2, 3, 6, 7, 8}
{ 0, 1, 4, 5, 2, 3, 6, 7, 8, 9}
/* Return number of consecutive hard regs needed starting at reg REGNO
to hold something of mode MODE.
@ -202,7 +202,7 @@ extern int target_flags;
class that represents their union. */
enum reg_class {
NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, DATA_OR_ADDRESS_REGS, DATA_OR_SP_REGS, SP_OR_ADDRESS_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, DATA_OR_ADDRESS_REGS, SP_OR_ADDRESS_REGS, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
};
#define N_REG_CLASSES (int) LIM_REG_CLASSES
@ -211,8 +211,8 @@ enum reg_class {
#define REG_CLASS_NAMES \
{ "NO_REGS", "DATA_REGS", "ADDRESS_REGS", \
"SP_REGS", "DATA_OR_ADDRESS_REGS", "DATA_OR_SP_REGS", \
"SP_OR_ADDRESS_REGS", "GENERAL_REGS", "ALL_REGS", "LIM_REGS" }
"SP_REGS", "DATA_OR_ADDRESS_REGS", "SP_OR_ADDRESS_REGS", \
"GENERAL_REGS", "ALL_REGS", "LIM_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
@ -221,13 +221,12 @@ enum reg_class {
#define REG_CLASS_CONTENTS \
{ 0, /* No regs */ \
0x00f, /* DATA_REGS */ \
0x0f0, /* ADDRESS_REGS */ \
0x100, /* SP_REGS */ \
0x0ff, /* DATA_OR_ADDRESS_REGS */\
0x00f, /* DATA_OR_SP_REGS */ \
0x0f0, /* SP_OR_ADDRESS_REGS */\
0x0ff, /* GENERAL_REGS */ \
0x0ff, /* ALL_REGS */ \
0x1f0, /* ADDRESS_REGS */ \
0x200, /* SP_REGS */ \
0x1ff, /* DATA_OR_ADDRESS_REGS */\
0x1f0, /* SP_OR_ADDRESS_REGS */\
0x1ff, /* GENERAL_REGS */ \
0x3ff, /* ALL_REGS */ \
}
/* The same information, inverted:
@ -237,8 +236,8 @@ enum reg_class {
#define REGNO_REG_CLASS(REGNO) \
((REGNO) < 4 ? DATA_REGS : \
(REGNO) < 8 ? ADDRESS_REGS : \
(REGNO) == 8 ? SP_REGS: 0)
(REGNO) < 9 ? ADDRESS_REGS : \
(REGNO) == 9 ? SP_REGS: 0)
/* The class value for index registers, and the one for base regs. */
@ -277,6 +276,9 @@ enum reg_class {
#define PREFERRED_RELOAD_CLASS(X,CLASS) \
(X == stack_pointer_rtx && CLASS != SP_REGS ? ADDRESS_REGS : CLASS)
#define PREFERRED_OUTPUT_RELOAD_CLASS(X,CLASS) \
(X == stack_pointer_rtx && CLASS != SP_REGS ? ADDRESS_REGS : CLASS)
#define LIMIT_RELOAD_CLASS(MODE, CLASS) \
((MODE == QImode || MODE == HImode) ? DATA_REGS : CLASS)
@ -302,12 +304,14 @@ enum reg_class {
#define CONST_OK_FOR_J(VALUE) ((VALUE) == 1)
#define CONST_OK_FOR_K(VALUE) ((VALUE) == 2)
#define CONST_OK_FOR_L(VALUE) ((VALUE) == 4)
#define CONST_OK_FOR_M(VALUE) ((VALUE) == 3)
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'I' ? CONST_OK_FOR_I (VALUE) : \
(C) == 'J' ? CONST_OK_FOR_J (VALUE) : \
(C) == 'K' ? CONST_OK_FOR_K (VALUE) : \
(C) == 'L' ? CONST_OK_FOR_L (VALUE) : 0)
(C) == 'L' ? CONST_OK_FOR_L (VALUE) : \
(C) == 'M' ? CONST_OK_FOR_M (VALUE) : 0)
/* Similar, but for floating constants, and defining letters G and H.
@ -343,19 +347,21 @@ enum reg_class {
/* Is equal to the size of the saved fp + pc, even if an fp isn't
saved since the value is used before we know. */
#define FIRST_PARM_OFFSET(FNDECL) (-4 + 20)
#define FIRST_PARM_OFFSET(FNDECL) -4
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM 8
#define STACK_POINTER_REGNUM 9
/* Base register for access to local variables of the function. */
#define FRAME_POINTER_REGNUM 7
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 7
/* Base register for access to arguments of the function. This
is a fake register and will be eliminated into either the frame
pointer or stack pointer. */
#define ARG_POINTER_REGNUM 8
/* Register in which static-chain is passed to a function. */
#define STATIC_CHAIN_REGNUM 5
@ -363,18 +369,40 @@ enum reg_class {
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c.
This is computed in `reload', in reload1.c.
Currently we always need a frame pointer. In the future we'd like
to be able to eliminate it. */
#define FRAME_POINTER_REQUIRED 1
We allow frame pointers to be eliminated when not having one will
not interfere with debugging.
/* Store in the variable DEPTH the initial difference between the
frame pointer reg contents and the stack pointer reg contents,
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. */
* If this is a leaf function, then we can keep the stack pointer
constant throughout the function, and therefore gdb can easily
find the base of the current frame.
#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) (DEPTH) = 20
* If this function never allocates stack space for outgoing
args (ie calls functions with either no args, or args only
in registers), then the stack pointer will be constant and
gdb can easily find the base of the current frame.
We'd really like to define ACCUMULATE_OUTGOING_ARGS and eliminate
all frame pointer, but currently we can't.
We probably also want a -m option to eliminate frame pointer, even
if the resulting executable can not be debugged. */
#define ELIMINABLE_REGS \
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
#define CAN_ELIMINATE(FROM, TO) 1
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
OFFSET = initial_offset (FROM, TO)
#define FRAME_POINTER_REQUIRED \
!(leaf_function_p () || current_function_outgoing_args_size == 0)
#define CAN_DEBUG_WITHOUT_FP
/* A guess for the MN10300. */
#define PROMOTE_PROTOTYPES 1
@ -565,7 +593,7 @@ enum reg_class {
/* Nonzero if X is a hard reg that can be used as a base reg
or if it is a pseudo reg. */
#define REG_OK_FOR_BASE_P(X) \
((REGNO (X) >= 4 && REGNO(X) <= 8) || REGNO (X) >= FIRST_PSEUDO_REGISTER)
((REGNO (X) >= 4 && REGNO(X) <= 9) || REGNO (X) >= FIRST_PSEUDO_REGISTER)
#else
/* Nonzero if X is a hard reg that can be used as an index. */
#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
@ -609,7 +637,7 @@ enum reg_class {
{ \
if (GET_CODE (index) == CONST_INT) \
goto ADDR; \
if (GET_CODE (index) == REG \
if (REG_P (index) \
&& REG_OK_FOR_INDEX_P (index)) \
goto ADDR; \
} \
@ -666,7 +694,7 @@ enum reg_class {
default: { int _zxy= const_costs(RTX, CODE); \
if(_zxy) return _zxy; break;}
#define REGISTER_MOVE_COST(CLASS1, CLASS2) 3
#define REGISTER_MOVE_COST(CLASS1, CLASS2) (CLASS1 != CLASS2 ? 4 : 0)
/* A crude cut at RTX_COSTS for the MN10300. */
@ -808,7 +836,7 @@ do { char dstr[30]; \
This sequence is indexed by compiler's hard-register-number (see above). */
#define REGISTER_NAMES \
{ "d0", "d1", "d2", "d3", "a0", "a1", "a2", "a3", "sp" }
{ "d0", "d1", "d2", "d3", "a0", "a1", "a2", "a3", "ap", "sp" }
/* Print an instruction operand X on file FILE.
look in mn10300.c for details */
@ -913,3 +941,4 @@ extern void expand_epilogue ();
extern void notice_update_cc ();
extern int call_address_operand ();
extern enum reg_class secondary_reload_class ();
extern int initial_offset ();

View File

@ -36,7 +36,7 @@
;; be known (if it isn't that's ok, we don't need it anyway).
;; compare - compare instruction
;; clobber - value of cc is unknown
(define_attr "cc" "none,none_0hit,set,set_zn_c0,compare,clobber"
(define_attr "cc" "none,none_0hit,tst,set_zn_c0,compare,clobber"
(const_string "clobber"))
;; ----------------------------------------------------------------------
@ -178,12 +178,12 @@
[(set (cc0) (match_operand:SI 0 "register_operand" "da"))]
""
"cmp 0,%0"
[(set_attr "cc" "set_zn_c0")])
[(set_attr "cc" "tst")])
(define_insn "cmpsi"
[(set (cc0)
(compare:SI (match_operand:SI 0 "register_operand" "da")
(match_operand:SI 1 "nonmemory_operand" "dai")))]
(match_operand:SI 1 "register_operand" "dai")))]
""
"cmp %1,%0"
[(set_attr "cc" "compare")])
@ -223,7 +223,7 @@
inc4 %0
add %2,%0
add %2,%0"
[(set_attr "cc" "set,none_0hit,none_0hit,set,none_0hit")])
[(set_attr "cc" "set_zn_c0,none_0hit,none_0hit,set_zn_c0,none_0hit")])
;; ----------------------------------------------------------------------
;; SUBTRACT INSTRUCTIONS
@ -235,7 +235,7 @@
(match_operand:SI 2 "register_operand" "dai")))]
""
"sub %2,%0"
[(set_attr "cc" "set")])
[(set_attr "cc" "set_zn_c0")])
(define_expand "negsi2"
[(set (match_operand:SI 0 "register_operand" "")
@ -571,38 +571,48 @@
;; EXTEND INSTRUCTIONS
;; ----------------------------------------------------------------------
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=d,d,d")
(zero_extend:SI
(match_operand:HI 1 "register_operand" "0")))]
(match_operand:QI 1 "general_operand" "0,d,m")))]
""
"exthu %0"
"@
extbu %0
mov %1,%0\;extbu %0
movbu %1,%0"
[(set_attr "cc" "none_0hit")])
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=d,d,d")
(zero_extend:SI
(match_operand:QI 1 "register_operand" "0")))]
(match_operand:HI 1 "general_operand" "0,d,m")))]
""
"extbu %0"
"@
exthu %0
mov %1,%0\;exthu %0
movhu %1,%0"
[(set_attr "cc" "none_0hit")])
;;- sign extension instructions
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "general_operand" "=d,d")
(sign_extend:SI
(match_operand:HI 1 "register_operand" "0")))]
(match_operand:QI 1 "general_operand" "0,d")))]
""
"exth %0"
"@
extb %0
mov %1,%0"
[(set_attr "cc" "none_0hit")])
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "general_operand" "=d,d")
(sign_extend:SI
(match_operand:QI 1 "register_operand" "0")))]
(match_operand:HI 1 "general_operand" "0,d")))]
""
"extb %0"
"@
exth %0
mov %1,%0"
[(set_attr "cc" "none_0hit")])
@ -611,13 +621,19 @@
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d")
[(set (match_operand:SI 0 "register_operand" "=da,d,a,d,a,d,a,d")
(ashift:SI
(match_operand:SI 1 "register_operand" "0,0")
(match_operand:QI 2 "nonmemory_operand" "K,di")))]
(match_operand:SI 1 "register_operand" "0,0,0,0,0,0,0,0")
(match_operand:QI 2 "nonmemory_operand" "J,K,K,M,M,L,L,di")))]
""
"@
add %0,%0
asl2 %0
add %0,%0\;add %0,%0
asl2 %0\;add %0,%0
add %0,%0\;add %0,%0\;add %0,%0
asl2 %0\;asl2 %0
add %0,%0\;add %0,%0\;add %0,%0\;add %0,%0
asl %2,%0"
[(set_attr "cc" "set_zn_c0")])
@ -656,15 +672,15 @@
DONE;
}")
(define_insn "return"
[(return)]
"0"
(define_insn "return_internal"
[(const_int 2)]
""
"rets"
[(set_attr "cc" "clobber")])
;; This insn restores the callee saved registers and does a return, it
;; can also deallocate stack space.
(define_insn "return_internal"
(define_insn "return_internal_regs"
[(const_int 0)
(match_operand:SI 0 "const_int_operand" "i")
(return)]
@ -677,3 +693,20 @@
""
"movm [d2,d3,a2,a3],(sp)"
[(set_attr "cc" "clobber")])
;; Try to combine consecutive updates of the stack pointer (or any
;; other register for that matter).
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=dax")
(plus:SI (match_dup 0)
(match_operand 1 "const_int_operand" "")))
(set (match_dup 0)
(plus:SI (match_dup 0)
(match_operand 2 "const_int_operand" "")))]
""
"*
{
operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
return \"add %1,%0\";
}"
[(set_attr "cc" "clobber")])