mn10300.opt (mliw): New command line option.
authorNick Clifton <nickc@redhat.com>
Tue, 8 Feb 2011 09:55:07 +0000 (09:55 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Tue, 8 Feb 2011 09:55:07 +0000 (09:55 +0000)
* 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

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 a239eca2a041334660bdcecab8bff36aee0547e6..3fd6d0225bd55591fe7cbb91ab92d70b72e9cda2 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 6b68166059c5789172ec17f1240bed3d3e433a40..5ff8852c5f7314fdd002823855802fddf0394b75 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 b10f45068059a89084be8e0db6866301b1d550a5..2e97ca4ff4c426942db2e1b5dcdebb763cf1369d 100644 (file)
         }                                      \
       else if (TARGET_AM33)                    \
         builtin_define ("__AM33__=1");         \
+                                               \
+      builtin_define (TARGET_ALLOW_LIW ?       \
+                     "__LIW__" : "__NO_LIW__");\
+                                               \
     }                                          \
   while (0)
 
index 57606e492af13e69c306f38a414f094e20998761..e8d2ae1194dc829821558e53e436f3b14074536d 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 f2a434ef7382ca6cada97dc44c2b499084ce66e8..427510304b2f340cecd16050a4f25a3949ed53a8 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 92320b0159aa65faee71a262f8e51c0214473af8..a916e4ea141afc6e48f3d2573e23420b4dc5719c 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