* config/mn10300/mn10300.opt (mliw): New command line option.
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 8 Feb 2011 09:55:07 +0000 (09:55 +0000)
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 8 Feb 2011 09:55:07 +0000 (09:55 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@169916 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mn10300/mn10300.c
gcc/config/mn10300/mn10300.h
gcc/config/mn10300/mn10300.md
gcc/config/mn10300/mn10300.opt
gcc/doc/invoke.texi

index a239eca..3fd6d02 100644 (file)
@@ -1,3 +1,36 @@
+2011-02-08  Nick Clifton  <nickc@redhat.com>
+
+       * 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.
+
 2011-02-07  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        * config.gcc (hppa[12]*-*-hpux11*): Don't set extra_parts.
index 6b68166..5ff8852 100644 (file)
@@ -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");
 }
 \f
+/* 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)
     }
 }
 \f
+/* 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 ();
+    }
+}
+\f
 /* 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
index b10f450..2e97ca4 100644 (file)
         }                                      \
       else if (TARGET_AM33)                    \
         builtin_define ("__AM33__=1");         \
+                                               \
+      builtin_define (TARGET_ALLOW_LIW ?       \
+                     "__LIW__" : "__NO_LIW__");\
+                                               \
     }                                          \
   while (0)
 
index 57606e4..e8d2ae1 100644 (file)
@@ -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")
 (define_mode_iterator INT [QI HI SI])
 
 \f
+;; 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");
+\f
 ;; ----------------------------------------------------------------------
 ;; Pipeline description.
 ;; ----------------------------------------------------------------------
     }
 }
   [(set_attr "isa" "*,*,*,*,*,*,*,am33,*,*")
+   (set_attr "liw" "*,*,either,*,*,*,*,*,*,*")
+   (set_attr "liw_op" "mov")
    (set_attr_alternative "timings"
         [(const_int 11)
          (const_int 22)
 ;; ----------------------------------------------------------------------
 
 (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.
 ;; ----------------------------------------------------------------------
 
 (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)))]
    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")]
 )
 
    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")]
 )
 
    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")]
 )
 
 
 (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
     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"
 ;; ----------------------------------------------------------------------
 
 (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))]
   ""
   "@
    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")]
 )
 
 ;; ----------------------------------------------------------------------
 }
   [(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)))]
+)
index f2a434e..4275103 100644 (file)
@@ -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
index 92320b0..a916e4e 100644 (file)
@@ -739,7 +739,7 @@ Objective-C and Objective-C++ Dialects}.
 -mno-am33 -mam33 -mam33-2 -mam34 @gol
 -mtune=@var{cpu-type} @gol
 -mreturn-pointer-on-d0 @gol
--mno-crt0  -mrelax}
+-mno-crt0  -mrelax -mliw}
 
 @emph{PDP-11 Options}
 @gccoptlist{-mfpu  -msoft-float  -mac0  -mno-ac0  -m40  -m45  -m10 @gol
@@ -15035,6 +15035,19 @@ to shorten branches, calls and absolute memory addresses.  This option only
 has an effect when used on the command line for the final link step.
 
 This option makes symbolic debugging impossible.
+
+@item -mliw
+@opindex mliw
+Allow the compiler to generate @emph{Long Instruction Word}
+instructions if the target is the @samp{AM33} or later.  This is the
+default.  This option defines the preprocessor macro @samp{__LIW__}.
+
+@item -mnoliw
+@opindex mnoliw
+Do not allow the compiler to generate @emph{Long Instruction Word}
+instructions.  This option defines the preprocessor macro
+@samp{__NO_LIW__}.
+
 @end table
 
 @node PDP-11 Options