From patchwork Mon Jan 10 20:31:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 78226 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id ED386B7110 for ; Tue, 11 Jan 2011 07:36:20 +1100 (EST) Received: (qmail 25304 invoked by alias); 10 Jan 2011 20:34:13 -0000 Received: (qmail 21799 invoked by uid 22791); 10 Jan 2011 20:33:36 -0000 X-SWARE-Spam-Status: No, hits=-1.0 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, TW_OV, TW_VB, TW_VH X-Spam-Check-By: sourceware.org Received: from eggs.gnu.org (HELO eggs.gnu.org) (140.186.70.92) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 10 Jan 2011 20:32:52 +0000 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PcOQ1-000758-MT for gcc-patches@gcc.gnu.org; Mon, 10 Jan 2011 15:32:50 -0500 Received: from b.mail.sonic.net ([64.142.19.5]:41377) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PcOQ0-00074q-Qa for gcc-patches@gcc.gnu.org; Mon, 10 Jan 2011 15:32:45 -0500 Received: from are.twiddle.net (are.twiddle.net [75.101.38.216]) by b.mail.sonic.net (8.13.8.Beta0-Sonic/8.13.7) with ESMTP id p0AKWh1r000316 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 10 Jan 2011 12:32:43 -0800 Received: from anchor.twiddle.home (anchor.twiddle.home [172.31.0.4]) by are.twiddle.net (8.14.4/8.14.4) with ESMTP id p0AKWgcm006793; Mon, 10 Jan 2011 12:32:42 -0800 Received: from anchor.twiddle.home (localhost.localdomain [127.0.0.1]) by anchor.twiddle.home (8.14.4/8.14.4) with ESMTP id p0AKWe6O019721; Mon, 10 Jan 2011 12:32:40 -0800 Received: (from rth@localhost) by anchor.twiddle.home (8.14.4/8.14.4/Submit) id p0AKWdjN019720; Mon, 10 Jan 2011 12:32:39 -0800 From: Richard Henderson To: gcc-patches@gcc.gnu.org Cc: nickc@redhat.com, law@redhat.com, Richard Henderson Subject: [PATCH 18/28] mn10300: Cleanup all arithmetic. Date: Mon, 10 Jan 2011 12:31:47 -0800 Message-Id: <1294691517-19580-19-git-send-email-rth@redhat.com> In-Reply-To: <1294691517-19580-1-git-send-email-rth@redhat.com> References: <1294691517-19580-1-git-send-email-rth@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org From: Richard Henderson For addition and logicals, define an operation-plus-flags update pattern in preparation for compare elimination. In addition, clean up the way we compare and validate CC_MODEs. Define NEG in terms of NOT; this is smaller and allows a non-clobbering destination alternative. --- gcc/config/mn10300/mn10300-modes.def | 2 + gcc/config/mn10300/mn10300-protos.h | 7 +- gcc/config/mn10300/mn10300.c | 481 ++++++++++----- gcc/config/mn10300/mn10300.h | 2 +- gcc/config/mn10300/mn10300.md | 1120 +++++++++++----------------------- gcc/config/mn10300/predicates.md | 16 + 6 files changed, 684 insertions(+), 944 deletions(-) diff --git a/gcc/config/mn10300/mn10300-modes.def b/gcc/config/mn10300/mn10300-modes.def index 8bcffcd..832663e 100644 --- a/gcc/config/mn10300/mn10300-modes.def +++ b/gcc/config/mn10300/mn10300-modes.def @@ -19,4 +19,6 @@ the Free Software Foundation, , Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +CC_MODE (CCZN); +CC_MODE (CCZNC); CC_MODE (CC_FLOAT); diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h index d0ce1b3..28a9412 100644 --- a/gcc/config/mn10300/mn10300-protos.h +++ b/gcc/config/mn10300/mn10300-protos.h @@ -32,13 +32,16 @@ extern int mn10300_get_live_callee_saved_regs (void); extern bool mn10300_hard_regno_mode_ok (unsigned int, Mmode); extern bool mn10300_legitimate_constant_p (rtx); extern bool mn10300_modes_tieable (Mmode, Mmode); -extern Cstar mn10300_output_cmp (rtx, rtx); +extern Cstar mn10300_output_add (rtx[3], bool); extern void mn10300_print_operand (FILE *, rtx, int); extern void mn10300_print_operand_address (FILE *, rtx); extern void mn10300_print_reg_list (FILE *, int); -extern Mmode mn10300_select_cc_mode (rtx); +extern Mmode mn10300_select_cc_mode (enum rtx_code, rtx, rtx); extern int mn10300_store_multiple_operation (rtx, Mmode); extern int mn10300_symbolic_operand (rtx, Mmode); +extern void mn10300_split_cbranch (Mmode, rtx, rtx); +extern int mn10300_split_and_operand_count (rtx); +extern bool mn10300_match_ccmode (rtx, Mmode); #endif /* RTX_CODE */ extern bool mn10300_regno_in_class_p (unsigned, int, bool); diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 36c35ca..8e62a0c 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -81,6 +81,14 @@ static const struct default_options mn10300_option_optimization_table[] = { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, { OPT_LEVELS_NONE, 0, NULL, 0 } }; + +#define CC_FLAG_Z 1 +#define CC_FLAG_N 2 +#define CC_FLAG_C 4 +#define CC_FLAG_V 8 + +static int cc_flags_for_mode(enum machine_mode); +static int cc_flags_for_code(enum rtx_code); /* Implement TARGET_HANDLE_OPTION. */ @@ -134,7 +142,7 @@ mn10300_option_override (void) when this flag is not enabled by default. */ flag_split_wide_types = 1; } - + if (mn10300_tune_string) { if (strcasecmp (mn10300_tune_string, "mn10300") == 0) @@ -171,95 +179,82 @@ mn10300_print_operand (FILE *file, rtx x, int code) { case 'b': case 'B': - if (GET_MODE (XEXP (x, 0)) == CC_FLOATmode) - { - switch (code == 'b' ? GET_CODE (x) - : reverse_condition_maybe_unordered (GET_CODE (x))) - { - case NE: - fprintf (file, "ne"); - break; - case EQ: - fprintf (file, "eq"); - break; - case GE: - fprintf (file, "ge"); - break; - case GT: - fprintf (file, "gt"); - break; - case LE: - fprintf (file, "le"); - break; - case LT: - fprintf (file, "lt"); - break; - case ORDERED: - fprintf (file, "lge"); - break; - case UNORDERED: - fprintf (file, "uo"); - break; - case LTGT: - fprintf (file, "lg"); - break; - case UNEQ: - fprintf (file, "ue"); - break; - case UNGE: - fprintf (file, "uge"); - break; - case UNGT: - fprintf (file, "ug"); - break; - case UNLE: - fprintf (file, "ule"); - break; - case UNLT: - fprintf (file, "ul"); - break; - default: - gcc_unreachable (); - } - break; - } - /* These are normal and reversed branches. */ - switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x))) - { - case NE: - fprintf (file, "ne"); - break; - case EQ: - fprintf (file, "eq"); - break; - case GE: - fprintf (file, "ge"); - break; - case GT: - fprintf (file, "gt"); - break; - case LE: - fprintf (file, "le"); - break; - case LT: - fprintf (file, "lt"); - break; - case GEU: - fprintf (file, "cc"); - break; - case GTU: - fprintf (file, "hi"); - break; - case LEU: - fprintf (file, "ls"); - break; - case LTU: - fprintf (file, "cs"); - break; - default: - gcc_unreachable (); - } + { + enum rtx_code cmp = GET_CODE (x); + enum machine_mode mode = GET_MODE (XEXP (x, 0)); + const char *str; + int have_flags; + + if (code == 'B') + cmp = reverse_condition (cmp); + have_flags = cc_flags_for_mode (mode); + + switch (cmp) + { + case NE: + str = "ne"; + break; + case EQ: + str = "eq"; + break; + case GE: + /* bge is smaller than bnc. */ + str = (have_flags & CC_FLAG_V ? "ge" : "nc"); + break; + case LT: + str = (have_flags & CC_FLAG_V ? "lt" : "ns"); + break; + case GT: + str = "gt"; + break; + case LE: + str = "le"; + break; + case GEU: + str = "cc"; + break; + case GTU: + str = "hi"; + break; + case LEU: + str = "ls"; + break; + case LTU: + str = "cs"; + break; + case ORDERED: + str = "lge"; + break; + case UNORDERED: + str = "uo"; + break; + case LTGT: + str = "lg"; + break; + case UNEQ: + str = "ue"; + break; + case UNGE: + str = "uge"; + break; + case UNGT: + str = "ug"; + break; + case UNLE: + str = "ule"; + break; + case UNLT: + str = "ul"; + break; + default: + gcc_unreachable (); + } + + gcc_checking_assert ((cc_flags_for_code (cmp) & ~have_flags) == 0); + fputs (str, file); + } break; + case 'C': /* This is used for the operand to a call instruction; if it's a REG, enclose it in parens, else output @@ -1709,95 +1704,96 @@ mn10300_function_value_regno_p (const unsigned int regno) return (regno == FIRST_DATA_REGNUM || regno == FIRST_ADDRESS_REGNUM); } -/* Output a compare insn. */ +/* Output an addition operation. */ const char * -mn10300_output_cmp (rtx operand, rtx insn) +mn10300_output_add (rtx operands[3], bool need_flags) { - rtx temp; - int past_call = 0; + rtx dest, src1, src2; + unsigned int dest_regnum, src1_regnum, src2_regnum; + enum reg_class src1_class, src2_class, dest_class; - /* We can save a byte if we can find a register which has the value - zero in it. */ - temp = PREV_INSN (insn); - while (optimize && temp) - { - rtx set; - - /* We allow the search to go through call insns. We record - the fact that we've past a CALL_INSN and reject matches which - use call clobbered registers. */ - if (LABEL_P (temp) - || JUMP_P (temp) - || GET_CODE (temp) == BARRIER) - break; + dest = operands[0]; + src1 = operands[1]; + src2 = operands[2]; - if (CALL_P (temp)) - past_call = 1; + dest_regnum = true_regnum (dest); + src1_regnum = true_regnum (src1); - if (GET_CODE (temp) == NOTE) - { - temp = PREV_INSN (temp); - continue; - } + dest_class = REGNO_REG_CLASS (dest_regnum); + src1_class = REGNO_REG_CLASS (src1_regnum); - /* It must be an insn, see if it is a simple set. */ - set = single_set (temp); - if (!set) - { - temp = PREV_INSN (temp); - continue; - } + if (GET_CODE (src2) == CONST_INT) + { + gcc_assert (dest_regnum == src1_regnum); - /* Are we setting a data register to zero (this does not win for - address registers)? - - If it's a call clobbered register, have we past a call? - - Make sure the register we find isn't the same as ourself; - the mn10300 can't encode that. - - ??? reg_set_between_p return nonzero anytime we pass a CALL_INSN - so the code to detect calls here isn't doing anything useful. */ - if (REG_P (SET_DEST (set)) - && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) - && !reg_set_between_p (SET_DEST (set), temp, insn) - && (REGNO_REG_CLASS (REGNO (SET_DEST (set))) - == REGNO_REG_CLASS (REGNO (operand))) - && REGNO_REG_CLASS (REGNO (SET_DEST (set))) != EXTENDED_REGS - && REGNO (SET_DEST (set)) != REGNO (operand) - && (!past_call - || ! call_really_used_regs [REGNO (SET_DEST (set))])) - { - rtx xoperands[2]; - xoperands[0] = operand; - xoperands[1] = SET_DEST (set); + if (src2 == const1_rtx && !need_flags) + return "inc %0"; + if (INTVAL (src2) == 4 && !need_flags && dest_class != DATA_REGS) + return "inc4 %0"; - output_asm_insn ("cmp %1,%0", xoperands); - return ""; - } + gcc_assert (!need_flags || dest_class != SP_REGS); + return "add %2,%0"; + } + else if (CONSTANT_P (src2)) + return "add %2,%0"; + + src2_regnum = true_regnum (src2); + src2_class = REGNO_REG_CLASS (src2_regnum); + + if (dest_regnum == src1_regnum) + return "add %2,%0"; + if (dest_regnum == src2_regnum) + return "add %1,%0"; + + /* The rest of the cases are reg = reg+reg. For AM33, we can implement + this directly, as below, but when optimizing for space we can sometimes + do better by using a mov+add. For MN103, we claimed that we could + implement a three-operand add because the various move and add insns + change sizes across register classes, and we can often do better than + reload in chosing which operand to move. */ + if (TARGET_AM33 && optimize_insn_for_speed_p ()) + return "add %2,%1,%0"; + + /* Catch cases where no extended register was used. */ + if (src1_class != EXTENDED_REGS + && src2_class != EXTENDED_REGS + && dest_class != EXTENDED_REGS) + { + /* We have to copy one of the sources into the destination, then + add the other source to the destination. + + Carefully select which source to copy to the destination; a + naive implementation will waste a byte when the source classes + are different and the destination is an address register. + Selecting the lowest cost register copy will optimize this + sequence. */ + if (src1_class == dest_class) + return "mov %1,%0\n\tadd %2,%0"; + else + return "mov %2,%0\n\tadd %1,%0"; + } - if (REGNO_REG_CLASS (REGNO (operand)) == EXTENDED_REGS - && REG_P (SET_DEST (set)) - && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set))) - && !reg_set_between_p (SET_DEST (set), temp, insn) - && (REGNO_REG_CLASS (REGNO (SET_DEST (set))) - != REGNO_REG_CLASS (REGNO (operand))) - && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == EXTENDED_REGS - && REGNO (SET_DEST (set)) != REGNO (operand) - && (!past_call - || ! call_really_used_regs [REGNO (SET_DEST (set))])) - { - rtx xoperands[2]; - xoperands[0] = operand; - xoperands[1] = SET_DEST (set); + /* At least one register is an extended register. */ - output_asm_insn ("cmp %1,%0", xoperands); - return ""; - } - temp = PREV_INSN (temp); - } - return "cmp 0,%0"; + /* The three operand add instruction on the am33 is a win iff the + output register is an extended register, or if both source + registers are extended registers. */ + if (dest_class == EXTENDED_REGS || src1_class == src2_class) + return "add %2,%1,%0"; + + /* It is better to copy one of the sources to the destination, then + perform a 2 address add. The destination in this case must be + an address or data register and one of the sources must be an + extended register and the remaining source must not be an extended + register. + + The best code for this case is to copy the extended reg to the + destination, then emit a two address add. */ + if (src1_class == EXTENDED_REGS) + return "mov %1,%0\n\tadd %2,%0"; + else + return "mov %2,%0\n\tadd %1,%0"; } /* Return 1 if X contains a symbolic expression. We know these @@ -2614,10 +2610,80 @@ mn10300_modes_tieable (enum machine_mode mode1, enum machine_mode mode2) return false; } +static int +cc_flags_for_mode (enum machine_mode mode) +{ + switch (mode) + { + case CCmode: + return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C | CC_FLAG_V; + case CCZNCmode: + return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C; + case CCZNmode: + return CC_FLAG_Z | CC_FLAG_N; + case CC_FLOATmode: + return -1; + default: + gcc_unreachable (); + } +} + +static int +cc_flags_for_code (enum rtx_code code) +{ + switch (code) + { + case EQ: /* Z */ + case NE: /* ~Z */ + return CC_FLAG_Z; + + case LT: /* N */ + case GE: /* ~N */ + return CC_FLAG_N; + break; + + case GT: /* ~(Z|(N^V)) */ + case LE: /* Z|(N^V) */ + return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_V; + + case GEU: /* ~C */ + case LTU: /* C */ + return CC_FLAG_C; + + case GTU: /* ~(C | Z) */ + case LEU: /* C | Z */ + return CC_FLAG_Z | CC_FLAG_C; + + case ORDERED: + case UNORDERED: + case LTGT: + case UNEQ: + case UNGE: + case UNGT: + case UNLE: + case UNLT: + return -1; + + default: + gcc_unreachable (); + } +} + enum machine_mode -mn10300_select_cc_mode (rtx x) +mn10300_select_cc_mode (enum rtx_code code, rtx x, rtx y ATTRIBUTE_UNUSED) { - return (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ? CC_FLOATmode : CCmode; + int req; + + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + return CC_FLOATmode; + + req = cc_flags_for_code (code); + + if (req & CC_FLAG_V) + return CCmode; + if (req & CC_FLAG_C) + return CCZNCmode; + return CCZNmode; } static inline bool @@ -2736,6 +2802,83 @@ mn10300_conditional_register_usage (void) fixed_regs[PIC_OFFSET_TABLE_REGNUM] = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; } + + +/* A helper function for splitting cbranch patterns after reload. */ + +void +mn10300_split_cbranch (enum machine_mode cmp_mode, rtx cmp_op, rtx label_ref) +{ + rtx flags, x; + + flags = gen_rtx_REG (cmp_mode, CC_REG); + x = gen_rtx_COMPARE (cmp_mode, XEXP (cmp_op, 0), XEXP (cmp_op, 1)); + x = gen_rtx_SET (VOIDmode, flags, x); + emit_insn (x); + + x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx); + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label_ref, pc_rtx); + x = gen_rtx_SET (VOIDmode, pc_rtx, x); + emit_jump_insn (x); +} + +/* A helper function for matching parallels that set the flags. */ + +bool +mn10300_match_ccmode (rtx insn, enum machine_mode cc_mode) +{ + rtx op1, flags; + enum machine_mode flags_mode; + + gcc_checking_assert (XVECLEN (PATTERN (insn), 0) == 2); + + op1 = XVECEXP (PATTERN (insn), 0, 1); + gcc_checking_assert (GET_CODE (SET_SRC (op1)) == COMPARE); + + flags = SET_DEST (op1); + flags_mode = GET_MODE (flags); + + if (GET_MODE (SET_SRC (op1)) != flags_mode) + return false; + if (GET_MODE_CLASS (flags_mode) != MODE_CC) + return false; + + /* Ensure that the mode of FLAGS is compatible with CC_MODE. */ + if (cc_flags_for_mode (flags_mode) & ~cc_flags_for_mode (cc_mode)) + return false; + + return true; +} + +int +mn10300_split_and_operand_count (rtx op) +{ + HOST_WIDE_INT val = INTVAL (op); + int count; + + if (val < 0) + { + /* High bit is set, look for bits clear at the bottom. */ + count = exact_log2 (-val); + if (count < 0) + return 0; + /* This is only size win if we can use the asl2 insn. Otherwise we + would be replacing 1 6-byte insn with 2 3-byte insns. */ + if (count > (optimize_insn_for_speed_p () ? 2 : 4)) + return 0; + return -count; + } + else + { + /* High bit is clear, look for bits set at the bottom. */ + count = exact_log2 (val + 1); + count = 32 - count; + /* Again, this is only a size win with asl2. */ + if (count > (optimize_insn_for_speed_p () ? 2 : 4)) + return 0; + return -count; + } +} /* Initialize the GCC target structure. */ diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index 43bad54..34ff2ae 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -600,7 +600,7 @@ do { \ /* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled. */ #define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X)) -#define SELECT_CC_MODE(OP, X, Y) mn10300_select_cc_mode (X) +#define SELECT_CC_MODE(OP, X, Y) mn10300_select_cc_mode (OP, X, Y) #define REVERSIBLE_CC_MODE(MODE) 0 /* Nonzero if access to memory by bytes or half words is no faster diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index 88743d6..965c6558 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -491,222 +491,95 @@ (const_int 13) (const_int 24)) ])] ) - ;; ---------------------------------------------------------------------- ;; ADD INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "addsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (plus:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,!*y,!r") + (plus:SI (match_operand:SI 1 "register_operand" "%0, 0, r") + (match_operand:SI 2 "nonmemory_operand" "ri, i, r"))) + (clobber (reg:CC CC_REG))] "" - "") - -(define_insn "*am33_addsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,a,x,a,dax,!*y,!dax") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,dax") - (match_operand:SI 2 "nonmemory_operand" "J,J,L,L,daxi,i,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* -{ - switch (which_alternative) - { - case 0: - case 1: - return \"inc %0\"; - case 2: - case 3: - return \"inc4 %0\"; - case 4: - case 5: - return \"add %2,%0\"; - case 6: - { - enum reg_class src1_class, src2_class, dst_class; - - src1_class = REGNO_REG_CLASS (true_regnum (operands[1])); - src2_class = REGNO_REG_CLASS (true_regnum (operands[2])); - dst_class = REGNO_REG_CLASS (true_regnum (operands[0])); - - /* I'm not sure if this can happen or not. Might as well be prepared - and generate the best possible code if it does happen. */ - if (true_regnum (operands[0]) == true_regnum (operands[1])) - return \"add %2,%0\"; - if (true_regnum (operands[0]) == true_regnum (operands[2])) - return \"add %1,%0\"; - - /* Catch cases where no extended register was used. These should be - handled just like the mn10300. */ - if (src1_class != EXTENDED_REGS - && src2_class != EXTENDED_REGS - && dst_class != EXTENDED_REGS) - { - /* We have to copy one of the sources into the destination, then - add the other source to the destination. - - Carefully select which source to copy to the destination; a - naive implementation will waste a byte when the source classes - are different and the destination is an address register. - Selecting the lowest cost register copy will optimize this - sequence. */ - if (REGNO_REG_CLASS (true_regnum (operands[1])) - == REGNO_REG_CLASS (true_regnum (operands[0]))) - return \"mov %1,%0\;add %2,%0\"; - return \"mov %2,%0\;add %1,%0\"; - } - - /* At least one register is an extended register. */ - - /* The three operand add instruction on the am33 is a win iff the - output register is an extended register, or if both source - registers are extended registers. */ - if (dst_class == EXTENDED_REGS - || src1_class == src2_class) - return \"add %2,%1,%0\"; - - /* It is better to copy one of the sources to the destination, then - perform a 2 address add. The destination in this case must be - an address or data register and one of the sources must be an - extended register and the remaining source must not be an extended - register. - - The best code for this case is to copy the extended reg to the - destination, then emit a two address add. */ - if (src1_class == EXTENDED_REGS) - return \"mov %1,%0\;add %2,%0\"; - return \"mov %2,%0\;add %1,%0\"; - } - default: - gcc_unreachable (); - } - }" - [(set_attr "timings" "11,11,11,11,11,11,22")] + { return mn10300_output_add (operands, false); } + [(set_attr "timings" "11,11,22")] ) -(define_insn "*mn10300_addsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,a,a,dax,!*y,!dax") - (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,dax") - (match_operand:SI 2 "nonmemory_operand" "J,J,L,daxi,i,dax"))) - (clobber (reg:CC CC_REG)) - ] - "" - "* -{ - switch (which_alternative) - { - case 0: - case 1: - return \"inc %0\"; - case 2: - return \"inc4 %0\"; - case 3: - case 4: - return \"add %2,%0\"; - case 5: - /* I'm not sure if this can happen or not. Might as well be prepared - and generate the best possible code if it does happen. */ - if (true_regnum (operands[0]) == true_regnum (operands[1])) - return \"add %2,%0\"; - if (true_regnum (operands[0]) == true_regnum (operands[2])) - return \"add %1,%0\"; - - /* We have to copy one of the sources into the destination, then add - the other source to the destination. - - Carefully select which source to copy to the destination; a naive - implementation will waste a byte when the source classes are different - and the destination is an address register. Selecting the lowest - cost register copy will optimize this sequence. */ - if (REGNO_REG_CLASS (true_regnum (operands[1])) - == REGNO_REG_CLASS (true_regnum (operands[0]))) - return \"mov %1,%0\;add %2,%0\"; - return \"mov %2,%0\;add %1,%0\"; - default: - gcc_unreachable (); - } -}" - [(set_attr "timings" "11,11,11,11,11,22")] +;; Note that ADD IMM,SP does not set the flags, so omit that here. +(define_insn "*addsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,!r") + (plus:SI (match_operand:SI 1 "register_operand" "%0, r") + (match_operand:SI 2 "nonmemory_operand" "ri, r"))) + (set (reg CC_REG) + (compare (plus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)" + { return mn10300_output_add (operands, true); } + [(set_attr "timings" "11,22")] ) ;; ---------------------------------------------------------------------- ;; SUBTRACT INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "subsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (minus:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "register_operand" " 0,r") + (match_operand:SI 2 "nonmemory_operand" "ri,r"))) + (clobber (reg:CC CC_REG))] "" - "") - -(define_insn "*am33_subsi3" - [(set (match_operand:SI 0 "register_operand" "=dax,!dax") - (minus:SI (match_operand:SI 1 "register_operand" "0,dax") - (match_operand:SI 2 "nonmemory_operand" "daxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* - { - if (true_regnum (operands[0]) == true_regnum (operands[1])) - return \"sub %2,%0\"; - else - { - enum reg_class src1_class, src2_class, dst_class; - - src1_class = REGNO_REG_CLASS (true_regnum (operands[1])); - src2_class = REGNO_REG_CLASS (true_regnum (operands[2])); - dst_class = REGNO_REG_CLASS (true_regnum (operands[0])); - - /* If no extended registers are used, then the best way to handle - this is to copy the first source operand into the destination - and emit a two address subtraction. */ - if (src1_class != EXTENDED_REGS - && src2_class != EXTENDED_REGS - && dst_class != EXTENDED_REGS - && true_regnum (operands[0]) != true_regnum (operands[2])) - return \"mov %1,%0\;sub %2,%0\"; - return \"sub %2,%1,%0\"; - } - }" - [(set_attr "timings" "11,22")] + "@ + sub %2,%0 + sub %2,%1,%0" + [(set_attr "isa" "*,am33") + (set_attr "timings" "11,22")] ) -(define_insn "*mn10300_subsi3" - [(set (match_operand:SI 0 "register_operand" "=dax") - (minus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "nonmemory_operand" "daxi"))) - (clobber (reg:CC CC_REG)) - ] - "" - "sub %2,%0" - [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") - (const_int 11) (const_int 22)))] +(define_insn "*subsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (minus:SI (match_operand:SI 1 "register_operand" " 0,r") + (match_operand:SI 2 "nonmemory_operand" "ri,r"))) + (set (reg CC_REG) + (compare (minus:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)" + "@ + sub %2,%0 + sub %2,%1,%0" + [(set_attr "isa" "*,am33") + (set_attr "timings" "11,22")] ) -(define_expand "negsi2" - [(set (match_operand:SI 0 "register_operand") - (neg:SI (match_operand:SI 1 "register_operand")))] +(define_insn_and_split "negsi2" + [(set (match_operand:SI 0 "register_operand" "=D,&r") + (neg:SI (match_operand:SI 1 "register_operand" " 0, r"))) + (clobber (reg:CC CC_REG))] "" - " + "#" + "&& reload_completed" + [(const_int 0)] { - rtx target = gen_reg_rtx (SImode); - - emit_move_insn (target, const0_rtx); - emit_insn (gen_subsi3 (target, target, operands[1])); - emit_move_insn (operands[0], target); + /* Recall that twos-compliment is ones-compliment plus one. When + allocated in DATA_REGS this is 2+1 bytes; otherwise (for am33) + this is 3+3 bytes. + + For AM33, it would have been possible to load zero and use the + three-address subtract to have a total size of 3+4*N bytes for + multiple negations, plus increased throughput. Not attempted here. */ + + if (true_regnum (operands[0]) == true_regnum (operands[1])) + { + emit_insn (gen_one_cmplsi2 (operands[0], operands[0])); + emit_insn (gen_addsi3 (operands[0], operands[0], const1_rtx)); + } + else + { + emit_move_insn (operands[0], const0_rtx); + emit_insn (gen_subsi3 (operands[0], operands[0], operands[1])); + } DONE; -}") +}) ;; ---------------------------------------------------------------------- ;; MULTIPLY INSTRUCTIONS @@ -896,221 +769,174 @@ ;; AND INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "andsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (and:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" " i,D,r"))) + (clobber (reg:CC CC_REG))] "" - "") - -(define_insn "*am33_andsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax") - (and:SI (match_operand:SI 1 "register_operand" "%0,0,dax") - (match_operand:SI 2 "nonmemory_operand" "N,dxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - { - if (CONST_INT_P (operands[2])) - switch (INTVAL (operands[2])) - { - case 0xff: return "extbu %0"; - case 0xffff: return "exthu %0"; - case 0x7fffffff: return "add %0, %0; lsr 1, %0"; - case 0x3fffffff: return "asl2 %0; lsr 2, %0"; - case 0x1fffffff: return "add %0, %0; asl2 %0; lsr 3, %0"; - case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0"; - case 0xfffffffe: return "lsr 1, %0; add %0, %0"; - case 0xfffffffc: return "lsr 2, %0; asl2 %0"; - case 0xfffffff8: return "lsr 3, %0; add %0, %0; asl2 %0"; - case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0"; - } - - if (REG_P (operands[2]) && REG_P (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[2]) - && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS) - return "mov %1, %0; and %2, %0"; - if (REG_P (operands[2]) && REG_P (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[2])) - return "and %1, %2, %0"; - if (REG_P (operands[2]) && REG_P (operands[0]) - && true_regnum (operands[2]) == true_regnum (operands[0])) - return "and %1, %0"; - - return "and %2, %0"; - } - [(set_attr "timings" "33")] + "@ + and %2,%0 + and %2,%0 + and %2,%1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr "timings" "22,11,11")] +) + +(define_insn "*andsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" " i,D,r"))) + (set (reg CC_REG) + (compare (and:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && mn10300_match_ccmode (insn, CCZNmode)" + "@ + and %2,%0 + and %2,%0 + and %2,%1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr "timings" "22,11,11")] ) -(define_insn "*mn10300_andsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,dx") - (and:SI (match_operand:SI 1 "register_operand" "%0,0") - (match_operand:SI 2 "nonmemory_operand" "N,dxi"))) - (clobber (reg:CC CC_REG)) - ] +;; Make sure we generate extensions instead of ANDs. + +(define_split + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "register_operand" "") + (const_int 255))) + (clobber (reg:CC CC_REG))])] "" - { - if (CONST_INT_P (operands[2])) - switch (INTVAL (operands[2])) - { - case 0xff: return "extbu %0"; - case 0xffff: return "exthu %0"; - case 0x7fffffff: return "add %0, %0; lsr 1, %0"; - case 0x3fffffff: return "asl2 %0; lsr 2, %0"; - case 0x1fffffff: return "add %0, %0; asl2 %0; lsr 3, %0"; - case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0"; - case 0xfffffffe: return "lsr 1, %0; add %0, %0"; - case 0xfffffffc: return "lsr 2, %0; asl2 %0"; - case 0xfffffff8: return "lsr 3, %0; add %0, %0; asl2 %0"; - case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0"; - } + [(set (match_dup 0) (zero_extend:SI (match_dup 1)))] + { operands[1] = gen_lowpart (QImode, operands[1]); } +) - return "and %2, %0"; - } - [(set_attr "timings" "33")] +(define_split + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_operand:SI 1 "register_operand" "") + (const_int 65535))) + (clobber (reg:CC CC_REG))])] + "" + [(set (match_dup 0) (zero_extend:SI (match_dup 1)))] + { operands[1] = gen_lowpart (HImode, operands[1]); } ) +;; Split AND by an appropriate constant into two shifts. Recall that +;; operations with a full 32-bit immediate require an extra cycle, so +;; this is a size optimization with no speed penalty. This only applies +;; do DATA_REGS; the shift insns that AM33 adds are too large for a win. + +(define_split + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (and:SI (match_dup 0) + (match_operand:SI 1 "const_int_operand" ""))) + (clobber (reg:CC CC_REG))])] + "reload_completed + && REGNO_DATA_P (true_regnum (operands[0]), 1) + && mn10300_split_and_operand_count (operands[1]) != 0" + [(const_int 0)] +{ + int count = mn10300_split_and_operand_count (operands[1]); + if (count > 0) + { + emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (count))); + emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (count))); + } + else + { + emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (-count))); + emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (-count))); + } + DONE; +}) + ;; ---------------------------------------------------------------------- ;; OR INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "iorsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (ior:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] - "" - "") - -(define_insn "*am33_iorsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,!dax") - (ior:SI (match_operand:SI 1 "register_operand" "%0,dax") - (match_operand:SI 2 "nonmemory_operand" "dxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* - { - if (REG_P (operands[2]) && REG_P (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[2]) - && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS) - return \"mov %1,%0\;or %2,%0\"; - if (REG_P (operands[2]) && REG_P (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[2])) - return \"or %1,%2,%0\"; - if (REG_P (operands[2]) && REG_P (operands[0]) - && true_regnum (operands[2]) == true_regnum (operands[0])) - return \"or %1,%0\"; - return \"or %2,%0\"; - }" - [(set_attr "timings" "22")] -) - -(define_insn "*mn10300_iorsi3" - [(set (match_operand:SI 0 "register_operand" "=dx") - (ior:SI (match_operand:SI 1 "register_operand" "%0") - (match_operand:SI 2 "nonmemory_operand" "dxi"))) - (clobber (reg:CC CC_REG)) - ] +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" " i,D,r"))) + (clobber (reg:CC CC_REG))] "" - "or %2,%0" - [(set_attr "timings" "33")] + "@ + or %2,%0 + or %2,%0 + or %2,%1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr "timings" "22,11,11")] +) + +(define_insn "*iorsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" " i,D,r"))) + (set (reg CC_REG) + (compare (ior:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && mn10300_match_ccmode (insn, CCZNmode)" + "@ + or %2,%0 + or %2,%0 + or %2,%1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr "timings" "22,11,11")] ) ;; ---------------------------------------------------------------------- ;; XOR INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "xorsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (xor:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] - "" - "") - -(define_insn "*am33_xorsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,!dax") - (xor:SI (match_operand:SI 1 "register_operand" "%0,dax") - (match_operand:SI 2 "nonmemory_operand" "dxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* - { - if (REG_P (operands[2]) && REG_P (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[2]) - && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS) - return \"mov %1,%0\;xor %2,%0\"; - if (REG_P (operands[2]) && REG_P (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[1]) - && true_regnum (operands[0]) != true_regnum (operands[2])) - return \"xor %1,%2,%0\"; - if (REG_P (operands[2]) && REG_P (operands[0]) - && true_regnum (operands[2]) == true_regnum (operands[0])) - return \"xor %1,%0\"; - return \"xor %2,%0\"; - }" - [(set_attr "timings" "22")] -) - -(define_insn "*mn10300_xorsi3" - [(set (match_operand:SI 0 "register_operand" "=dx") - (xor:SI (match_operand:SI 1 "register_operand" "%0") - (match_operand:SI 2 "nonmemory_operand" "dxi"))) - (clobber (reg:CC CC_REG)) - ] +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" " i,D,r"))) + (clobber (reg:CC CC_REG))] "" - "xor %2,%0" - [(set_attr "timings" "11")] + "@ + xor %2,%0 + xor %2,%0 + xor %2,%1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr "timings" "22,11,11")] +) + +(define_insn "*xorsi3_flags" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0,r") + (match_operand:SI 2 "nonmemory_operand" " i,D,r"))) + (set (reg CC_REG) + (compare (xor:SI (match_dup 1) (match_dup 2)) + (const_int 0)))] + "reload_completed && mn10300_match_ccmode (insn, CCZNmode)" + "@ + xor %2,%0 + xor %2,%0 + xor %2,%1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr "timings" "22,11,11")] ) ;; ---------------------------------------------------------------------- ;; NOT INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "one_cmplsi2" - [(parallel [(set (match_operand:SI 0 "register_operand") - (not:SI (match_operand:SI 1 "register_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=D") + (not:SI (match_operand:SI 1 "register_operand" " 0"))) + (clobber (reg:CC CC_REG))] "" - "") - -(define_insn "*am33_cmplsi2" - [(set (match_operand:SI 0 "register_operand" "=dx,!dax") - (not:SI (match_operand:SI 1 "register_operand" "0,0"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" "not %0" ) -(define_insn "*mn10300_cmplsi2" - [(set (match_operand:SI 0 "register_operand" "=dx") - (not:SI (match_operand:SI 1 "register_operand" "0"))) - (clobber (reg:CC CC_REG)) - ] - "" +(define_insn "*one_cmplsi2_flags" + [(set (match_operand:SI 0 "register_operand" "=D") + (not:SI (match_operand:SI 1 "register_operand" " 0"))) + (set (reg CC_REG) + (compare (not:SI (match_dup 1)) + (const_int 0)))] + "reload_completed && mn10300_match_ccmode (insn, CCZNmode)" "not %0" ) @@ -1126,140 +952,133 @@ (match_operator 0 "ordered_comparison_operator" [(match_operand:SI 1 "register_operand") (match_operand:SI 2 "nonmemory_operand")]) - (label_ref (match_operand 3 "")) + (label_ref (match_operand 3 "")) (pc)))] "" "" ) -(define_insn_and_split "*cbranchsi4_post_reload" +(define_insn_and_split "*cbranchsi4_cmp" [(set (pc) (if_then_else (match_operator 3 "ordered_comparison_operator" - [(match_operand:SI 0 "register_operand" "dax") - (match_operand:SI 1 "nonmemory_operand" "daxi")]) - (label_ref (match_operand 2 "" "")) - (pc))) - ] + [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "nonmemory_operand" "ri")]) + (match_operand 2 "label_ref_operand" "") + (pc)))] "" "#" "reload_completed" [(const_int 0)] - " - /* We construct the split by hand as otherwise the JUMP_LABEL - attribute is not set correctly on the jump insn. */ - emit_insn (gen_cmpsi (operands[0], operands[1])); - - emit_jump_insn (gen_integer_conditional_branch - (gen_rtx_fmt_ee (GET_CODE (operands[3]), - CCmode, - gen_rtx_REG (CCmode, CC_REG), - const0_rtx), - operands[2])); - " -) +{ + mn10300_split_cbranch (CCmode, operands[3], operands[2]); + DONE; +}) -;; Ordinarily, the cmp instruction will set the Z bit of cc0 to 1 if -;; its operands hold equal values, but the operands of a cmp -;; instruction must be distinct registers. In the case where we'd -;; like to compare a register to itself, we can achieve this effect -;; with a btst 0,d0 instead. (This will not alter the contents of d0 -;; but will have the proper effect on cc0. Using d0 is arbitrary; any -;; data register would work.) - -;; Even though the first alternative would be preferable if it can -;; possibly match, reload must not be given the opportunity to attempt -;; to use it. It assumes that such matches can only occur when one of -;; the operands is used for input and the other for output. Since -;; this is not the case, it abort()s. Indeed, such a reload cannot be -;; possibly satisfied, so just mark the alternative with a `!', so -;; that it is not considered by reload. - -(define_insn "cmpsi" - [(set (reg:CC CC_REG) - (compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax,dax") - (match_operand:SI 1 "nonmemory_operand" "*0,I,daxi")))] - "" - { - if (which_alternative == 0) - return \"btst 0,d0\"; - if (which_alternative == 1) - return mn10300_output_cmp (operands[0], insn); - return \"cmp %1,%0\"; - } +(define_insn "*cmpsi" + [(set (reg CC_REG) + (compare (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "nonmemory_operand" "ri")))] + "reload_completed" +{ + /* The operands of CMP must be distinct registers. In the case where + we've failed to optimize the comparison of a register to itself, we + must use another method to set the Z flag. We can achieve this + effect with a BTST 0,D0. This will not alter the contents of D0; + the use of d0 is arbitrary; any data register would work. */ + if (rtx_equal_p (operands[0], operands[1])) + return "btst 0,d0"; + else + return "cmp %1,%0"; +} [(set_attr_alternative "timings" - [(const_int 11) - (if_then_else (eq_attr "cpu" "am34") - (const_int 11) (const_int 22)) - (const_int 22) - ]) - ] + [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])] ) -(define_insn "integer_conditional_branch" +(define_insn "*integer_conditional_branch" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" - [(reg:CC CC_REG) (const_int 0)]) + [(match_operand 2 "int_mode_flags" "") + (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] - "" + "reload_completed" "b%b0 %1" ) +(define_insn_and_split "*cbranchsi4_btst" + [(set (pc) + (if_then_else + (match_operator 3 "CCZN_comparison_operator" + [(and:SI (match_operand:SI 0 "register_operand" "D") + (match_operand:SI 1 "immediate_operand" "i")) + (const_int 0)]) + (match_operand 2 "label_ref_operand" "") + (pc)))] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + mn10300_split_cbranch (CCZNmode, operands[3], operands[2]); + DONE; +}) + +(define_insn "*btstsi" + [(set (reg:CCZN CC_REG) + (compare:CCZN + (and:SI (match_operand:SI 0 "register_operand" "D") + (match_operand:SI 1 "immediate_operand" "i")) + (const_int 0)))] + "reload_completed" + "btst %1,%0" +) + (define_expand "cbranchsf4" [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" [(match_operand:SF 1 "register_operand") (match_operand:SF 2 "nonmemory_operand")]) - (label_ref (match_operand 3 "")) + (label_ref (match_operand 3 "")) (pc)))] "TARGET_AM33_2" "" ) -(define_insn_and_split "*cbranchsf4_post_reload" +(define_insn_and_split "*cbranchsf4_cmp" [(set (pc) (if_then_else (match_operator 3 "ordered_comparison_operator" [(match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "nonmemory_operand" "fF")]) - (label_ref (match_operand 2 "" "")) + (match_operand 2 "label_ref_operand" "") (pc))) ] "TARGET_AM33_2" "#" "&& reload_completed" [(const_int 0)] - " - /* We construct the split by hand as otherwise the JUMP_LABEL - attribute is not set correctly on the jump insn. */ - emit_insn (gen_am33_cmpsf (operands[0], operands[1])); - - emit_jump_insn (gen_float_conditional_branch - (gen_rtx_fmt_ee (GET_CODE (operands[3]), - CC_FLOATmode, - gen_rtx_REG (CC_FLOATmode, CC_REG), - const0_rtx), - operands[2])); - " -) +{ + mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]); + DONE; +}) -(define_insn "am33_cmpsf" +(define_insn "*am33_cmpsf" [(set (reg:CC_FLOAT CC_REG) (compare:CC_FLOAT (match_operand:SF 0 "register_operand" "f") (match_operand:SF 1 "nonmemory_operand" "fF")))] - "TARGET_AM33_2" + "TARGET_AM33_2 && reload_completed" "fcmp %1, %0" [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 17) (const_int 25)))] ) -(define_insn "float_conditional_branch" +(define_insn "*float_conditional_branch" [(set (pc) (if_then_else (match_operator 0 "comparison_operator" [(reg:CC_FLOAT CC_REG) (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] - "TARGET_AM33_2" + "TARGET_AM33_2 && reload_completed" "fb%b0 %1" [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 33)))] @@ -1301,7 +1120,6 @@ (match_operand:SI 2 "immediate_operand") (match_operand 3 "" "") (match_operand 4 "")] "" - " { rtx table = gen_reg_rtx (SImode); rtx index = gen_reg_rtx (SImode); @@ -1321,7 +1139,7 @@ emit_jump_insn (gen_tablejump (addr, operands[3])); DONE; -}") +}) (define_insn "tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "a")) @@ -1431,7 +1249,6 @@ (match_operand 1 "") (match_operand 2 "")])] "" - " { int i; @@ -1443,7 +1260,7 @@ emit_move_insn (SET_DEST (set), SET_SRC (set)); } DONE; -}") +}) (define_insn "nop" [(const_int 0)] @@ -1455,328 +1272,109 @@ ;; EXTEND INSTRUCTIONS ;; ---------------------------------------------------------------------- -(define_expand "zero_extendqisi2" - [(set (match_operand:SI 0 "register_operand") +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") (zero_extend:SI - (match_operand:QI 1 "nonimmediate_operand")))] + (match_operand:QI 1 "nonimmediate_operand" " 0,m,r")))] "" - "") - -(define_insn "*zero_extendqisi2_am33" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax") - (zero_extend:SI - (match_operand:QI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))] - "TARGET_AM33" "@ - extbu %0 - mov %1,%0\;extbu %0 - movbu %1,%0 - extbu %0 - mov %1,%0\;extbu %0 - movbu %1,%0" - [(set_attr_alternative "timings" - [(const_int 11) - (const_int 22) - (if_then_else (eq_attr "cpu" "am34") - (const_int 13) (const_int 24)) - (const_int 11) - (const_int 22) - (if_then_else (eq_attr "cpu" "am34") - (const_int 13) (const_int 24)) - ]) - ] -) - -(define_insn "*zero_extendqisi2_mn10300" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx") - (zero_extend:SI - (match_operand:QI 1 "nonimmediate_operand" "0,d,m")))] - "" - "@ - extbu %0 - mov %1,%0\;extbu %0 - movbu %1,%0" - [(set_attr_alternative "timings" - [(const_int 11) - (const_int 22) - (if_then_else (eq_attr "cpu" "am34") - (const_int 13) (const_int 24)) - ]) - ] -) - -(define_expand "zero_extendhisi2" - [(set (match_operand:SI 0 "register_operand") - (zero_extend:SI - (match_operand:HI 1 "nonimmediate_operand")))] - "" - "") - -(define_insn "*zero_extendhisi2_am33" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax") - (zero_extend:SI - (match_operand:HI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))] - "TARGET_AM33" - "@ - exthu %0 - mov %1,%0\;exthu %0 - movhu %1,%0 - exthu %0 - mov %1,%0\;exthu %0 - movhu %1,%0" - [(set_attr_alternative "timings" - [(const_int 11) - (const_int 22) - (if_then_else (eq_attr "cpu" "am34") - (const_int 13) (const_int 24)) - (const_int 11) - (const_int 22) - (if_then_else (eq_attr "cpu" "am34") - (const_int 13) (const_int 24)) - ]) - ] + extbu %0 + movbu %1,%0 + extbu %1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr_alternative "timings" + [(const_int 11) + (if_then_else (eq_attr "cpu" "am34") + (const_int 13) (const_int 24)) + (const_int 11) + ])] ) -(define_insn "*zero_extendhisi2_mn10300" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx") +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=D,D,r") (zero_extend:SI - (match_operand:HI 1 "nonimmediate_operand" "0,dx,m")))] + (match_operand:HI 1 "nonimmediate_operand" " 0,m,r")))] "" "@ - exthu %0 - mov %1,%0\;exthu %0 - movhu %1,%0" - [(set_attr_alternative "timings" - [(const_int 11) - (const_int 22) - (if_then_else (eq_attr "cpu" "am34") - (const_int 13) (const_int 24)) - ]) - ] -) - -;;- sign extension instructions - -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "register_operand") - (sign_extend:SI - (match_operand:QI 1 "register_operand")))] - "" - "") - -(define_insn "*extendqisi2_am33" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax") - (sign_extend:SI - (match_operand:QI 1 "register_operand" "0,dx,0,dax")))] - "TARGET_AM33" - "@ - extb %0 - mov %1,%0\;extb %0 - extb %0 - mov %1,%0\;extb %0" - [(set_attr "timings" "11,22,11,22")] -) - -(define_insn "*extendqisi2_mn10300" - [(set (match_operand:SI 0 "register_operand" "=dx,dx") - (sign_extend:SI - (match_operand:QI 1 "register_operand" "0,dx")))] - "" - "@ - extb %0 - mov %1,%0\;extb %0" - [(set_attr "timings" "11,22")] + exthu %0 + movhu %1,%0 + exthu %1,%0" + [(set_attr "isa" "*,*,am33") + (set_attr_alternative "timings" + [(const_int 11) + (if_then_else (eq_attr "cpu" "am34") + (const_int 13) (const_int 24)) + (const_int 11)])] ) -(define_expand "extendhisi2" - [(set (match_operand:SI 0 "register_operand") +(define_insn "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=D,r") (sign_extend:SI - (match_operand:HI 1 "register_operand")))] + (match_operand:QI 1 "register_operand" "0,r")))] "" - "") - -(define_insn "*extendhisi2_am33" - [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax") - (sign_extend:SI - (match_operand:HI 1 "register_operand" "0,dax,0,dax")))] - "TARGET_AM33" "@ - exth %0 - mov %1,%0\;exth %0 - exth %0 - mov %1,%0\;exth %0" - [(set_attr "timings" "11,22,11,22")] + extb %0 + extb %1,%0" + [(set_attr "isa" "*,am33")] ) -(define_insn "*extendhisi2_mn10300" - [(set (match_operand:SI 0 "register_operand" "=dx,dx") +(define_insn "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=D,r") (sign_extend:SI - (match_operand:HI 1 "register_operand" "0,dx")))] + (match_operand:HI 1 "register_operand" "0,r")))] "" "@ - exth %0 - mov %1,%0\;exth %0" - [(set_attr "timings" "11,22")] + exth %0 + exth %1,%0" + [(set_attr "isa" "*,am33")] ) ;; ---------------------------------------------------------------------- ;; SHIFTS ;; ---------------------------------------------------------------------- -(define_expand "ashlsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (ashift:SI - (match_operand:SI 1 "register_operand") - (match_operand:QI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] - "" - "") - -(define_insn "*am33_ashlsi3" - [(set (match_operand:SI 0 "register_operand" "=dax,dx,!dax") +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,D,d,d, D,r") (ashift:SI - (match_operand:SI 1 "register_operand" "0,0,dax") - (match_operand:QI 2 "nonmemory_operand" "J,dxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* - { - if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 1) - return \"add %0,%0\"; - - if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 2) - return \"asl2 %0\"; - - if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 3 - && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS) - return \"asl2 %0\;add %0,%0\"; - - if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 4 - && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS) - return \"asl2 %0\;asl2 %0\"; - - if (true_regnum (operands[1]) == true_regnum (operands[0])) - return \"asl %S2,%0\"; - - if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS - && true_regnum (operands[0]) != true_regnum (operands[2])) - return \"mov %1,%0\;asl %S2,%0\"; - return \"asl %2,%1,%0\"; - }" - [(set_attr "timings" "22")] -) - -(define_insn "*mn10300_ashlsi3" - [(set (match_operand:SI 0 "register_operand" "=dax,dx,dx,dx,dx") - (ashift:SI - (match_operand:SI 1 "register_operand" "0,0,0,0,0") - (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,dxi"))) - (clobber (reg:CC CC_REG)) - ] + (match_operand:SI 1 "register_operand" " 0,0,0,0, 0,r") + (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,Di,r"))) + (clobber (reg:CC CC_REG))] "" "@ - add %0,%0 - asl2 %0 - asl2 %0\;add %0,%0 - asl2 %0\;asl2 %0 - asl %S2,%0" - [(set_attr "timings" "11,11,22,22,11")] -) - -(define_expand "lshrsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (lshiftrt:SI - (match_operand:SI 1 "register_operand") - (match_operand:QI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] - "" - "") - -(define_insn "*am33_lshrsi3" - [(set (match_operand:SI 0 "register_operand" "=dx,!dax") + add %0,%0 + asl2 %0 + asl2 %0\;add %0,%0 + asl2 %0\;asl2 %0 + asl %S2,%0 + asl %2,%1,%0" + [(set_attr "isa" "*,*,*,*,*,am33") + (set_attr "timings" "11,11,22,22,11,11")] +) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=D,r") (lshiftrt:SI - (match_operand:SI 1 "register_operand" "0,dax") - (match_operand:QI 2 "nonmemory_operand" "dxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* - { - if (true_regnum (operands[1]) == true_regnum (operands[0])) - return \"lsr %S2,%0\"; - - if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS - && true_regnum (operands[0]) != true_regnum (operands[2])) - return \"mov %1,%0\;lsr %S2,%0\"; - return \"lsr %2,%1,%0\"; - }" - [(set_attr "timings" "22")] -) - -(define_insn "*mn10300_lshrsi3" - [(set (match_operand:SI 0 "register_operand" "=dx") - (lshiftrt:SI - (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "dxi"))) - (clobber (reg:CC CC_REG)) - ] - "" - "lsr %S2,%0" - [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") - (const_int 11) (const_int 22)))] -) - -(define_expand "ashrsi3" - [(parallel [(set (match_operand:SI 0 "register_operand") - (ashiftrt:SI - (match_operand:SI 1 "register_operand") - (match_operand:QI 2 "nonmemory_operand"))) - (clobber (reg:CC CC_REG)) - ]) - ] + (match_operand:SI 1 "register_operand" " 0,r") + (match_operand:QI 2 "nonmemory_operand" "Di,r"))) + (clobber (reg:CC CC_REG))] "" - "") - -(define_insn "*am33_ashrisi3" - [(set (match_operand:SI 0 "register_operand" "=dx,!dax") - (ashiftrt:SI - (match_operand:SI 1 "register_operand" "0,dax") - (match_operand:QI 2 "nonmemory_operand" "dxi,dax"))) - (clobber (reg:CC CC_REG)) - ] - "TARGET_AM33" - "* - { - if (true_regnum (operands[1]) == true_regnum (operands[0])) - return \"asr %S2,%0\"; - - if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS - && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS - && true_regnum (operands[0]) != true_regnum (operands[2])) - return \"mov %1,%0\;asr %S2,%0\"; - return \"asr %2,%1,%0\"; - }" - [(set_attr "timings" "22")] + "@ + lsr %S2,%0 + lsr %2,%1,%0" + [(set_attr "isa" "*,am33")] ) -(define_insn "*mn10300_ashrsi3" - [(set (match_operand:SI 0 "register_operand" "=dx") +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=D,r") (ashiftrt:SI - (match_operand:SI 1 "register_operand" "0") - (match_operand:QI 2 "nonmemory_operand" "dxi"))) - (clobber (reg:CC CC_REG)) - ] + (match_operand:SI 1 "register_operand" " 0,r") + (match_operand:QI 2 "nonmemory_operand" "Di,r"))) + (clobber (reg:CC CC_REG))] "" - "asr %S2,%0" - [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") - (const_int 11) (const_int 22)))] + "@ + asr %S2,%0 + asr %2,%1,%0" + [(set_attr "isa" "*,am33")] ) ;; ---------------------------------------------------------------------- @@ -2031,28 +1629,6 @@ [(set_attr "timings" "66")] ) -;; Try to combine consecutive updates of the stack pointer (or any -;; other register for that matter). -(define_peephole - [(parallel [(set (match_operand:SI 0 "register_operand" "=dxay") - (plus:SI (match_dup 0) - (match_operand 1 "const_int_operand" ""))) - (clobber (reg:CC CC_REG)) - ]) - (parallel [(set (match_dup 0) - (plus:SI (match_dup 0) - (match_operand 2 "const_int_operand" ""))) - (clobber (reg:CC CC_REG)) - ]) - ] - "" - "* -{ - operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1])); - return \"add %1,%0\"; -}" -) - (define_expand "int_label" [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)] "" "") diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md index df1b1f4..4badebb 100644 --- a/gcc/config/mn10300/predicates.md +++ b/gcc/config/mn10300/predicates.md @@ -42,3 +42,19 @@ return XEXP (op, 0) == stack_pointer_rtx || XEXP (op, 1) == stack_pointer_rtx; }) + +(define_predicate "label_ref_operand" + (match_code "label_ref")) + +(define_special_predicate "int_mode_flags" + (match_code "reg") +{ + if (REGNO (op) != CC_REG) + return false; + if (GET_MODE (op) == CC_FLOATmode) + return false; + return GET_MODE_CLASS (GET_MODE (op)) == MODE_CC; +}) + +(define_predicate "CCZN_comparison_operator" + (match_code "eq,ne,lt,ge"))