aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/mn10300
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2011-02-08 09:55:07 +0000
committerNick Clifton <nickc@gcc.gnu.org>2011-02-08 09:55:07 +0000
commit298362c83f1e4250dc2598fa11e8f6a3bacd6153 (patch)
tree1c0fb74b651b2e76acaebbf1cdc8a355f3ea96c6 /gcc/config/mn10300
parent30c4a23d026c9f3fb6d2f688b294d41c07ecbc51 (diff)
downloadgcc-298362c83f1e4250dc2598fa11e8f6a3bacd6153.zip
gcc-298362c83f1e4250dc2598fa11e8f6a3bacd6153.tar.gz
gcc-298362c83f1e4250dc2598fa11e8f6a3bacd6153.tar.bz2
mn10300.opt (mliw): New command line option.
* config/mn10300/mn10300.opt (mliw): New command line option. * config/mn10300/mn10300.md (UNSPEC_LIW): New unspec. (liw_bundling): New automaton. (liw): New attribute. (liw_op): New attribute. (liw_op1, liw_op2, liw_both, liw_either): New reservations. (movsi_internal): Add LIW attributes. (andsi3): Likewise. (iorsi3): Likewise. (xorsi3): Likewise. (addsi3): Separate register and immediate alternatives. Add LIW attributes. (subsi3): Likewise. (cmpsi): Likewise. (aslsi3): Likewise. (lshrsi3): Likewise. (ashrsi3): Likewise. (liw): New pattern. * config/mn10300/mn10300.c (liw_op_names): New (mn10300_print_operand): Handle 'W' operand descriptor. (extract_bundle): New function. (check_liw_constraints): New function. (liw_candidate): New function. (mn10300_bundle_liw): New function. (mn10300_reorg): New function. (TARGET_MACHINE_DEPENDENT_REORG): Define. (TARGET_DEFAULT_TARGET_FLAGS): Add MASK_ALLOW_LIW. * config/mn10300/mn10300.h (TARGET_CPU_CPP_BUILTINS): Define __LIW__ or __NO_LIW__. * doc/invoke.texi: Describe the -mliw command line option. From-SVN: r169916
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r--gcc/config/mn10300/mn10300.c705
-rw-r--r--gcc/config/mn10300/mn10300.h4
-rw-r--r--gcc/config/mn10300/mn10300.md174
-rw-r--r--gcc/config/mn10300/mn10300.opt6
4 files changed, 601 insertions, 288 deletions
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 6b68166..5ff8852 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -1,6 +1,6 @@
/* Subroutines for insn-output.c for Matsushita MN10300 series
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
This file is part of GCC.
@@ -165,6 +165,16 @@ mn10300_file_start (void)
fprintf (asm_out_file, "\t.am33\n");
}
+/* Note: This list must match the liw_op attribute in mn10300.md. */
+
+static const char *liw_op_names[] =
+{
+ "add", "cmp", "sub", "mov",
+ "and", "or", "xor",
+ "asr", "lsr", "asl",
+ "none", "max"
+};
+
/* Print operand X using operand code CODE to assembly language output file
FILE. */
@@ -173,309 +183,319 @@ mn10300_print_operand (FILE *file, rtx x, int code)
{
switch (code)
{
- case 'b':
- case 'B':
- {
- 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 ();
- }
+ case 'W':
+ {
+ unsigned int liw_op = UINTVAL (x);
- gcc_checking_assert ((cc_flags_for_code (cmp) & ~have_flags) == 0);
- fputs (str, file);
- }
+ gcc_assert (TARGET_ALLOW_LIW);
+ gcc_assert (liw_op < LIW_OP_MAX);
+ fputs (liw_op_names[liw_op], 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
- the operand normally. */
- if (REG_P (x))
- {
- fputc ('(', file);
- mn10300_print_operand (file, x, 0);
- fputc (')', file);
- }
- else
- mn10300_print_operand (file, x, 0);
- break;
+ case 'b':
+ case 'B':
+ {
+ 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);
- case 'D':
- switch (GET_CODE (x))
+ switch (cmp)
{
- case MEM:
- fputc ('(', file);
- output_address (XEXP (x, 0));
- fputc (')', file);
+ case NE:
+ str = "ne";
break;
-
- case REG:
- fprintf (file, "fd%d", REGNO (x) - 18);
+ 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 ();
}
- break;
+
+ 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
+ the operand normally. */
+ if (REG_P (x))
+ {
+ fputc ('(', file);
+ mn10300_print_operand (file, x, 0);
+ fputc (')', file);
+ }
+ else
+ mn10300_print_operand (file, x, 0);
+ break;
+
+ case 'D':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
+
+ case REG:
+ fprintf (file, "fd%d", REGNO (x) - 18);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ break;
/* These are the least significant word in a 64bit value. */
- case 'L':
- switch (GET_CODE (x))
- {
- case MEM:
- fputc ('(', file);
- output_address (XEXP (x, 0));
- fputc (')', file);
- break;
+ case 'L':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
- case REG:
- fprintf (file, "%s", reg_names[REGNO (x)]);
- break;
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ break;
- case SUBREG:
- fprintf (file, "%s", reg_names[subreg_regno (x)]);
- break;
+ case SUBREG:
+ fprintf (file, "%s", reg_names[subreg_regno (x)]);
+ break;
- case CONST_DOUBLE:
- {
- long val[2];
- REAL_VALUE_TYPE rv;
+ case CONST_DOUBLE:
+ {
+ long val[2];
+ REAL_VALUE_TYPE rv;
- switch (GET_MODE (x))
- {
- case DFmode:
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
- fprintf (file, "0x%lx", val[0]);
- break;;
- case SFmode:
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]);
- fprintf (file, "0x%lx", val[0]);
- break;;
- case VOIDmode:
- case DImode:
- mn10300_print_operand_address (file,
- GEN_INT (CONST_DOUBLE_LOW (x)));
- break;
- default:
- break;
- }
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
+ fprintf (file, "0x%lx", val[0]);
+ break;;
+ case SFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val[0]);
+ fprintf (file, "0x%lx", val[0]);
+ break;;
+ case VOIDmode:
+ case DImode:
+ mn10300_print_operand_address (file,
+ GEN_INT (CONST_DOUBLE_LOW (x)));
+ break;
+ default:
break;
}
+ break;
+ }
- case CONST_INT:
- {
- rtx low, high;
- split_double (x, &low, &high);
- fprintf (file, "%ld", (long)INTVAL (low));
- break;
+ case CONST_INT:
+ {
+ rtx low, high;
+ split_double (x, &low, &high);
+ fprintf (file, "%ld", (long)INTVAL (low));
+ break;
}
- default:
- gcc_unreachable ();
- }
- break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
/* Similarly, but for the most significant word. */
- case 'H':
- switch (GET_CODE (x))
- {
- case MEM:
- fputc ('(', file);
- x = adjust_address (x, SImode, 4);
- output_address (XEXP (x, 0));
- fputc (')', file);
- break;
+ case 'H':
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ x = adjust_address (x, SImode, 4);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
- case REG:
- fprintf (file, "%s", reg_names[REGNO (x) + 1]);
- break;
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+ break;
- case SUBREG:
- fprintf (file, "%s", reg_names[subreg_regno (x) + 1]);
- break;
+ case SUBREG:
+ fprintf (file, "%s", reg_names[subreg_regno (x) + 1]);
+ break;
- case CONST_DOUBLE:
- {
- long val[2];
- REAL_VALUE_TYPE rv;
+ case CONST_DOUBLE:
+ {
+ long val[2];
+ REAL_VALUE_TYPE rv;
- switch (GET_MODE (x))
- {
- case DFmode:
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
- fprintf (file, "0x%lx", val[1]);
- break;;
- case SFmode:
- gcc_unreachable ();
- case VOIDmode:
- case DImode:
- mn10300_print_operand_address (file,
- GEN_INT (CONST_DOUBLE_HIGH (x)));
- break;
- default:
- break;
- }
+ switch (GET_MODE (x))
+ {
+ case DFmode:
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
+ fprintf (file, "0x%lx", val[1]);
+ break;;
+ case SFmode:
+ gcc_unreachable ();
+ case VOIDmode:
+ case DImode:
+ mn10300_print_operand_address (file,
+ GEN_INT (CONST_DOUBLE_HIGH (x)));
+ break;
+ default:
break;
}
+ break;
+ }
- case CONST_INT:
- {
- rtx low, high;
- split_double (x, &low, &high);
- fprintf (file, "%ld", (long)INTVAL (high));
- break;
- }
-
- default:
- gcc_unreachable ();
+ case CONST_INT:
+ {
+ rtx low, high;
+ split_double (x, &low, &high);
+ fprintf (file, "%ld", (long)INTVAL (high));
+ break;
}
- break;
- case 'A':
- fputc ('(', file);
- if (REG_P (XEXP (x, 0)))
- output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx));
- else
- output_address (XEXP (x, 0));
- fputc (')', file);
- break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
- case 'N':
- gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
- fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff));
- break;
+ case 'A':
+ fputc ('(', file);
+ if (REG_P (XEXP (x, 0)))
+ output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx));
+ else
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
- case 'U':
- gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
- fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
- break;
+ case 'N':
+ gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
+ fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff));
+ break;
+
+ case 'U':
+ gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
+ fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
+ break;
/* For shift counts. The hardware ignores the upper bits of
any immediate, but the assembler will flag an out of range
shift count as an error. So we mask off the high bits
of the immediate here. */
- case 'S':
- if (CONST_INT_P (x))
- {
- fprintf (file, "%d", (int)(INTVAL (x) & 0x1f));
- break;
- }
- /* FALL THROUGH */
+ case 'S':
+ if (CONST_INT_P (x))
+ {
+ fprintf (file, "%d", (int)(INTVAL (x) & 0x1f));
+ break;
+ }
+ /* FALL THROUGH */
- default:
- switch (GET_CODE (x))
- {
- case MEM:
- fputc ('(', file);
- output_address (XEXP (x, 0));
- fputc (')', file);
- break;
+ default:
+ switch (GET_CODE (x))
+ {
+ case MEM:
+ fputc ('(', file);
+ output_address (XEXP (x, 0));
+ fputc (')', file);
+ break;
- case PLUS:
- output_address (x);
- break;
+ case PLUS:
+ output_address (x);
+ break;
- case REG:
- fprintf (file, "%s", reg_names[REGNO (x)]);
- break;
+ case REG:
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ break;
- case SUBREG:
- fprintf (file, "%s", reg_names[subreg_regno (x)]);
- break;
+ case SUBREG:
+ fprintf (file, "%s", reg_names[subreg_regno (x)]);
+ break;
/* This will only be single precision.... */
- case CONST_DOUBLE:
- {
- unsigned long val;
- REAL_VALUE_TYPE rv;
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
- REAL_VALUE_TO_TARGET_SINGLE (rv, val);
- fprintf (file, "0x%lx", val);
- break;
- }
+ case CONST_DOUBLE:
+ {
+ unsigned long val;
+ REAL_VALUE_TYPE rv;
- case CONST_INT:
- case SYMBOL_REF:
- case CONST:
- case LABEL_REF:
- case CODE_LABEL:
- case UNSPEC:
- mn10300_print_operand_address (file, x);
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+ REAL_VALUE_TO_TARGET_SINGLE (rv, val);
+ fprintf (file, "0x%lx", val);
break;
- default:
- gcc_unreachable ();
}
- break;
- }
+
+ case CONST_INT:
+ case SYMBOL_REF:
+ case CONST:
+ case LABEL_REF:
+ case CODE_LABEL:
+ case UNSPEC:
+ mn10300_print_operand_address (file, x);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ }
}
/* Output assembly language output for the address ADDR to FILE. */
@@ -1694,7 +1714,7 @@ mn10300_output_add (rtx operands[3], bool need_flags)
dest_class = REGNO_REG_CLASS (dest_regnum);
src1_class = REGNO_REG_CLASS (src1_regnum);
- if (GET_CODE (src2) == CONST_INT)
+ if (CONST_INT_P (src2))
{
gcc_assert (dest_regnum == src1_regnum);
@@ -2925,8 +2945,177 @@ mn10300_split_and_operand_count (rtx op)
}
}
+/* Extract operands and (if requested) the LIW op type from the insn.
+ Returns false if the insn can't be bundled. */
+
+static bool
+extract_bundle (rtx insn, rtx * ops, enum attr_liw_op * plop)
+{
+ enum attr_liw_op lop;
+ rtx p, s;
+
+ p = single_set (insn);
+ s = SET_SRC (p);
+ lop = get_attr_liw_op (insn);
+ if (plop != NULL)
+ * plop = lop;
+
+ switch (lop)
+ {
+ case LIW_OP_MOV:
+ ops[0] = SET_DEST (p);
+ ops[1] = SET_SRC (p);
+ break;
+ case LIW_OP_CMP:
+ ops[0] = XEXP (SET_SRC (p), 0);
+ ops[1] = XEXP (SET_SRC (p), 1);
+ break;
+ case LIW_OP_NONE:
+ return false;
+ default:
+ ops[0] = SET_DEST (p);
+ ops[1] = XEXP (SET_SRC (p), 1);
+ break;
+ }
+
+ return REG_P (ops[0]) && REG_P (ops[1]);
+}
+
+/* Look for conflicts in the operands used in
+ the potential bundling of the two insns. */
+
+static bool
+check_liw_constraints (rtx ops[4],
+ enum attr_liw_op op1,
+ enum attr_liw_op op2,
+ bool swapped)
+{
+ /* Look for the two destination registers being the same. This is OK if
+ the first op is a comparison op, since it will compare the value prior
+ to the completion of the second op. */
+ if (REGNO (ops[0]) == REGNO (ops[2])
+ && ( (! swapped && op1 != LIW_OP_CMP)
+ || (swapped && op2 != LIW_OP_CMP)))
+ return false;
+
+ /* Look for the source of the second op being the destination of the first op.
+ Nomrally this will prevent the bundling since GCC has generated sequential
+ operations and the LIW opcodes are executed in parallel. But if the first
+ opcode is a MOV, we can copy its source to the second ops source. */
+ if (swapped)
+ return REGNO (ops[1]) != REGNO (ops[2]);
+
+ if (REGNO (ops[3]) == REGNO (ops[0]))
+ {
+ if (op1 == LIW_OP_MOV)
+ {
+ ops[3] = ops[1];
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/* Decide if the given insn is a candidate for LIW bundling. For now we just
+ check that the insn has an LIW attribute. Later on we check operand
+ constraints and such. */
+
+static bool
+liw_candidate (rtx insn)
+{
+ return insn != NULL_RTX
+ && single_set (insn) != NULL_RTX
+ && get_attr_liw (insn) != LIW_BOTH;
+}
+
+/* Combine pairs of insns into LIW bundles. */
+
+static void
+mn10300_bundle_liw (void)
+{
+ rtx r;
+
+ for (r = get_insns (); r != NULL_RTX; r = next_nonnote_nondebug_insn (r))
+ {
+ rtx insn1, insn2, ops[4];
+ enum attr_liw liw1, liw2;
+ enum attr_liw_op op1, op2;
+ bool swapped = false;
+
+ insn1 = r;
+ if (! liw_candidate (insn1))
+ continue;
+
+ insn2 = next_nonnote_nondebug_insn (insn1);
+ if (! liw_candidate (insn2))
+ continue;
+
+ liw1 = get_attr_liw (insn1);
+ if (liw1 == LIW_BOTH)
+ continue;
+ liw2 = get_attr_liw (insn2);
+ if (liw2 == LIW_BOTH)
+ continue;
+ if (liw2 == liw1 && liw1 != LIW_EITHER)
+ continue;
+
+ /* The scheduler always groups the insns correctly, but not
+ always in sequence. So, we can do a naive check and expect
+ it to work. */
+ if (liw1 == LIW_OP2 || liw2 == LIW_OP1)
+ {
+ rtx r;
+ enum attr_liw lt;
+
+ r = insn1;
+ insn1 = insn2;
+ insn2 = r;
+ lt = liw1;
+ liw1 = liw2;
+ liw2 = lt;
+ swapped = true;
+ }
+
+ if (! extract_bundle (insn1, ops, & op1))
+ continue;
+ if (! extract_bundle (insn2, ops + 2, & op2))
+ continue;
+ if (! check_liw_constraints (ops, op1, op2, swapped))
+ continue;
+
+ delete_insn (insn2);
+
+ if (op1 == LIW_OP_CMP)
+ insn2 = gen_cmp_liw (ops[2], ops[3], ops[0], ops[1], GEN_INT (op2));
+ else if (op2 == LIW_OP_CMP)
+ insn2 = gen_liw_cmp (ops[0], ops[1], ops[2], ops[3], GEN_INT (op1));
+ else
+ insn2 = gen_liw (ops[0], ops[2], ops[1], ops[3],
+ GEN_INT (op1), GEN_INT (op2));
+
+ insn2 = emit_insn_after (insn2, insn1);
+ delete_insn (insn1);
+ r = insn2;
+ }
+}
+
+static void
+mn10300_reorg (void)
+{
+ if (TARGET_AM33)
+ {
+ if (TARGET_ALLOW_LIW)
+ mn10300_bundle_liw ();
+ }
+}
+
/* Initialize the GCC target structure. */
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg
+
#undef TARGET_EXCEPT_UNWIND_INFO
#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
@@ -2954,7 +3143,7 @@ mn10300_split_and_operand_count (rtx op)
#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra
#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION mn10300_handle_option
#undef TARGET_OPTION_OVERRIDE
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index b10f450..2e97ca4 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -50,6 +50,10 @@
} \
else if (TARGET_AM33) \
builtin_define ("__AM33__=1"); \
+ \
+ builtin_define (TARGET_ALLOW_LIW ? \
+ "__LIW__" : "__NO_LIW__");\
+ \
} \
while (0)
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 57606e4..e8d2ae1 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -1,6 +1,6 @@
;; GCC machine description for Matsushita MN10300
;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010
+;; 2005, 2006, 2007, 2008, 2009, 2010, 2011
;; Free Software Foundation, Inc.
;; Contributed by Jeff Law (law@cygnus.com).
@@ -39,6 +39,9 @@
(UNSPEC_EXT 6)
(UNSPEC_BSCH 7)
+
+ ;; This is used to encode LIW patterns.
+ (UNSPEC_LIW 8)
])
(include "predicates.md")
@@ -75,6 +78,43 @@
(define_mode_iterator INT [QI HI SI])
+;; Bundling of smaller insns into a long instruction word (LIW)
+(define_automaton "liw_bundling")
+(automata_option "ndfa")
+
+(define_cpu_unit "liw_op1_u,liw_op2_u" "liw_bundling")
+
+(define_attr "liw" "op1,op2,both,either"
+ (const_string "both"))
+;; Note: this list must match the one defined for liw_op_names[].
+(define_attr "liw_op" "add,cmp,sub,mov,and,or,xor,asr,lsr,asl,none,max"
+ (const_string "none"))
+
+(define_insn_reservation "liw_op1" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "op1"))
+ "liw_op1_u");
+(define_insn_reservation "liw_op2" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "op2"))
+ "liw_op2_u");
+(define_insn_reservation "liw_both" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "both"))
+ "liw_op1_u + liw_op2_u");
+(define_insn_reservation "liw_either" 1
+ (and (ior (eq_attr "cpu" "am33")
+ (eq_attr "cpu" "am33_2")
+ (eq_attr "cpu" "am34"))
+ (eq_attr "liw" "either"))
+ "liw_op1_u | liw_op2_u");
+
;; ----------------------------------------------------------------------
;; Pipeline description.
;; ----------------------------------------------------------------------
@@ -417,6 +457,8 @@
}
}
[(set_attr "isa" "*,*,*,*,*,*,*,am33,*,*")
+ (set_attr "liw" "*,*,either,*,*,*,*,*,*,*")
+ (set_attr "liw_op" "mov")
(set_attr_alternative "timings"
[(const_int 11)
(const_int 22)
@@ -521,13 +563,15 @@
;; ----------------------------------------------------------------------
(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")))
+ [(set (match_operand:SI 0 "register_operand" "=r,r,!*y,!r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0, 0, r")
+ (match_operand:SI 2 "nonmemory_operand" "r,i, i, r")))
(clobber (reg:CC CC_REG))]
""
{ return mn10300_output_add (operands, false); }
- [(set_attr "timings" "11,11,22")]
+ [(set_attr "timings" "11,11,11,22")
+ (set_attr "liw" "either,*,*,*")
+ (set_attr "liw_op" "add")]
)
;; Note that ADD IMM,SP does not set the flags, so omit that here.
@@ -714,22 +758,25 @@
;; ----------------------------------------------------------------------
(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")))
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0,r")
+ (match_operand:SI 2 "nonmemory_operand" "r,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
sub %2,%0
+ sub %2,%0
sub %2,%1,%0"
- [(set_attr "isa" "*,am33")
- (set_attr "timings" "11,22")]
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "either,*,*")
+ (set_attr "liw_op" "sub")
+ (set_attr "timings" "11,11,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 (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)))]
@@ -1125,6 +1172,8 @@
and %2,%0
and %2,%1,%0"
[(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "and")
(set_attr "timings" "22,11,11")]
)
@@ -1210,6 +1259,8 @@
or %2,%0
or %2,%1,%0"
[(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "or")
(set_attr "timings" "22,11,11")]
)
@@ -1244,6 +1295,8 @@
xor %2,%0
xor %2,%1,%0"
[(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "*,op1,*")
+ (set_attr "liw_op" "xor")
(set_attr "timings" "22,11,11")]
)
@@ -1321,8 +1374,8 @@
(define_insn "*cmpsi"
[(set (reg CC_REG)
- (compare (match_operand:SI 0 "register_operand" "r")
- (match_operand:SI 1 "nonmemory_operand" "ri")))]
+ (compare (match_operand:SI 0 "register_operand" "r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,i")))]
"reload_completed"
{
/* The operands of CMP must be distinct registers. In the case where
@@ -1336,7 +1389,10 @@
return "cmp %1,%0";
}
[(set_attr_alternative "timings"
- [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])]
+ [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))
+ (if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])
+ (set_attr "liw" "either,*")
+ (set_attr "liw_op" "cmp")]
)
(define_insn "*integer_conditional_branch"
@@ -1676,10 +1732,10 @@
;; ----------------------------------------------------------------------
(define_insn "ashlsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,D,d,d, D,r")
+ [(set (match_operand:SI 0 "register_operand" "=r,D,d,d,D,D,r")
(ashift:SI
- (match_operand:SI 1 "register_operand" " 0,0,0,0, 0,r")
- (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,Di,r")))
+ (match_operand:SI 1 "register_operand" " 0,0,0,0,0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,D,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
@@ -1688,35 +1744,44 @@
asl2 %0\;add %0,%0
asl2 %0\;asl2 %0
asl %S2,%0
+ asl %S2,%0
asl %2,%1,%0"
- [(set_attr "isa" "*,*,*,*,*,am33")
- (set_attr "timings" "11,11,22,22,11,11")]
+ [(set_attr "isa" "*,*,*,*,*,*,am33")
+ (set_attr "liw" "*,*,*,*,op2,*,*")
+ (set_attr "liw_op" "asl")
+ (set_attr "timings" "11,11,22,22,11,11,11")]
)
(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "register_operand" "=D,r")
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
(lshiftrt:SI
- (match_operand:SI 1 "register_operand" " 0,r")
- (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+ (match_operand:SI 1 "register_operand" "0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
lsr %S2,%0
+ lsr %S2,%0
lsr %2,%1,%0"
- [(set_attr "isa" "*,am33")]
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "op2,*,*")
+ (set_attr "liw_op" "lsr")]
)
(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "register_operand" "=D,r")
+ [(set (match_operand:SI 0 "register_operand" "=D,D,r")
(ashiftrt:SI
- (match_operand:SI 1 "register_operand" " 0,r")
- (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+ (match_operand:SI 1 "register_operand" "0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "D,i,r")))
(clobber (reg:CC CC_REG))]
""
"@
asr %S2,%0
+ asr %S2,%0
asr %2,%1,%0"
- [(set_attr "isa" "*,am33")]
+ [(set_attr "isa" "*,*,am33")
+ (set_attr "liw" "op2,*,*")
+ (set_attr "liw_op" "asr")]
)
;; ----------------------------------------------------------------------
@@ -2029,3 +2094,54 @@
}
[(set_attr "timings" "66")]
)
+
+;; The mode on operand 3 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "liw"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))
+ (set (match_operand:SI 1 "register_operand" "=r")
+ (unspec:SI [(match_dup 1)
+ (match_operand 3 "register_operand" "r")
+ (match_operand:SI 5 "const_int_operand" "")]
+ UNSPEC_LIW))]
+ "TARGET_ALLOW_LIW"
+ "%W4_%W5 %2, %0, %3, %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+;; The mode on operand 1 has been deliberately omitted because it
+;; can be either SI (for arithmetic operations) or QI (for shifts).
+(define_insn "cmp_liw"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand 1 "register_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))]
+ "TARGET_ALLOW_LIW"
+ "cmp_%W4 %2, %3, %0, %1"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
+
+(define_insn "liw_cmp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_dup 0)
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "")]
+ UNSPEC_LIW))
+ (set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")))]
+ "TARGET_ALLOW_LIW"
+ "%W4_cmp %0, %1, %2, %3"
+ [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+ (const_int 13) (const_int 12)))]
+)
diff --git a/gcc/config/mn10300/mn10300.opt b/gcc/config/mn10300/mn10300.opt
index f2a434e..4275103 100644
--- a/gcc/config/mn10300/mn10300.opt
+++ b/gcc/config/mn10300/mn10300.opt
@@ -1,6 +1,6 @@
; Options for the Matsushita MN10300 port of the compiler.
-; Copyright (C) 2005, 2007, 2010 Free Software Foundation, Inc.
+; Copyright (C) 2005, 2007, 2010, 2011 Free Software Foundation, Inc.
;
; This file is part of GCC.
;
@@ -46,3 +46,7 @@ Enable linker relaxations
mreturn-pointer-on-d0
Target Report Mask(PTR_A0D0)
Return pointers in both a0 and d0
+
+mliw
+Target Report Mask(ALLOW_LIW)
+Allow gcc to generate LIW instructions