This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Committed, CRIS: Describe special registers SRP and MOF as allocatable registers.
- From: Hans-Peter Nilsson <hans-peter dot nilsson at axis dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 3 Mar 2005 04:54:16 +0100
- Subject: Committed, CRIS: Describe special registers SRP and MOF as allocatable registers.
(MOF is for "multiplication overflow"; high 32 bits of 64-bit
result; SRP is for "subroutine return pointer".)
I was hoping to get the TARGET_MD_ASM_CLOBBERS patch at
<URL:http://gcc.gnu.org/ml/gcc-patches/2005-02/msg01725.html>
approved before this, but I need pieces of this patch to
continue. No harm done by applying it: couldn't describe MOF as
an asm input or output before, still can't after this patch.
Figures for my favorite test apps compared to before this patch:
Performance figures: 99.28% and 99.44%.
Size figures: 99.95% and 99.85%.
Tested cris-elf, committed.
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.
Index: cris.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.c,v
retrieving revision 1.67
diff -c -p -r1.67 cris.c
*** cris.c 1 Mar 2005 20:37:30 -0000 1.67
--- cris.c 3 Mar 2005 03:34:56 -0000
*************** static bool cris_pass_by_reference (CUMU
*** 125,130 ****
--- 125,131 ----
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;
*************** int cris_cpu_version = CRIS_DEFAULT_CPU_
*** 196,201 ****
--- 197,204 ----
#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;
*************** cris_conditional_register_usage (void)
*** 479,484 ****
--- 482,490 ----
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,
*************** cris_print_operand (FILE *file, rtx x, i
*** 1454,1459 ****
--- 1460,1475 ----
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. */
*************** cris_print_operand (FILE *file, rtx x, i
*** 1488,1494 ****
switch (GET_CODE (operand))
{
case REG:
! if (REGNO (operand) > 15)
internal_error ("internal error: bad register: %d", REGNO (operand));
fprintf (file, "$%s", reg_names[REGNO (operand)]);
return;
--- 1504,1512 ----
switch (GET_CODE (operand))
{
case REG:
! 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;
*************** cris_arg_partial_bytes (CUMULATIVE_ARGS
*** 3039,3044 ****
--- 3057,3072 ----
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
Index: cris.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.h,v
retrieving revision 1.86
diff -c -p -r1.86 cris.h
*** cris.h 1 Mar 2005 20:37:30 -0000 1.86
--- cris.h 3 Mar 2005 03:34:56 -0000
*************** Boston, MA 02111-1307, USA. */
*** 50,61 ****
#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
/* Most of the time, we need the index into the register-names array.
! When passing debug-info, we need the real register number. */
#define CRIS_CANONICAL_SRP_REGNUM (16 + 11)
#define CRIS_CANONICAL_MOF_REGNUM (16 + 7)
--- 50,59 ----
#define CRIS_FIRST_ARG_REG 10
#define CRIS_MAX_ARGS_IN_REGS 4
! /* 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 hardware register number. */
#define CRIS_CANONICAL_SRP_REGNUM (16 + 11)
#define CRIS_CANONICAL_MOF_REGNUM (16 + 7)
*************** extern int target_flags;
*** 602,610 ****
/* Node: Register Basics */
! /* We count all 16 non-special registers, SRP and a faked argument
! pointer register. */
! #define FIRST_PSEUDO_REGISTER (16 + 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
--- 600,608 ----
/* Node: Register Basics */
! /* 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
*************** extern int target_flags;
*** 612,623 ****
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}
/* 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}
#define CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage ()
--- 610,621 ----
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, 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, 1}
#define CONDITIONAL_REGISTER_USAGE cris_conditional_register_usage ()
*************** extern int target_flags;
*** 643,649 ****
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}
/* Node: Values in Registers */
--- 641,647 ----
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, 18, 16, 17}
/* Node: Values in Registers */
*************** extern int target_flags;
*** 674,700 ****
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};
#define N_REG_CLASSES (int) LIM_REG_CLASSES
! #define REG_CLASS_NAMES {"NO_REGS", "ALL_REGS"}
! #define GENERAL_REGS ALL_REGS
/* Count in the faked argument register in GENERAL_REGS. Keep out SRP. */
! #define REG_CLASS_CONTENTS {{0}, {0x2ffff}}
!
! #define REGNO_REG_CLASS(REGNO) 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
/* Since it uses reg_renumber, it is safe only once reg_renumber
has been allocated, which happens in local-alloc.c. */
--- 672,717 ----
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,
! 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", "MOF_REGS", "SPECIAL_REGS", "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}, \
! {1 << CRIS_MOF_REGNUM}, \
! {CRIS_SPECIAL_REGS_CONTENTS}, \
! {0x2ffff}, \
! {0x2ffff | CRIS_SPECIAL_REGS_CONTENTS} \
! }
!
! #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
! #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. */
*************** enum reg_class {NO_REGS, ALL_REGS, LIM_R
*** 710,718 ****
/* 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))
/* For CRIS, this is always the size of MODE in words,
since all registers are the same size. To use omitted modes in
--- 727,749 ----
/* 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.
! 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
*************** enum reg_class {NO_REGS, ALL_REGS, LIM_R
*** 884,900 ****
/* Node: Frame Registers */
! #define STACK_POINTER_REGNUM 14
/* 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
/* 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 STATIC_CHAIN_REGNUM 7
/* Node: Elimination */
--- 915,931 ----
/* Node: Frame Registers */
! #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 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 CRIS_AP_REGNUM
! #define STATIC_CHAIN_REGNUM CRIS_STATIC_CHAIN_REGNUM
/* Node: Elimination */
*************** struct cum_args {int regs;};
*** 1288,1295 ****
/* Node: Costs */
! /* FIXME: Need to define REGISTER_MOVE_COST when more register classes are
! introduced. */
/* This isn't strictly correct for v0..3 in buswidth-8bit mode, but
should suffice. */
--- 1319,1350 ----
/* Node: Costs */
! /* 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. */
*************** struct cum_args {int regs;};
*** 1323,1329 ****
/* Node: PIC */
! #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 0 : INVALID_REGNUM)
#define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
--- 1378,1384 ----
/* Node: PIC */
! #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? CRIS_GOT_REGNUM : INVALID_REGNUM)
#define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
*************** struct cum_args {int regs;};
*** 1439,1445 ****
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \
! "r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap"}
#define ADDITIONAL_REGISTER_NAMES \
{{"r14", 14}, {"r15", 15}}
--- 1494,1500 ----
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", \
! "r9", "r10", "r11", "r12", "r13", "sp", "pc", "srp", "faked_ap", "mof"}
#define ADDITIONAL_REGISTER_NAMES \
{{"r14", 14}, {"r15", 15}}
*************** struct cum_args {int regs;};
*** 1525,1532 ****
/* Node: All Debuggers */
! #define DBX_REGISTER_NUMBER(REGNO) \
! ((REGNO) == CRIS_SRP_REGNUM ? CRIS_CANONICAL_SRP_REGNUM : (REGNO))
/* FIXME: Investigate DEBUGGER_AUTO_OFFSET, DEBUGGER_ARG_OFFSET. */
--- 1580,1589 ----
/* Node: All Debuggers */
! #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. */
Index: cris.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.md,v
retrieving revision 1.24
diff -c -p -r1.24 cris.md
*** cris.md 2 Mar 2005 16:48:29 -0000 1.24
--- cris.md 3 Mar 2005 03:34:56 -0000
***************
*** 59,64 ****
--- 59,76 ----
;; 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,1004 ****
(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 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"))]
""
"*
{
--- 1006,1016 ----
(define_insn "*movsi_internal"
[(set
! (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,x, rQ>,x,gi"))]
""
"*
{
***************
*** 1014,1019 ****
--- 1026,1037 ----
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,1065 ****
return \"BOGUS: %1 to %0\";
}
}"
! [(set_attr "slottable" "yes,yes,yes,yes,yes,yes,no,no,no,no,no")])
;; Extend operations with side-effect from mem to register, using
;; MOVS/MOVU. These are from mem to register only.
--- 1077,1084 ----
return \"BOGUS: %1 to %0\";
}
}"
! [(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,1214 ****
(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"))]
""
"*
{
--- 1226,1233 ----
(define_insn "movhi"
[(set
! (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,1225 ****
--- 1239,1247 ----
case 10:
case 11:
return \"move.w %1,%0\";
+ case 12:
+ case 13:
+ return \"move %1,%0\";
case 2:
case 3:
case 9:
***************
*** 1241,1251 ****
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")))])
(define_insn "movstricthi"
[(set
--- 1263,1270 ----
return \"BOGUS: %1 to %0\";
}
}"
! [(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,1272 ****
move.w %1,%0
move.w %1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
(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"))]
""
"@
move.b %1,%0
--- 1282,1307 ----
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,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,1289 ****
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")))])
(define_insn "movstrictqi"
[(set (strict_low_part
--- 1313,1323 ----
clear.b %0
move.b %1,%0
moveq %b1,%0
! 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,1314 ****
move.b %1,%0"
[(set_attr "slottable" "yes,yes,yes,yes,yes,no,no,no")])
;; 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"))]
""
"@
move.d %1,%0
--- 1335,1364 ----
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,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,1325 ****
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")])
;; Sign- and zero-extend insns with standard names.
--- 1368,1381 ----
clear.d %0
clear.d %0
move.d %1,%0
! 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,2478 ****
[(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"))))]
"TARGET_HAS_MUL_INSNS"
"%!mulu.w %2,%0"
[(set (attr "slottable")
--- 2528,2535 ----
[(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"))))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!mulu.w %2,%0"
[(set (attr "slottable")
***************
*** 2486,2492 ****
[(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"))))]
"TARGET_HAS_MUL_INSNS"
"%!mulu.b %2,%0"
[(set (attr "slottable")
--- 2543,2550 ----
[(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"))))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!mulu.b %2,%0"
[(set (attr "slottable")
***************
*** 2505,2511 ****
(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")))]
"TARGET_HAS_MUL_INSNS"
"%!muls.d %2,%0"
[(set (attr "slottable")
--- 2563,2570 ----
(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")))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!muls.d %2,%0"
[(set (attr "slottable")
***************
*** 2523,2529 ****
[(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"))))]
"TARGET_HAS_MUL_INSNS"
"%!muls.b %2,%0"
[(set (attr "slottable")
--- 2582,2589 ----
[(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"))))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!muls.b %2,%0"
[(set (attr "slottable")
***************
*** 2536,2542 ****
[(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"))))]
"TARGET_HAS_MUL_INSNS"
"%!muls.w %2,%0"
[(set (attr "slottable")
--- 2596,2603 ----
[(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"))))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!muls.w %2,%0"
[(set (attr "slottable")
***************
*** 2556,2562 ****
[(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"))))]
"TARGET_HAS_MUL_INSNS"
"%!muls.d %2,%M0\;move $mof,%H0")
--- 2617,2624 ----
[(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"))))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!muls.d %2,%M0\;move $mof,%H0")
***************
*** 2564,2605 ****
[(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"))))]
"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).
(define_insn "smulsi3_highpart"
! [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
(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")))
(const_int 32))))
! (clobber (match_scratch:SI 3 "=X,1,1"))]
"TARGET_HAS_MUL_INSNS"
! "%!muls.d %2,%1\;move $mof,%0"
! [(set_attr "cc" "clobber")])
(define_insn "umulsi3_highpart"
! [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m")
(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")))
(const_int 32))))
! (clobber (match_scratch:SI 3 "=X,1,1"))]
"TARGET_HAS_MUL_INSNS"
! "%!mulu.d %2,%1\;move $mof,%0"
! [(set_attr "cc" "clobber")])
;; Divide and modulus instructions. CRIS only has a step instruction.
--- 2626,2685 ----
[(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"))))
! (clobber (match_scratch:SI 3 "=h"))]
"TARGET_HAS_MUL_INSNS"
"%!mulu.d %2,%M0\;move $mof,%H0")
! ;; 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" "=h,h,?r,?r")
(truncate:SI
(lshiftrt:DI
(mult:DI
! (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 "=1,2,h,h"))]
"TARGET_HAS_MUL_INSNS"
! "@
! %!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 "register_operand" "=h,h,?r,?r")
(truncate:SI
(lshiftrt:DI
(mult:DI
! (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 "=1,2,h,h"))]
"TARGET_HAS_MUL_INSNS"
! "@
! %!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,4664 ****
;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
;; cselib_invalidate_regno.
! (define_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)))"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 0) (match_dup 3))]
"operands[2] = gen_rtx_REG (Pmode, REGNO (operands[0]));
--- 4731,4745 ----
;; 2001-08-24, unwind-dw2-fde.c, _Unwind_Find_FDE ICE in
;; cselib_invalidate_regno.
! (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)))
! && 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,4998 ****
--- 5074,5081 ----
(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]);")
brgds, H-P