Describe special registers SRP and MOF as allocatable registers.
* config/cris/cris.c (cris_md_asm_clobbers): New function. (TARGET_MD_ASM_CLOBBERS): Define to cris_md_asm_clobbers. (cris_conditional_register_usage): Enable CRIS_MOF_REGNUM if TARGET_HAS_MUL_INSNS. (cris_print_operand) <case 'd'>: New case. <case REG>: Allow CRIS_MOF_REGNUM and CRIS_SRP_REGNUM. * config/cris/cris.h (CRIS_PC_REGNUM, CRIS_SRP_REGNUM): Don't define. (FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS) (REG_ALLOC_ORDER): Update for MOF. (enum reg_class): New members MOF_REGS, GENERAL_REGS and SPECIAL_REGS. (GENERAL_REGS): No longer a define of ALL_REGS. (REGNO_REG_CLASS, REG_CLASS_CONTENTS, REG_CLASS_NAMES) (PREFERRED_RELOAD_CLASS, REGISTER_NAMES, DBX_REGISTER_NUMBER): Adjust accordingly. (CRIS_SPECIAL_REGS_CONTENTS): New macro. (REG_CLASS_FROM_LETTER): Allocate 'h' and 'x'. (SECONDARY_RELOAD_CLASS): Define. (STACK_POINTER_REGNUM): Define as CRIS_SP_REGNUM. (FRAME_POINTER_REGNUM): Define as CRIS_FP_REGNUM. (ARG_POINTER_REGNUM): Define as CRIS_AP_REGNUM. (STATIC_CHAIN_REGNUM): Define as CRIS_STATIC_CHAIN_REGNUM. (REGISTER_MOVE_COST): Define. (PIC_OFFSET_TABLE_REGNUM): Define in terms of CRIS_GOT_REGNUM. * config/cris/cris.md (CRIS_GOT_REGNUM, CRIS_STATIC_CHAIN_REGNUM) (CRIS_FP_REGNUM, CRIS_SP_REGNUM, CRIS_SRP_REGNUM, CRIS_AP_REGNUM) (CRIS_MOF_REGNUM): New define_constants. ("*movsi_internal", "movhi", "movqi", "movsf"): Add alternatives for special registers. ("reload_inhi", "reload_outhi", "reload_inqi", ("umulhisi3", "umulqihi3", "mulsi3", "mulqihi3", "mulhisi3") ("mulsidi3", "umulsidi3", "smulsi3_highpart", "umulsi3_highpart"): Adjust for MOF being properly described as a register. (indir_to_reg_split): Name this split. Conditionalize on the destination register being a general register. (movei): Conditionalize on on operands 0 and 1 having the same register class. From-SVN: r95823
This commit is contained in:
parent
768875a86f
commit
f60c7155c1
4 changed files with 292 additions and 82 deletions
|
@ -1,3 +1,45 @@
|
|||
2005-03-03 Hans-Peter Nilsson <hp@axis.com>
|
||||
|
||||
Describe special registers SRP and MOF as allocatable registers.
|
||||
* config/cris/cris.c (cris_md_asm_clobbers): New function.
|
||||
(TARGET_MD_ASM_CLOBBERS): Define to cris_md_asm_clobbers.
|
||||
(cris_conditional_register_usage): Enable CRIS_MOF_REGNUM if
|
||||
TARGET_HAS_MUL_INSNS.
|
||||
(cris_print_operand) <case 'd'>: New case.
|
||||
<case REG>: Allow CRIS_MOF_REGNUM and CRIS_SRP_REGNUM.
|
||||
* config/cris/cris.h (CRIS_PC_REGNUM, CRIS_SRP_REGNUM): Don't
|
||||
define.
|
||||
(FIRST_PSEUDO_REGISTER, FIXED_REGISTERS, CALL_USED_REGISTERS)
|
||||
(REG_ALLOC_ORDER): Update for MOF.
|
||||
(enum reg_class): New members MOF_REGS, GENERAL_REGS and
|
||||
SPECIAL_REGS.
|
||||
(GENERAL_REGS): No longer a define of ALL_REGS.
|
||||
(REGNO_REG_CLASS, REG_CLASS_CONTENTS, REG_CLASS_NAMES)
|
||||
(PREFERRED_RELOAD_CLASS, REGISTER_NAMES, DBX_REGISTER_NUMBER):
|
||||
Adjust accordingly.
|
||||
(CRIS_SPECIAL_REGS_CONTENTS): New macro.
|
||||
(REG_CLASS_FROM_LETTER): Allocate 'h' and 'x'.
|
||||
(SECONDARY_RELOAD_CLASS): Define.
|
||||
(STACK_POINTER_REGNUM): Define as CRIS_SP_REGNUM.
|
||||
(FRAME_POINTER_REGNUM): Define as CRIS_FP_REGNUM.
|
||||
(ARG_POINTER_REGNUM): Define as CRIS_AP_REGNUM.
|
||||
(STATIC_CHAIN_REGNUM): Define as CRIS_STATIC_CHAIN_REGNUM.
|
||||
(REGISTER_MOVE_COST): Define.
|
||||
(PIC_OFFSET_TABLE_REGNUM): Define in terms of CRIS_GOT_REGNUM.
|
||||
* config/cris/cris.md (CRIS_GOT_REGNUM, CRIS_STATIC_CHAIN_REGNUM)
|
||||
(CRIS_FP_REGNUM, CRIS_SP_REGNUM, CRIS_SRP_REGNUM, CRIS_AP_REGNUM)
|
||||
(CRIS_MOF_REGNUM): New define_constants.
|
||||
("*movsi_internal", "movhi", "movqi", "movsf"): Add alternatives for
|
||||
special registers.
|
||||
("reload_inhi", "reload_outhi", "reload_inqi",
|
||||
("umulhisi3", "umulqihi3", "mulsi3", "mulqihi3", "mulhisi3")
|
||||
("mulsidi3", "umulsidi3", "smulsi3_highpart", "umulsi3_highpart"):
|
||||
Adjust for MOF being properly described as a register.
|
||||
(indir_to_reg_split): Name this split. Conditionalize on the
|
||||
destination register being a general register.
|
||||
(movei): Conditionalize on on operands 0 and 1 having the same
|
||||
register class.
|
||||
|
||||
2005-03-03 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
PR target/20277
|
||||
|
|
|
@ -125,6 +125,7 @@ static bool cris_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
|
|||
tree, bool);
|
||||
static int cris_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
|
||||
tree, bool);
|
||||
static tree cris_md_asm_clobbers (tree);
|
||||
|
||||
/* This is the argument from the "-max-stack-stackframe=" option. */
|
||||
const char *cris_max_stackframe_str;
|
||||
|
@ -196,6 +197,8 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
|
|||
#define TARGET_PASS_BY_REFERENCE cris_pass_by_reference
|
||||
#undef TARGET_ARG_PARTIAL_BYTES
|
||||
#define TARGET_ARG_PARTIAL_BYTES cris_arg_partial_bytes
|
||||
#undef TARGET_MD_ASM_CLOBBERS
|
||||
#define TARGET_MD_ASM_CLOBBERS cris_md_asm_clobbers
|
||||
|
||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||
|
||||
|
@ -479,6 +482,9 @@ cris_conditional_register_usage (void)
|
|||
if (flag_pic)
|
||||
fixed_regs[PIC_OFFSET_TABLE_REGNUM]
|
||||
= call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
|
||||
|
||||
if (TARGET_HAS_MUL_INSNS)
|
||||
fixed_regs[CRIS_MOF_REGNUM] = 0;
|
||||
}
|
||||
|
||||
/* Return current_function_uses_pic_offset_table. For use in cris.md,
|
||||
|
@ -1454,6 +1460,16 @@ cris_print_operand (FILE *file, rtx x, int code)
|
|||
fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
|
||||
return;
|
||||
|
||||
case 'd':
|
||||
/* If this is a GOT symbol, print it as :GOT regardless of -fpic. */
|
||||
if (flag_pic && CONSTANT_P (operand) && cris_got_symbol (operand))
|
||||
{
|
||||
cris_output_addr_const (file, operand);
|
||||
fprintf (file, ":GOT");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
/* When emitting an sub for the high part of a DImode constant, we
|
||||
want to use subq for 0 and subs.w for -1. */
|
||||
|
@ -1488,7 +1504,9 @@ cris_print_operand (FILE *file, rtx x, int code)
|
|||
switch (GET_CODE (operand))
|
||||
{
|
||||
case REG:
|
||||
if (REGNO (operand) > 15)
|
||||
if (REGNO (operand) > 15
|
||||
&& REGNO (operand) != CRIS_MOF_REGNUM
|
||||
&& REGNO (operand) != CRIS_SRP_REGNUM)
|
||||
internal_error ("internal error: bad register: %d", REGNO (operand));
|
||||
fprintf (file, "$%s", reg_names[REGNO (operand)]);
|
||||
return;
|
||||
|
@ -3039,6 +3057,16 @@ cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Worker function for TARGET_MD_ASM_CLOBBERS. */
|
||||
|
||||
static tree
|
||||
cris_md_asm_clobbers (tree clobbers)
|
||||
{
|
||||
return tree_cons (NULL_TREE,
|
||||
build_string (strlen (reg_names[CRIS_MOF_REGNUM]),
|
||||
reg_names[CRIS_MOF_REGNUM]),
|
||||
clobbers);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Various small functions to replace macros. Only called from a
|
||||
|
|
|
@ -50,12 +50,10 @@ Boston, MA 02111-1307, USA. */
|
|||
#define CRIS_FIRST_ARG_REG 10
|
||||
#define CRIS_MAX_ARGS_IN_REGS 4
|
||||
|
||||
/* Other convenience definitions. */
|
||||
#define CRIS_PC_REGNUM 15
|
||||
#define CRIS_SRP_REGNUM 16
|
||||
/* See also *_REGNUM constants in cris.md. */
|
||||
|
||||
/* Most of the time, we need the index into the register-names array.
|
||||
When passing debug-info, we need the real register number. */
|
||||
When passing debug-info, we need the real hardware register number. */
|
||||
#define CRIS_CANONICAL_SRP_REGNUM (16 + 11)
|
||||
#define CRIS_CANONICAL_MOF_REGNUM (16 + 7)
|
||||
|
||||
|
@ -602,9 +600,9 @@ extern int target_flags;
|
|||
|
||||
/* Node: Register Basics */
|
||||
|
||||
/* We count all 16 non-special registers, SRP and a faked argument
|
||||
pointer register. */
|
||||
#define FIRST_PSEUDO_REGISTER (16 + 1 + 1)
|
||||
/* We count all 16 non-special registers, SRP, a faked argument
|
||||
pointer register and MOF. */
|
||||
#define FIRST_PSEUDO_REGISTER (16 + 1 + 1 + 1)
|
||||
|
||||
/* For CRIS, these are r15 (pc) and r14 (sp). Register r8 is used as a
|
||||
frame-pointer, but is not fixed. SRP is not included in general
|
||||
|
@ -612,12 +610,12 @@ extern int target_flags;
|
|||
registers are fixed at the moment. The faked argument pointer register
|
||||
is fixed too. */
|
||||
#define FIXED_REGISTERS \
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1}
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1}
|
||||
|
||||
/* Register r9 is used for structure-address, r10-r13 for parameters,
|
||||
r10- for return values. */
|
||||
#define CALL_USED_REGISTERS \
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1}
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1}
|
||||
|
||||
#define CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage ()
|
||||
|
||||
|
@ -643,7 +641,7 @@ extern int target_flags;
|
|||
Use struct-return address first, since very few functions use
|
||||
structure return values so it is likely to be available. */
|
||||
#define REG_ALLOC_ORDER \
|
||||
{9, 13, 12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 17}
|
||||
{9, 13, 12, 11, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 18, 16, 17}
|
||||
|
||||
|
||||
/* Node: Values in Registers */
|
||||
|
@ -674,27 +672,46 @@ extern int target_flags;
|
|||
class for special registers, and yet another class for the
|
||||
multiply-overflow register in v10; then a class for the return
|
||||
register also makes sense. */
|
||||
enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
|
||||
enum reg_class
|
||||
{
|
||||
NO_REGS,
|
||||
MOF_REGS, SPECIAL_REGS, GENERAL_REGS, ALL_REGS,
|
||||
LIM_REG_CLASSES
|
||||
};
|
||||
|
||||
#define N_REG_CLASSES (int) LIM_REG_CLASSES
|
||||
|
||||
#define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS"}
|
||||
#define REG_CLASS_NAMES \
|
||||
{"NO_REGS", "MOF_REGS", "SPECIAL_REGS", "GENERAL_REGS", "ALL_REGS"}
|
||||
|
||||
#define GENERAL_REGS ALL_REGS
|
||||
#define CRIS_SPECIAL_REGS_CONTENTS \
|
||||
((1 << CRIS_SRP_REGNUM) | (1 << CRIS_MOF_REGNUM))
|
||||
|
||||
/* Count in the faked argument register in GENERAL_REGS. Keep out SRP. */
|
||||
#define REG_CLASS_CONTENTS {{0}, {0x2ffff}}
|
||||
#define REG_CLASS_CONTENTS \
|
||||
{ \
|
||||
{0}, \
|
||||
{1 << CRIS_MOF_REGNUM}, \
|
||||
{CRIS_SPECIAL_REGS_CONTENTS}, \
|
||||
{0x2ffff}, \
|
||||
{0x2ffff | CRIS_SPECIAL_REGS_CONTENTS} \
|
||||
}
|
||||
|
||||
#define REGNO_REG_CLASS(REGNO) GENERAL_REGS
|
||||
#define REGNO_REG_CLASS(REGNO) \
|
||||
((REGNO) == CRIS_MOF_REGNUM ? MOF_REGS : \
|
||||
(REGNO) == CRIS_SRP_REGNUM ? SPECIAL_REGS : \
|
||||
GENERAL_REGS)
|
||||
|
||||
#define BASE_REG_CLASS GENERAL_REGS
|
||||
|
||||
#define INDEX_REG_CLASS GENERAL_REGS
|
||||
|
||||
/* Get reg_class from a letter such as appears in the machine
|
||||
description. No letters are used, since 'r' is used for any
|
||||
register. */
|
||||
#define REG_CLASS_FROM_LETTER(C) NO_REGS
|
||||
#define REG_CLASS_FROM_LETTER(C) \
|
||||
( \
|
||||
(C) == 'h' ? MOF_REGS : \
|
||||
(C) == 'x' ? SPECIAL_REGS : \
|
||||
NO_REGS \
|
||||
)
|
||||
|
||||
/* Since it uses reg_renumber, it is safe only once reg_renumber
|
||||
has been allocated, which happens in local-alloc.c. */
|
||||
|
@ -710,9 +727,23 @@ enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
|
|||
/* It seems like gcc (2.7.2 and 2.9x of 2000-03-22) may send "NO_REGS" as
|
||||
the class for a constant (testcase: __Mul in arit.c). To avoid forcing
|
||||
out a constant into the constant pool, we will trap this case and
|
||||
return something a bit more sane. FIXME: Check if this is a bug. */
|
||||
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
|
||||
((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
|
||||
return something a bit more sane. FIXME: Check if this is a bug.
|
||||
Beware that we must not "override" classes that can be specified as
|
||||
constraint letters, or else asm operands using them will fail when
|
||||
they need to be reloaded. FIXME: Investigate whether that constitutes
|
||||
a bug. */
|
||||
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
|
||||
((CLASS) != MOF_REGS \
|
||||
&& (CLASS) != SPECIAL_REGS \
|
||||
? GENERAL_REGS : (CLASS))
|
||||
|
||||
/* We can't move special registers to and from memory in smaller than
|
||||
word_mode. */
|
||||
#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \
|
||||
(((CLASS) != SPECIAL_REGS && (CLASS) != MOF_REGS) \
|
||||
|| GET_MODE_SIZE (MODE) == 4 \
|
||||
|| GET_CODE (X) != MEM \
|
||||
? NO_REGS : GENERAL_REGS)
|
||||
|
||||
/* For CRIS, this is always the size of MODE in words,
|
||||
since all registers are the same size. To use omitted modes in
|
||||
|
@ -884,17 +915,17 @@ enum reg_class {NO_REGS, ALL_REGS, LIM_REG_CLASSES};
|
|||
|
||||
/* Node: Frame Registers */
|
||||
|
||||
#define STACK_POINTER_REGNUM 14
|
||||
#define STACK_POINTER_REGNUM CRIS_SP_REGNUM
|
||||
|
||||
/* Register used for frame pointer. This is also the last of the saved
|
||||
registers, when a frame pointer is not used. */
|
||||
#define FRAME_POINTER_REGNUM 8
|
||||
#define FRAME_POINTER_REGNUM CRIS_FP_REGNUM
|
||||
|
||||
/* Faked register, is always eliminated. We need it to eliminate
|
||||
allocating stack slots for the return address and the frame pointer. */
|
||||
#define ARG_POINTER_REGNUM 17
|
||||
#define ARG_POINTER_REGNUM CRIS_AP_REGNUM
|
||||
|
||||
#define STATIC_CHAIN_REGNUM 7
|
||||
#define STATIC_CHAIN_REGNUM CRIS_STATIC_CHAIN_REGNUM
|
||||
|
||||
|
||||
/* Node: Elimination */
|
||||
|
@ -1288,8 +1319,32 @@ struct cum_args {int regs;};
|
|||
|
||||
/* Node: Costs */
|
||||
|
||||
/* FIXME: Need to define REGISTER_MOVE_COST when more register classes are
|
||||
introduced. */
|
||||
/* Can't move to and from a SPECIAL_REGS register, so we have to say
|
||||
their move cost within that class is higher. How about 7? That's 3
|
||||
for a move to a GENERAL_REGS register, 3 for the move from the
|
||||
GENERAL_REGS register, and 1 for the increased register pressure.
|
||||
Also, it's higher than the memory move cost, which is in order.
|
||||
We also do this for ALL_REGS, since we don't want that class to be
|
||||
preferred (even to memory) at all where GENERAL_REGS doesn't fit.
|
||||
Whenever it's about to be used, it's for SPECIAL_REGS. If we don't
|
||||
present a higher cost for ALL_REGS than memory, a SPECIAL_REGS may be
|
||||
used when a GENERAL_REGS should be used, even if there are call-saved
|
||||
GENERAL_REGS left to allocate. This is because the fall-back when
|
||||
the most preferred register class isn't available, isn't the next
|
||||
(or next good) wider register class, but the *most widest* register
|
||||
class.
|
||||
Give the cost 3 between a special register and a general register,
|
||||
because we want constraints verified. */
|
||||
|
||||
#define REGISTER_MOVE_COST(MODE, FROM, TO) \
|
||||
((((FROM) == SPECIAL_REGS || (FROM) == MOF_REGS) \
|
||||
&& ((TO) == SPECIAL_REGS || (TO) == MOF_REGS)) \
|
||||
|| (FROM) == ALL_REGS \
|
||||
|| (TO) == ALL_REGS \
|
||||
? 7 : \
|
||||
((FROM) == SPECIAL_REGS || (FROM) == MOF_REGS \
|
||||
|| (TO) == SPECIAL_REGS || (TO) == MOF_REGS) \
|
||||
? 3 : 2)
|
||||
|
||||
/* This isn't strictly correct for v0..3 in buswidth-8bit mode, but
|
||||
should suffice. */
|
||||
|
@ -1323,7 +1378,7 @@ struct cum_args {int regs;};
|
|||
|
||||
/* Node: PIC */
|
||||
|
||||
#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 0 : INVALID_REGNUM)
|
||||
#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? CRIS_GOT_REGNUM : INVALID_REGNUM)
|
||||
|
||||
#define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
|
||||
|
||||
|
@ -1439,7 +1494,7 @@ struct cum_args {int regs;};
|
|||
|
||||
#define REGISTER_NAMES \
|
||||
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \
|
||||
"r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap"}
|
||||
"r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap", "mof"}
|
||||
|
||||
#define ADDITIONAL_REGISTER_NAMES \
|
||||
{{"r14", 14}, {"r15", 15}}
|
||||
|
@ -1525,8 +1580,10 @@ struct cum_args {int regs;};
|
|||
|
||||
/* Node: All Debuggers */
|
||||
|
||||
#define DBX_REGISTER_NUMBER(REGNO) \
|
||||
((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM : (REGNO))
|
||||
#define DBX_REGISTER_NUMBER(REGNO) \
|
||||
((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM : \
|
||||
(REGNO) == CRIS_MOF_REGNUM ? CRIS_CANONICAL_MOF_REGNUM : \
|
||||
(REGNO))
|
||||
|
||||
/* FIXME: Investigate DEBUGGER_AUTO_OFFSET, DEBUGGER_ARG_OFFSET. */
|
||||
|
||||
|
|
|
@ -59,6 +59,18 @@
|
|||
;; 0 PLT reference from call expansion: operand 0 is the address,
|
||||
;; the mode is VOIDmode. Always wrapped in CONST.
|
||||
|
||||
|
||||
;; Register numbers.
|
||||
(define_constants
|
||||
[(CRIS_GOT_REGNUM 0)
|
||||
(CRIS_STATIC_CHAIN_REGNUM 7)
|
||||
(CRIS_FP_REGNUM 8)
|
||||
(CRIS_SP_REGNUM 14)
|
||||
(CRIS_SRP_REGNUM 16)
|
||||
(CRIS_AP_REGNUM 17)
|
||||
(CRIS_MOF_REGNUM 18)]
|
||||
)
|
||||
|
||||
;; We need an attribute to define whether an instruction can be put in
|
||||
;; a branch-delay slot or not, and whether it has a delay slot.
|
||||
;;
|
||||
|
@ -994,11 +1006,11 @@
|
|||
|
||||
(define_insn "*movsi_internal"
|
||||
[(set
|
||||
(match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r,r,g")
|
||||
(match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x, m,x")
|
||||
(match_operand:SI 1
|
||||
;; FIXME: We want to put S last, but apparently g matches S.
|
||||
;; It's a bug: an S is not a general_operand and shouldn't match g.
|
||||
"cris_general_operand_or_gotless_symbol" "r,Q>,M,M, I,r, M,n,!S,g,r"))]
|
||||
"cris_general_operand_or_gotless_symbol" "r,Q>,M,M, I,r, M,n,!S,g,r,x, rQ>,x,gi"))]
|
||||
""
|
||||
"*
|
||||
{
|
||||
|
@ -1014,6 +1026,12 @@
|
|||
case 10:
|
||||
return \"move.d %1,%0\";
|
||||
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
return \"move %d1,%0\";
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
|
@ -1059,7 +1077,8 @@
|
|||
return \"BOGUS: %1 to %0\";
|
||||
}
|
||||
}"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no")])
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no,yes,yes,no,no")
|
||||
(set_attr "cc" "*,*,*,*,*,*,*,*,*,*,*,none,none,none,none")])
|
||||
|
||||
;; Extend operations with side-effect from mem to register, using
|
||||
;; MOVS/MOVU. These are from mem to register only.
|
||||
|
@ -1207,8 +1226,8 @@
|
|||
|
||||
(define_insn "movhi"
|
||||
[(set
|
||||
(match_operand:HI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,r,r,r,g,g,r")
|
||||
(match_operand:HI 1 "general_operand" "r,Q>,M,M, I,r, L,O,n,M,r,g"))]
|
||||
(match_operand:HI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,r,r,r,g,g,r,r,x")
|
||||
(match_operand:HI 1 "general_operand" "r,Q>,M,M, I,r, L,O,n,M,r,g,x,r"))]
|
||||
""
|
||||
"*
|
||||
{
|
||||
|
@ -1220,6 +1239,9 @@
|
|||
case 10:
|
||||
case 11:
|
||||
return \"move.w %1,%0\";
|
||||
case 12:
|
||||
case 13:
|
||||
return \"move %1,%0\";
|
||||
case 2:
|
||||
case 3:
|
||||
case 9:
|
||||
|
@ -1241,11 +1263,8 @@
|
|||
return \"BOGUS: %1 to %0\";
|
||||
}
|
||||
}"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no")
|
||||
(set (attr "cc")
|
||||
(if_then_else (eq_attr "alternative" "7")
|
||||
(const_string "clobber")
|
||||
(const_string "normal")))])
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,yes,no,no,no,no,yes,yes")
|
||||
(set_attr "cc" "*,*,none,none,*,none,*,clobber,*,none,none,*,none,none")])
|
||||
|
||||
(define_insn "movstricthi"
|
||||
[(set
|
||||
|
@ -1263,10 +1282,26 @@
|
|||
move.w %1,%0
|
||||
move.w %1,%0"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
|
||||
|
||||
(define_expand "reload_inhi"
|
||||
[(set (match_operand:HI 2 "register_operand" "=r")
|
||||
(match_operand:HI 1 "memory_operand" "m"))
|
||||
(set (match_operand:HI 0 "register_operand" "=x")
|
||||
(match_dup 2))]
|
||||
""
|
||||
"")
|
||||
|
||||
(define_expand "reload_outhi"
|
||||
[(set (match_operand:HI 2 "register_operand" "=r")
|
||||
(match_operand:HI 1 "register_operand" "x"))
|
||||
(set (match_operand:HI 0 "memory_operand" "=m")
|
||||
(match_dup 2))]
|
||||
""
|
||||
"")
|
||||
|
||||
(define_insn "movqi"
|
||||
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,r,g,g,r,r")
|
||||
(match_operand:QI 1 "general_operand" "r,r, Q>,M,M, I,M,r,O,g"))]
|
||||
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,r,g,g,r,r,r,x")
|
||||
(match_operand:QI 1 "general_operand" "r,r, Q>,M,M, I,M,r,O,g,x,r"))]
|
||||
""
|
||||
"@
|
||||
move.b %1,%0
|
||||
|
@ -1278,12 +1313,11 @@
|
|||
clear.b %0
|
||||
move.b %1,%0
|
||||
moveq %b1,%0
|
||||
move.b %1,%0"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no")
|
||||
(set (attr "cc")
|
||||
(if_then_else (eq_attr "alternative" "8")
|
||||
(const_string "clobber")
|
||||
(const_string "normal")))])
|
||||
move.b %1,%0
|
||||
move %1,%0
|
||||
move %1,%0"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,yes,no,yes,yes")
|
||||
(set_attr "cc" "*,*,*,*,*,*,*,*,clobber,*,none,none")])
|
||||
|
||||
(define_insn "movstrictqi"
|
||||
[(set (strict_low_part
|
||||
|
@ -1301,14 +1335,30 @@
|
|||
move.b %1,%0"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
|
||||
|
||||
(define_expand "reload_inqi"
|
||||
[(set (match_operand:QI 2 "register_operand" "=r")
|
||||
(match_operand:QI 1 "memory_operand" "m"))
|
||||
(set (match_operand:QI 0 "register_operand" "=x")
|
||||
(match_dup 2))]
|
||||
""
|
||||
"")
|
||||
|
||||
(define_expand "reload_outqi"
|
||||
[(set (match_operand:QI 2 "register_operand" "=r")
|
||||
(match_operand:QI 1 "register_operand" "x"))
|
||||
(set (match_operand:QI 0 "memory_operand" "=m")
|
||||
(match_dup 2))]
|
||||
""
|
||||
"")
|
||||
|
||||
;; The valid "quick" bit-patterns are, except for 0.0, denormalized
|
||||
;; values REALLY close to 0, and some NaN:s (I think; their exponent is
|
||||
;; all ones); the worthwhile one is "0.0".
|
||||
;; It will use clear, so we know ALL types of immediate 0 never change cc.
|
||||
|
||||
(define_insn "movsf"
|
||||
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,g,g,r")
|
||||
(match_operand:SF 1 "general_operand" "r,r, Q>,G,G, G,r,g"))]
|
||||
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,Q>,r, r,Q>,g,g,r,r,x,Q>,m,x, x")
|
||||
(match_operand:SF 1 "general_operand" "r,r, Q>,G,G, G,r,g,x,r,x, x,Q>,g"))]
|
||||
""
|
||||
"@
|
||||
move.d %1,%0
|
||||
|
@ -1318,8 +1368,14 @@
|
|||
clear.d %0
|
||||
clear.d %0
|
||||
move.d %1,%0
|
||||
move.d %1,%0"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
|
||||
move.d %1,%0
|
||||
move %1,%0
|
||||
move %1,%0
|
||||
move %1,%0
|
||||
move %1,%0
|
||||
move %1,%0
|
||||
move %1,%0"
|
||||
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no,yes,yes,yes,no,yes,no")])
|
||||
|
||||
|
||||
;; Sign- and zero-extend insns with standard names.
|
||||
|
@ -2472,7 +2528,8 @@
|
|||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(mult:SI
|
||||
(zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
|
||||
(zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
|
||||
(zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!mulu.w %2,%0"
|
||||
[(set (attr "slottable")
|
||||
|
@ -2486,7 +2543,8 @@
|
|||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(mult:HI
|
||||
(zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
|
||||
(zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
|
||||
(zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!mulu.b %2,%0"
|
||||
[(set (attr "slottable")
|
||||
|
@ -2505,7 +2563,8 @@
|
|||
(define_insn "mulsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(mult:SI (match_operand:SI 1 "register_operand" "%0")
|
||||
(match_operand:SI 2 "register_operand" "r")))]
|
||||
(match_operand:SI 2 "register_operand" "r")))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!muls.d %2,%0"
|
||||
[(set (attr "slottable")
|
||||
|
@ -2523,7 +2582,8 @@
|
|||
[(set (match_operand:HI 0 "register_operand" "=r")
|
||||
(mult:HI
|
||||
(sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
|
||||
(sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
|
||||
(sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!muls.b %2,%0"
|
||||
[(set (attr "slottable")
|
||||
|
@ -2536,7 +2596,8 @@
|
|||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
(mult:SI
|
||||
(sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
|
||||
(sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
|
||||
(sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!muls.w %2,%0"
|
||||
[(set (attr "slottable")
|
||||
|
@ -2556,7 +2617,8 @@
|
|||
[(set (match_operand:DI 0 "register_operand" "=r")
|
||||
(mult:DI
|
||||
(sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
|
||||
(sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
|
||||
(sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!muls.d %2,%M0\;move $mof,%H0")
|
||||
|
||||
|
@ -2564,42 +2626,60 @@
|
|||
[(set (match_operand:DI 0 "register_operand" "=r")
|
||||
(mult:DI
|
||||
(zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
|
||||
(zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
|
||||
(zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))
|
||||
(clobber (match_scratch:SI 3 "=h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!mulu.d %2,%M0\;move $mof,%H0")
|
||||
|
||||
;; This pattern would probably not be needed if we add "mof" in its own
|
||||
;; register class (and open a can of worms about /not/ pairing it with a
|
||||
;; "normal" register). Having multiple register classes here, and
|
||||
;; applicable to the v10 variant only, seems worse than having these two
|
||||
;; patterns with multi-insn contents for now (may change; having a free
|
||||
;; call-clobbered register is worth some trouble).
|
||||
;; These two patterns may be expressible by other means, perhaps by making
|
||||
;; [u]?mulsidi3 a define_expand.
|
||||
|
||||
;; Due to register allocation braindamage, the clobber 1,2 alternatives
|
||||
;; cause a move into the clobbered register *before* the insn, then
|
||||
;; after the insn, mof is moved too, rather than the clobber assigned
|
||||
;; the last mof target. This became apparent when making MOF and SRP
|
||||
;; visible registers, with the necessary tweak to smulsi3_highpart.
|
||||
;; Because these patterns are used in division by constants, that damage
|
||||
;; is visible (ipps regression tests). Therefore the last two
|
||||
;; alternatives, "helping" reload to avoid an unnecessary move, but
|
||||
;; punished by force of one "?". Check code from "int d (int a) {return
|
||||
;; a / 1000;}" and unsigned. FIXME: Comment above was for 3.2, revisit.
|
||||
|
||||
(define_insn "smulsi3_highpart"
|
||||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
|
||||
[(set (match_operand:SI 0 "nonimmediate_operand" "=h,h,?r,?r")
|
||||
(truncate:SI
|
||||
(lshiftrt:DI
|
||||
(mult:DI
|
||||
(sign_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
|
||||
(sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
|
||||
(sign_extend:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
|
||||
(sign_extend:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
|
||||
(const_int 32))))
|
||||
(clobber (match_scratch:SI 3 "=X,1,1"))]
|
||||
(clobber (match_scratch:SI 3 "=1,2,h,h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!muls.d %2,%1\;move $mof,%0"
|
||||
[(set_attr "cc" "clobber")])
|
||||
"@
|
||||
%!muls.d %2,%1
|
||||
.error 'untested assembly generated by GCC (smulsi3_highpart): muls.d %1,%2'
|
||||
%!muls.d %2,%1\;move $mof,%0
|
||||
%!muls.d %1,%2\;move $mof,%0"
|
||||
[(set_attr "slottable" "yes,yes,no,no")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
(define_insn "umulsi3_highpart"
|
||||
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
|
||||
[(set (match_operand:SI 0 "register_operand" "=h,h,?r,?r")
|
||||
(truncate:SI
|
||||
(lshiftrt:DI
|
||||
(mult:DI
|
||||
(zero_extend:DI (match_operand:SI 1 "register_operand" "%0,r,r"))
|
||||
(zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r")))
|
||||
(zero_extend:DI (match_operand:SI 1 "register_operand" "r,r,0,r"))
|
||||
(zero_extend:DI (match_operand:SI 2 "register_operand" "r,r,r,0")))
|
||||
(const_int 32))))
|
||||
(clobber (match_scratch:SI 3 "=X,1,1"))]
|
||||
(clobber (match_scratch:SI 3 "=1,2,h,h"))]
|
||||
"TARGET_HAS_MUL_INSNS"
|
||||
"%!mulu.d %2,%1\;move $mof,%0"
|
||||
[(set_attr "cc" "clobber")])
|
||||
"@
|
||||
%!mulu.d %2,%1
|
||||
.error 'untested assembly generated by GCC (umulsi3_highpart): mulu.d %1,%2'
|
||||
%!mulu.d %2,%1\;move $mof,%0
|
||||
%!mulu.d %1,%2\;move $mof,%0"
|
||||
[(set_attr "slottable" "yes,yes,no,no")
|
||||
(set_attr "cc" "clobber")])
|
||||
|
||||
;; Divide and modulus instructions. CRIS only has a step instruction.
|
||||
|
||||
|
@ -4651,14 +4731,15 @@
|
|||
;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
|
||||
;; cselib_invalidate_regno.
|
||||
|
||||
(define_split
|
||||
(define_split ; indir_to_reg_split
|
||||
[(set (match_operand 0 "register_operand" "")
|
||||
(match_operand 1 "indirect_operand" ""))]
|
||||
"reload_completed
|
||||
&& REG_P (operands[0])
|
||||
&& GET_MODE_SIZE (GET_MODE (operands[0])) <= UNITS_PER_WORD
|
||||
&& (GET_CODE (XEXP (operands[1], 0)) == MEM
|
||||
|| CONSTANT_P (XEXP (operands[1], 0)))"
|
||||
|| CONSTANT_P (XEXP (operands[1], 0)))
|
||||
&& REGNO (operands[0]) < CRIS_LAST_GENERAL_REGISTER"
|
||||
[(set (match_dup 2) (match_dup 4))
|
||||
(set (match_dup 0) (match_dup 3))]
|
||||
"operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
|
||||
|
@ -4993,6 +5074,8 @@
|
|||
(set (match_operand 2 "register_operand" "")
|
||||
(match_operator 3 "cris_mem_op" [(match_dup 0)]))]
|
||||
"REGNO (operands[0]) == REGNO (operands[2])
|
||||
&& (REGNO_REG_CLASS (REGNO (operands[0]))
|
||||
== REGNO_REG_CLASS (REGNO (operands[1])))
|
||||
&& GET_MODE_SIZE (GET_MODE (operands[2])) <= UNITS_PER_WORD"
|
||||
[(set (match_dup 2) (match_dup 4))]
|
||||
"operands[4] = replace_equiv_address (operands[3], operands[1]);")
|
||||
|
|
Loading…
Add table
Reference in a new issue