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:
parent
e9b1360b49
commit
777fbf098d
|
@ -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 ();
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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")])
|
||||
|
|
Loading…
Reference in New Issue