Add support for Cirrus EP9312, an ARM variant.
authorNick Clifton <nickc@redhat.com>
Mon, 10 Feb 2003 11:45:26 +0000 (11:45 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Mon, 10 Feb 2003 11:45:26 +0000 (11:45 +0000)
From-SVN: r62625

gcc/ChangeLog
gcc/config.gcc
gcc/config/arm/aout.h
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/t-arm-elf
gcc/doc/invoke.texi

index 4b08a6310b1b1f441dfe1dca0502dfcdae714002..7bd777971a86d25c6723cbe6a344d3fac36acd67 100644 (file)
@@ -1,3 +1,18 @@
+2003-02-10  Nick Clifton  <nickc@redhat.com>
+
+       * Contributed support for the Cirrus EP9312 "Maverick"
+       floating point co-processor.  Written by Aldy Hernandez
+       <aldyh@redhat.com>. 
+       (config/arm/arm.c): Add Cirrus support.
+       (config/arm/arm.h): Likewise.
+       (config/arm/aout.h): Likewise.
+       (config/arm/arm.md): Likewise.
+       (config/arm/arm-protos.h): Likewise.
+       (config.gcc): Likewise.
+       (doc/invoke.texi): Describe new -mcpu value and new
+       -mcirrus-fix-invalid-insns switch,
+       (cirrus.md): New file.
+
 Mon Feb 10 11:40:18 CET 2003  Jan Hubicka  <jh@suse.cz>
 
        * combine.c (combine_simplify_rtx): Simplify using
index 2b8d0b506f79af5382e81049e63ee213cdff1d8b..b76fbd8326fe1f67c84843e757f84ebeb742bfd8 100644 (file)
@@ -259,6 +259,9 @@ strongarm*-*-*)
 arm*-*-*)
        cpu_type=arm
        ;;
+ep9312*-*-*)
+       cpu_type=arm
+       ;;
 xscale-*-*)
        cpu_type=arm
        ;;
@@ -700,7 +703,7 @@ arm*-*-rtems*)
          thread_file='rtems'
        fi
        ;;
-arm*-*-elf)
+arm*-*-elf | ep9312-*-elf)
        tm_file="dbxelf.h elfos.h arm/unknown-elf.h arm/elf.h arm/aout.h arm/arm.h"
        tmake_file=arm/t-arm-elf
        ;;
@@ -2789,6 +2792,7 @@ arm*-*-*)
                | xarm7m | xarm7dm | xarm7dmi | xarm[79]tdmi \
                | xarm7100 | xarm7500 | xarm7500fe | xarm810 \
                | xxscale \
+               | xep9312 \
                | xstrongarm | xstrongarm110 | xstrongarm1100)
                        target_cpu_default2="TARGET_CPU_$with_cpu"
                        ;;
@@ -2806,6 +2810,11 @@ arm*-*-*)
                        fi
                        ;;
        esac
+       case $machine in
+               9ep9312-*-*)
+                       target_cpu_default2="TARGET_CPU_9ep9312"
+                       ;;
+       esac
        ;;
 
 hppa*-*-* | parisc*-*-*)
index a142ae11944f87ed8786f8ff9a16e792ccc59025..6d6e908951b3c791b5eacbe31915d142088d2219 100644 (file)
@@ -73,7 +73,10 @@ Boston, MA 02111-1307, USA.  */
   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",  \
   "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc",  \
   "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",  \
-  "cc", "sfp", "afp"                              \
+  "cc", "sfp", "afp",                             \
+  "mv0",  "mv1",   "mv2",  "mv3",  "mv4",   "mv5", \
+  "mv6",  "mv7",   "mv8",  "mv9",  "mv10",  "mv11",\
+  "mv12", "mv13",  "mv14", "mv15"                 \
 }
 #endif
 
@@ -98,7 +101,71 @@ Boston, MA 02111-1307, USA.  */
   {"r12", 12}, /* ip */                        \
   {"r13", 13}, /* sp */                        \
   {"r14", 14}, /* lr */                        \
-  {"r15", 15}  /* pc */                        \
+  {"r15", 15}, /* pc */                        \
+  {"mvf0", 27},                                        \
+  {"mvf1", 28},                                        \
+  {"mvf2", 29},                                        \
+  {"mvf3", 30},                                        \
+  {"mvf4", 31},                                        \
+  {"mvf5", 32},                                        \
+  {"mvf6", 33},                                        \
+  {"mvf7", 34},                                        \
+  {"mvf8", 35},                                        \
+  {"mvf9", 36},                                        \
+  {"mvf10", 37},                               \
+  {"mvf11", 38},                               \
+  {"mvf12", 39},                               \
+  {"mvf13", 40},                               \
+  {"mvf14", 41},                               \
+  {"mvf15", 42},                               \
+  {"mvd0", 27},                                        \
+  {"mvd1", 28},                                        \
+  {"mvd2", 29},                                        \
+  {"mvd3", 30},                                        \
+  {"mvd4", 31},                                        \
+  {"mvd5", 32},                                        \
+  {"mvd6", 33},                                        \
+  {"mvd7", 34},                                        \
+  {"mvd8", 35},                                        \
+  {"mvd9", 36},                                        \
+  {"mvd10", 37},                               \
+  {"mvd11", 38},                               \
+  {"mvd12", 39},                               \
+  {"mvd13", 40},                               \
+  {"mvd14", 41},                               \
+  {"mvd15", 42},                               \
+  {"mvfx0", 27},                               \
+  {"mvfx1", 28},                               \
+  {"mvfx2", 29},                               \
+  {"mvfx3", 30},                               \
+  {"mvfx4", 31},                               \
+  {"mvfx5", 32},                               \
+  {"mvfx6", 33},                               \
+  {"mvfx7", 34},                               \
+  {"mvfx8", 35},                               \
+  {"mvfx9", 36},                               \
+  {"mvfx10", 37},                              \
+  {"mvfx11", 38},                              \
+  {"mvfx12", 39},                              \
+  {"mvfx13", 40},                              \
+  {"mvfx14", 41},                              \
+  {"mvfx15", 42},                              \
+  {"mvdx0", 27},                               \
+  {"mvdx1", 28},                               \
+  {"mvdx2", 29},                               \
+  {"mvdx3", 30},                               \
+  {"mvdx4", 31},                               \
+  {"mvdx5", 32},                               \
+  {"mvdx6", 33},                               \
+  {"mvdx7", 34},                               \
+  {"mvdx8", 35},                               \
+  {"mvdx9", 36},                               \
+  {"mvdx10", 37},                              \
+  {"mvdx11", 38},                              \
+  {"mvdx12", 39},                              \
+  {"mvdx13", 40},                              \
+  {"mvdx14", 41},                              \
+  {"mvdx15", 42}                               \
 }
 #endif
 
index 8923dd02452e4c00db6d09fbf3a9d63aaa57a44f..0d0dba22a6cdf57e411306543aa7a0acec97909e 100644 (file)
@@ -94,6 +94,11 @@ extern int    logical_binary_operator        PARAMS ((rtx, enum machine_mode));
 extern int    multi_register_push      PARAMS ((rtx, enum machine_mode));
 extern int    load_multiple_operation  PARAMS ((rtx, enum machine_mode));
 extern int    store_multiple_operation PARAMS ((rtx, enum machine_mode));
+extern int    cirrus_fp_register       PARAMS ((rtx, enum machine_mode));
+extern int    cirrus_general_operand   PARAMS ((rtx, enum machine_mode));
+extern int    cirrus_register_operand  PARAMS ((rtx, enum machine_mode));
+extern int    cirrus_shift_const       PARAMS ((rtx, enum machine_mode));
+extern int    cirrus_memory_offset     PARAMS ((rtx));
 
 extern int    symbol_mentioned_p       PARAMS ((rtx));
 extern int    label_mentioned_p                PARAMS ((rtx));
@@ -149,7 +154,6 @@ extern rtx    arm_va_arg                PARAMS ((tree, tree));
 extern int    arm_function_arg_pass_by_reference PARAMS ((CUMULATIVE_ARGS *,
                                                         enum machine_mode,
                                                         tree, int));
-
 #endif
 
 #if defined AOF_ASSEMBLER 
index e59f461fbeaf07d188edff4bca9fdeb4e52c5c85..c1a6f2f740673f31843a1236479efe46844bc184 100644 (file)
@@ -62,6 +62,12 @@ typedef struct minipool_fixup   Mfix;
 #define Ulong    unsigned long
 #define Ccstar   const char *
 
+const char extra_reg_names1[][16] =
+{ "mv0", "mv1", "mv2",  "mv3",  "mv4",  "mv5",  "mv6",  "mv7",
+  "mv8", "mv9", "mv10", "mv11", "mv12", "mv13", "mv14", "mv15"
+};
+#define extra_reg_names1 bogus1_regnames
+
 const struct attribute_spec arm_attribute_table[];
 
 /* Forward function declarations.  */
@@ -144,6 +150,9 @@ static int arm_rtx_costs_1                  PARAMS ((rtx, enum rtx_code,
                                                         enum rtx_code));
 static bool arm_rtx_costs                      PARAMS ((rtx, int, int, int*));
 static int arm_address_cost                    PARAMS ((rtx));
+static int      is_load_address                PARAMS ((rtx));
+static int       is_cirrus_insn                 PARAMS ((rtx));
+static void      cirrus_reorg                   PARAMS ((rtx));
 
 #undef Hint
 #undef Mmode
@@ -263,6 +272,7 @@ int    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
 #define FL_STRONG     (1 << 8)       /* StrongARM */
 #define FL_ARCH5E     (1 << 9)        /* DSP extensions to v5 */
 #define FL_XSCALE     (1 << 10)              /* XScale */
+#define FL_CIRRUS     (1 << 11)              /* Cirrus/DSP.  */
 
 /* The bits in this mask specify which
    instructions we are allowed to generate.  */
@@ -301,6 +311,9 @@ int arm_is_xscale = 0;
 /* Nonzero if this chip is an ARM6 or an ARM7.  */
 int arm_is_6_or_7 = 0;
 
+/* Nonzero if this chip is a Cirrus/DSP.  */
+int arm_is_cirrus = 0;
+
 /* Nonzero if generating Thumb instructions.  */
 int thumb_code = 0;
 
@@ -391,6 +404,7 @@ static const struct processors all_cores[] =
   {"arm940t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
   {"arm9tdmi",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
   {"arm9e",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
+  {"ep9312",                            FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED |             FL_CIRRUS },
   {"strongarm",                     FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm110",           FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm1100",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
@@ -417,6 +431,7 @@ static const struct processors all_architectures[] =
   { "armv5",     FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
   { "armv5t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
   { "armv5te",   FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
+  { "ep9312",                            FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
   { NULL, 0 }
 };
 
@@ -514,6 +529,7 @@ arm_override_options ()
        { TARGET_CPU_arm9,      "arm9" },
        { TARGET_CPU_strongarm, "strongarm" },
        { TARGET_CPU_xscale,    "xscale" },
+       { TARGET_CPU_ep9312,    "ep9312" },
        { TARGET_CPU_generic,   "arm" },
        { 0, 0 }
       };
@@ -712,13 +728,23 @@ arm_override_options ()
   thumb_code       = (TARGET_ARM == 0);
   arm_is_6_or_7     = (((tune_flags & (FL_MODE26 | FL_MODE32))
                       && !(tune_flags & FL_ARCH4))) != 0;
+  arm_is_cirrus            = (tune_flags & FL_CIRRUS) != 0;
 
-  /* Default value for floating point code... if no co-processor
-     bus, then schedule for emulated floating point.  Otherwise,
-     assume the user has an FPA.
-     Note: this does not prevent use of floating point instructions,
-     -msoft-float does that.  */
-  arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
+  if (arm_is_cirrus)
+    {
+      arm_fpu = FP_CIRRUS;
+
+      /* Ignore -mhard-float if -mcpu=ep9312.  */
+      if (TARGET_HARD_FLOAT)
+       target_flags ^= ARM_FLAG_SOFT_FLOAT;
+    }
+  else
+    /* Default value for floating point code... if no co-processor
+       bus, then schedule for emulated floating point.  Otherwise,
+       assume the user has an FPA.
+       Note: this does not prevent use of floating point instructions,
+       -msoft-float does that.  */
+    arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
   
   if (target_fp_name)
     {
@@ -733,8 +759,15 @@ arm_override_options ()
   else
     arm_fpu_arch = FP_DEFAULT;
   
-  if (TARGET_FPE && arm_fpu != FP_HARD)
+  if (TARGET_FPE)
+    {
+      if (arm_fpu == FP_SOFT3)
+       arm_fpu = FP_SOFT2;
+      else if (arm_fpu == FP_CIRRUS)
+       warning ("-mpfpe switch not supported by ep9312 target cpu - ignored.");
+      else if (arm_fpu != FP_HARD)
     arm_fpu = FP_SOFT2;
+    }
   
   /* For arm2/3 there is no need to do any scheduling if there is only
      a floating point emulator, or we are doing software floating-point.  */
@@ -1902,6 +1935,8 @@ arm_return_in_memory (type)
 int
 arm_float_words_big_endian ()
 {
+  if (TARGET_CIRRUS)
+    return 0;
 
   /* For FPA, float words are always big-endian.  For VFP, floats words
      follow the memory system mode.  */
@@ -2688,6 +2723,12 @@ arm_legitimate_index_p (mode, index, strict_p)
            && INTVAL (index) > -1024
            && (INTVAL (index) & 3) == 0);
 
+  if (TARGET_CIRRUS
+      && (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode))
+    return (code == CONST_INT
+           && INTVAL (index) < 255
+           && INTVAL (index) > -255);
+
   if (arm_address_register_rtx_p (index, strict_p)
       && GET_MODE_SIZE (mode) <= 4)
     return 1;
@@ -3856,6 +3897,262 @@ fpu_add_operand (op, mode)
   return FALSE;
 }
 
+/* Return nonzero if OP is a valid Cirrus memory address pattern.  */
+
+int
+cirrus_memory_offset (op)
+     rtx op;
+{
+  /* Reject eliminable registers.  */
+  if (! (reload_in_progress || reload_completed)
+      && (   reg_mentioned_p (frame_pointer_rtx, op)
+         || reg_mentioned_p (arg_pointer_rtx, op)
+         || reg_mentioned_p (virtual_incoming_args_rtx, op)
+         || reg_mentioned_p (virtual_outgoing_args_rtx, op)
+         || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
+         || reg_mentioned_p (virtual_stack_vars_rtx, op)))
+    return 0;
+
+  if (GET_CODE (op) == MEM)
+    {
+      rtx ind;
+
+      ind = XEXP (op, 0);
+
+      /* Match: (mem (reg)).  */
+      if (GET_CODE (ind) == REG)
+       return 1;
+
+      /* Match:
+        (mem (plus (reg)
+                   (const))).  */
+      if (GET_CODE (ind) == PLUS
+         && GET_CODE (XEXP (ind, 0)) == REG
+         && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
+         && GET_CODE (XEXP (ind, 1)) == CONST_INT)
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Return nonzero if OP is a Cirrus or general register.  */
+
+int
+cirrus_register_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  return (GET_CODE (op) == REG
+         && (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
+             || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
+}
+
+/* Return nonzero if OP is a cirrus FP register.  */
+
+int
+cirrus_fp_register (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  return (GET_CODE (op) == REG
+         && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+             || REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
+}
+
+/* Return nonzero if OP is a 6bit constant (0..63).  */
+
+int
+cirrus_shift_const (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return (GET_CODE (op) == CONST_INT
+         && INTVAL (op) >= 0
+         && INTVAL (op) < 64);
+}
+
+/* Return nonzero if INSN is an LDR R0,ADDR instruction.  */
+
+static int
+is_load_address (insn)
+     rtx insn;
+{
+  rtx body, lhs, rhs;;
+
+  if (!insn)
+    return 0;
+
+  if (GET_CODE (insn) != INSN)
+    return 0;
+
+  body = PATTERN (insn);
+
+  if (GET_CODE (body) != SET)
+    return 0;
+
+  lhs = XEXP (body, 0);
+  rhs = XEXP (body, 1);
+
+  return (GET_CODE (lhs) == REG
+         && REGNO_REG_CLASS (REGNO (lhs)) == GENERAL_REGS
+         && (GET_CODE (rhs) == MEM
+             || GET_CODE (rhs) == SYMBOL_REF));
+}
+
+/* Return nonzero if INSN is a Cirrus instruction.  */
+
+static int
+is_cirrus_insn (insn)
+     rtx insn;
+{
+  enum attr_cirrus attr;
+
+  /* get_attr aborts on USE and CLOBBER.  */
+  if (!insn
+      || GET_CODE (insn) != INSN
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return 0;
+
+  attr = get_attr_cirrus (insn);
+
+  return attr != CIRRUS_NO;
+}
+
+/* Cirrus reorg for invalid instruction combinations.  */
+
+static void
+cirrus_reorg (first)
+     rtx first;
+{
+  enum attr_cirrus attr;
+  rtx body = PATTERN (first);
+  rtx t;
+  int nops;
+
+  /* Any branch must be followed by 2 non Cirrus instructions.  */
+  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
+    {
+      nops = 0;
+      t = next_nonnote_insn (first);
+
+      if (is_cirrus_insn (t))
+       ++ nops;
+
+      if (is_cirrus_insn (next_nonnote_insn (t)))
+       ++ nops;
+
+      while (nops --)
+       emit_insn_after (gen_nop (), first);
+
+      return;
+    }
+
+  /* (float (blah)) is in parallel with a clobber.  */
+  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
+    body = XVECEXP (body, 0, 0);
+
+  if (GET_CODE (body) == SET)
+    {
+      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
+
+      /* cfldrd, cfldr64, cfstrd, cfstr64 must
+        be followed by a non Cirrus insn.  */
+      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
+       {
+         if (is_cirrus_insn (next_nonnote_insn (first)))
+           emit_insn_after (gen_nop (), first);
+
+         return;
+       }
+      else if (is_load_address (first))
+       {
+         unsigned int arm_regno;
+
+         /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
+            ldr/cfmv64hr combination where the Rd field is the same
+            in both instructions must be split with a non Cirrus
+            insn.  Example:
+
+            ldr r0, blah
+            nop
+            cfmvsr mvf0, r0.  */
+
+         /* Get Arm register number for ldr insn.  */
+         if (GET_CODE (lhs) == REG)
+           arm_regno = REGNO (lhs);
+         else if (GET_CODE (rhs) == REG)
+           arm_regno = REGNO (rhs);
+         else
+           abort ();
+
+         /* Next insn.  */
+         first = next_nonnote_insn (first);
+
+         if (!is_cirrus_insn (first))
+           return;
+
+         body = PATTERN (first);
+
+          /* (float (blah)) is in parallel with a clobber.  */
+          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
+           body = XVECEXP (body, 0, 0);
+
+         if (GET_CODE (body) == FLOAT)
+           body = XEXP (body, 0);
+
+         if (get_attr_cirrus (first) == CIRRUS_MOVE
+             && GET_CODE (XEXP (body, 1)) == REG
+             && arm_regno == REGNO (XEXP (body, 1)))
+           emit_insn_after (gen_nop (), first);
+
+         return;
+       }
+    }
+
+  /* get_attr aborts on USE and CLOBBER.  */
+  if (!first
+      || GET_CODE (first) != INSN
+      || GET_CODE (PATTERN (first)) == USE
+      || GET_CODE (PATTERN (first)) == CLOBBER)
+    return;
+
+  attr = get_attr_cirrus (first);
+
+  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
+     must be followed by a non-coprocessor instruction.  */
+  if (attr == CIRRUS_COMPARE)
+    {
+      nops = 0;
+
+      t = next_nonnote_insn (first);
+
+      if (is_cirrus_insn (t))
+       ++ nops;
+
+      if (is_cirrus_insn (next_nonnote_insn (t)))
+       ++ nops;
+
+      while (nops --)
+       emit_insn_after (gen_nop (), first);
+
+      return;
+    }
+}
+
 /* Return nonzero if OP is a constant power of two.  */
 
 int
@@ -5355,6 +5652,8 @@ arm_select_cc_mode (op, x, y)
        case LE:
        case GT:
        case GE:
+         if (TARGET_CIRRUS)
+           return CCFPmode;
          return CCFPEmode;
 
        default:
@@ -6678,6 +6977,12 @@ arm_reorg (first)
   /* Scan all the insns and record the operands that will need fixing.  */
   for (insn = next_nonnote_insn (first); insn; insn = next_nonnote_insn (insn))
     {
+      if (TARGET_CIRRUS_FIX_INVALID_INSNS
+          && (is_cirrus_insn (insn)
+             || GET_CODE (insn) == JUMP_INSN
+             || is_load_address (insn)))
+       cirrus_reorg (insn);
+
       if (GET_CODE (insn) == BARRIER)
        push_minipool_barrier (insn, address);
       else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
@@ -9168,6 +9473,16 @@ arm_print_operand (stream, x, code)
       fprintf (stream, "%s", arithmetic_instr (x, 1));
       return;
 
+    /* Truncate Cirrus shift counts.  */
+    case 's':
+      if (GET_CODE (x) == CONST_INT)
+       {
+         fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
+         return;
+       }
+      arm_print_operand (stream, x, 0);
+      return;
+
     case 'I':
       fprintf (stream, "%s", arithmetic_instr (x, 0));
       return;
@@ -9274,6 +9589,43 @@ arm_print_operand (stream, x, code)
        fputs (thumb_condition_code (x, 1), stream);
       return;
 
+
+    /* Cirrus registers can be accessed in a variety of ways:
+         single floating point (f)
+        double floating point (d)
+        32bit integer         (fx)
+        64bit integer         (dx).  */
+    case 'W':                  /* Cirrus register in F mode.  */
+    case 'X':                  /* Cirrus register in D mode.  */
+    case 'Y':                  /* Cirrus register in FX mode.  */
+    case 'Z':                  /* Cirrus register in DX mode.  */
+      if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
+       abort ();
+
+      fprintf (stream, "mv%s%s",
+              code == 'W' ? "f"
+              : code == 'X' ? "d"
+              : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
+
+      return;
+
+    /* Print cirrus register in the mode specified by the register's mode.  */
+    case 'V':
+      {
+       int mode = GET_MODE (x);
+
+       if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
+         abort ();
+
+       fprintf (stream, "mv%s%s",
+                mode == DFmode ? "d"
+                : mode == SImode ? "fx"
+                : mode == DImode ? "dx"
+                : "f", reg_names[REGNO (x)] + 2);
+
+       return;
+      }
+
     default:
       if (x == 0)
        abort ();
@@ -9765,6 +10117,18 @@ arm_final_prescan_insn (insn)
                    || GET_CODE (scanbody) == PARALLEL)
                  || get_attr_conds (this_insn) != CONDS_NOCOND)
                fail = TRUE;
+
+             /* A conditional cirrus instruction must be followed by
+                a non Cirrus instruction.  However, since we
+                conditionalize instructions in this function and by
+                the time we get here we can't add instructions
+                (nops), because shorten_branches() has already been
+                called, we will disable conditionalizing Cirrus
+                instructions to be safe.  */
+             if (GET_CODE (scanbody) != USE
+                 && GET_CODE (scanbody) != CLOBBER
+                 && get_attr_cirrus (this_insn) != CIRRUS_NO)
+               fail = TRUE;
              break;
 
            default:
@@ -9848,6 +10212,14 @@ arm_hard_regno_mode_ok (regno, mode)
        start of an even numbered register pair.  */
     return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
 
+  if (IS_CIRRUS_REGNUM (regno))
+    /* We have outlawed SI values in Cirrus registers because they
+       reside in the lower 32 bits, but SF values reside in the
+       upper 32 bits.  This causes gcc all sorts of grief.  We can't
+       even split the registers into pairs because Cirrus SI values
+       get sign extended to 64bits-- aldyh.  */
+    return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
+
   if (regno <= LAST_ARM_REGNUM)
     /* We allow any value to be stored in the general regisetrs.  */
     return 1;
@@ -9887,6 +10259,9 @@ arm_regno_class (regno)
   if (regno == CC_REGNUM)
     return NO_REGS;
 
+  if (IS_CIRRUS_REGNUM (regno))
+    return CIRRUS_REGS;
+
   return FPU_REGS;
 }
 
index 802e19986c758b7043bc4fe68b1c2c0093a09333..5732f38c7d0f0d8b163605620379781788925d01 100644 (file)
@@ -96,6 +96,7 @@ Boston, MA 02111-1307, USA.  */
 #define TARGET_CPU_arm9                0x0080
 #define TARGET_CPU_arm9tdmi    0x0080
 #define TARGET_CPU_xscale       0x0100
+#define TARGET_CPU_ep9312      0x0200
 /* Configure didn't specify.  */
 #define TARGET_CPU_generic     0x8000
 
@@ -164,6 +165,14 @@ extern GTY(()) rtx aof_pic_label;
 #if TARGET_CPU_DEFAULT == TARGET_CPU_xscale
 #define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_5TE__ -D__XSCALE__"
 #else
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ep9312
+#define CPP_ARCH_DEFAULT_SPEC "-D__ARM_ARCH_4T__ -D__MAVERICK__"
+/* Set TARGET_DEFAULT to the default, but without soft-float.  */
+#ifdef  TARGET_DEFAULT
+#undef  TARGET_DEFAULT
+#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME)
+#endif /* TARGET_CPU_DEFAULT */
+#else
 Unrecognized value in TARGET_CPU_DEFAULT.
 #endif
 #endif
@@ -171,6 +180,7 @@ Unrecognized value in TARGET_CPU_DEFAULT.
 #endif
 #endif
 #endif
+#endif
 
 #undef  CPP_SPEC
 #define CPP_SPEC "%(cpp_cpu_arch) %(subtarget_cpp_spec)                        \
@@ -212,6 +222,8 @@ Unrecognized value in TARGET_CPU_DEFAULT.
 %{march=strongarm1100:-D__ARM_ARCH_4__} \
 %{march=xscale:-D__ARM_ARCH_5TE__} \
 %{march=xscale:-D__XSCALE__} \
+%{march=ep9312:-D__ARM_ARCH_4T__} \
+%{march=ep9312:-D__MAVERICK__} \
 %{march=armv2:-D__ARM_ARCH_2__} \
 %{march=armv2a:-D__ARM_ARCH_2__} \
 %{march=armv3:-D__ARM_ARCH_3__} \
@@ -251,6 +263,8 @@ Unrecognized value in TARGET_CPU_DEFAULT.
  %{mcpu=strongarm1100:-D__ARM_ARCH_4__} \
  %{mcpu=xscale:-D__ARM_ARCH_5TE__} \
  %{mcpu=xscale:-D__XSCALE__} \
+ %{mcpu=ep9312:-D__ARM_ARCH_4T__} \
+ %{mcpu=ep9312:-D__MAVERICK__} \
  %{!mcpu*:%(cpp_cpu_arch_default)}} \
 "
 
@@ -376,6 +390,9 @@ Unrecognized value in TARGET_CPU_DEFAULT.
 /* Nonzero means to use ARM/Thumb Procedure Call Standard conventions.  */
 #define ARM_FLAG_ATPCS         (1 << 22)
 
+/* Fix invalid Cirrus instruction combinations by inserting NOPs.  */
+#define CIRRUS_FIX_INVALID_INSNS (1 << 23)
+
 #define TARGET_APCS_FRAME              (target_flags & ARM_FLAG_APCS_FRAME)
 #define TARGET_POKE_FUNCTION_NAME      (target_flags & ARM_FLAG_POKE)
 #define TARGET_FPE                     (target_flags & ARM_FLAG_FPE)
@@ -387,6 +404,8 @@ Unrecognized value in TARGET_CPU_DEFAULT.
 #define TARGET_MMU_TRAPS               (target_flags & ARM_FLAG_MMU_TRAPS)
 #define TARGET_SOFT_FLOAT              (target_flags & ARM_FLAG_SOFT_FLOAT)
 #define TARGET_HARD_FLOAT              (! TARGET_SOFT_FLOAT)
+#define TARGET_CIRRUS                  (arm_is_cirrus)
+#define TARGET_ANY_HARD_FLOAT          (TARGET_HARD_FLOAT || TARGET_CIRRUS)
 #define TARGET_VFP                     (target_flags & ARM_FLAG_VFP)
 #define TARGET_BIG_END                 (target_flags & ARM_FLAG_BIG_END)
 #define TARGET_INTERWORK               (target_flags & ARM_FLAG_INTERWORK)
@@ -403,6 +422,7 @@ Unrecognized value in TARGET_CPU_DEFAULT.
 #define TARGET_BACKTRACE               (leaf_function_p ()                             \
                                         ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE)   \
                                         : (target_flags & THUMB_FLAG_BACKTRACE))
+#define TARGET_CIRRUS_FIX_INVALID_INSNS        (target_flags & CIRRUS_FIX_INVALID_INSNS)
 
 /* SUBTARGET_SWITCHES is used to add flags on a per-config basis.  */
 #ifndef SUBTARGET_SWITCHES
@@ -481,6 +501,10 @@ Unrecognized value in TARGET_CPU_DEFAULT.
    N_("Thumb: Assume function pointers may go to non-Thumb aware code") }, \
   {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING,  \
    "" },                                                                  \
+  {"cirrus-fix-invalid-insns",      CIRRUS_FIX_INVALID_INSNS,             \
+   N_("Cirrus: Place NOPs to avoid invalid instruction combinations") },   \
+  {"no-cirrus-fix-invalid-insns",  -CIRRUS_FIX_INVALID_INSNS,             \
+   N_("Cirrus: Do not break up invalid instruction combinations with NOPs") },\
   SUBTARGET_SWITCHES                                                      \
   {"",                         TARGET_DEFAULT, "" }                       \
 }
@@ -530,7 +554,8 @@ enum floating_point_type
 {
   FP_HARD,
   FP_SOFT2,
-  FP_SOFT3
+  FP_SOFT3,
+  FP_CIRRUS
 };
 
 /* Recast the floating point class to be the floating point attribute.  */
@@ -548,6 +573,11 @@ extern enum floating_point_type arm_fpu_arch;
 #define FP_DEFAULT FP_SOFT2
 #endif
 
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ep9312
+#undef  FP_DEFAULT
+#define FP_DEFAULT FP_CIRRUS
+#endif
+
 /* Nonzero if the processor has a fast multiply insn, and one that does
    a 64-bit multiply of two 32-bit values.  */
 extern int arm_fast_multiply;
@@ -570,6 +600,9 @@ extern int thumb_code;
 /* Nonzero if this chip is a StrongARM.  */
 extern int arm_is_strong;
 
+/* Nonzero if this chip is a Cirrus variant.  */
+extern int arm_is_cirrus;
+
 /* Nonzero if this chip is an XScale.  */
 extern int arm_is_xscale;
 
@@ -756,6 +789,11 @@ extern const char * structure_size_string;
 
    *: See CONDITIONAL_REGISTER_USAGE  */
 
+/*
+       mvf0            Cirrus floating point result
+       mvf1-mvf3       Cirrus floating point scratch
+       mvf4-mvf15   S  Cirrus floating point variable.  */
+
 /* The stack backtrace structure is as follows:
   fp points to here:  |  save code pointer  |      [fp]
                       |  return link value  |      [fp, #-4]
@@ -785,7 +823,9 @@ extern const char * structure_size_string;
   0,0,0,0,0,0,0,0,      \
   0,0,0,0,0,1,0,1,      \
   0,0,0,0,0,0,0,0,      \
-  1,1,1                         \
+  1,1,1,               \
+  1,1,1,1,1,1,1,1,     \
+  1,1,1,1,1,1,1,1      \
 }
 
 /* 1 for registers not available across function calls.
@@ -801,7 +841,9 @@ extern const char * structure_size_string;
   1,1,1,1,0,0,0,0,          \
   0,0,0,0,1,1,1,1,          \
   1,1,1,1,0,0,0,0,          \
-  1,1,1                             \
+  1,1,1,                    \
+  1,1,1,1,1,1,1,1,          \
+  1,1,1,1,1,1,1,1           \
 }
 
 #ifndef SUBTARGET_CONDITIONAL_REGISTER_USAGE
@@ -818,6 +860,20 @@ extern const char * structure_size_string;
           regno <= LAST_ARM_FP_REGNUM; ++regno)                \
        fixed_regs[regno] = call_used_regs[regno] = 1;          \
     }                                                          \
+                                                               \
+  if (TARGET_CIRRUS)                                           \
+    {                                                          \
+      for (regno = FIRST_ARM_FP_REGNUM;                                \
+          regno <= LAST_ARM_FP_REGNUM; ++ regno)               \
+       fixed_regs[regno] = call_used_regs[regno] = 1;          \
+      for (regno = FIRST_CIRRUS_FP_REGNUM;                     \
+          regno <= LAST_CIRRUS_FP_REGNUM; ++ regno)            \
+       {                                                       \
+         fixed_regs[regno] = 0;                                \
+         call_used_regs[regno] = regno < FIRST_CIRRUS_FP_REGNUM + 4; \
+       }                                                       \
+    }                                                          \
+                                                               \
   if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)    \
     {                                                          \
       fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;                 \
@@ -941,8 +997,14 @@ extern const char * structure_size_string;
 /* Base register for access to arguments of the function.  */
 #define ARG_POINTER_REGNUM     26
 
+#define FIRST_CIRRUS_FP_REGNUM 27
+#define LAST_CIRRUS_FP_REGNUM  42
+#define IS_CIRRUS_REGNUM(REGNUM) \
+  (((REGNUM) >= FIRST_CIRRUS_FP_REGNUM) && ((REGNUM) <= LAST_CIRRUS_FP_REGNUM))
+
 /* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP.  */
-#define FIRST_PSEUDO_REGISTER  27
+/* Cirrus registers take us up to 43... */
+#define FIRST_PSEUDO_REGISTER  43
 
 /* Value should be nonzero if functions must have frame pointers.
    Zero means the frame pointer need not be set up (and parms may be accessed
@@ -990,6 +1052,8 @@ extern const char * structure_size_string;
      3,  2,  1,  0, 12, 14,  4,  5, \
      6,  7,  8, 10,  9, 11, 13, 15, \
     16, 17, 18, 19, 20, 21, 22, 23, \
+    27, 28, 29, 30, 31, 32, 33, 34, \
+    35, 36, 37, 38, 39, 40, 41, 42, \
     24, 25, 26                     \
 }
 
@@ -1008,6 +1072,7 @@ enum reg_class
 {
   NO_REGS,
   FPU_REGS,
+  CIRRUS_REGS,
   LO_REGS,
   STACK_REG,
   BASE_REGS,
@@ -1025,6 +1090,7 @@ enum reg_class
 {                      \
   "NO_REGS",           \
   "FPU_REGS",          \
+  "CIRRUS_REGS",       \
   "LO_REGS",           \
   "STACK_REG",         \
   "BASE_REGS",         \
@@ -1039,15 +1105,16 @@ enum reg_class
    of length N_REG_CLASSES.  */
 #define REG_CLASS_CONTENTS             \
 {                                      \
-  { 0x0000000 }, /* NO_REGS  */                \
-  { 0x0FF0000 }, /* FPU_REGS */                \
-  { 0x00000FF }, /* LO_REGS */         \
-  { 0x0002000 }, /* STACK_REG */       \
-  { 0x00020FF }, /* BASE_REGS */       \
-  { 0x000FF00 }, /* HI_REGS */         \
-  { 0x1000000 }, /* CC_REG */          \
-  { 0x200FFFF }, /* GENERAL_REGS */    \
-  { 0x2FFFFFF }  /* ALL_REGS */                \
+  { 0x00000000, 0x0 },        /* NO_REGS  */   \
+  { 0x00FF0000, 0x0 },        /* FPU_REGS */   \
+  { 0xF8000000, 0x000007FF }, /* CIRRUS_REGS */        \
+  { 0x000000FF, 0x0 },        /* LO_REGS */    \
+  { 0x00002000, 0x0 },        /* STACK_REG */  \
+  { 0x000020FF, 0x0 },        /* BASE_REGS */  \
+  { 0x0000FF00, 0x0 },        /* HI_REGS */    \
+  { 0x01000000, 0x0 },        /* CC_REG */     \
+  { 0x0200FFFF, 0x0 },        /* GENERAL_REGS */\
+  { 0xFAFFFFFF, 0x000007FF }  /* ALL_REGS */   \
 }
 
 /* The same information, inverted:
@@ -1080,6 +1147,7 @@ enum reg_class
    ARM, but several more letters for the Thumb.  */
 #define REG_CLASS_FROM_LETTER(C)       \
   (  (C) == 'f' ? FPU_REGS             \
+   : (C) == 'v' ? CIRRUS_REGS          \
    : (C) == 'l' ? (TARGET_ARM ? GENERAL_REGS : LO_REGS)        \
    : TARGET_ARM ? NO_REGS              \
    : (C) == 'h' ? HI_REGS              \
@@ -1143,8 +1211,9 @@ enum reg_class
    (C) == 'R' ? (GET_CODE (OP) == MEM                                      \
                 && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF                   \
                 && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) :               \
-   (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP))                  \
-   : 0)
+   (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) :                \
+   (C) == 'T' ? cirrus_memory_offset (OP) :                                \
+   0)
 
 #define EXTRA_CONSTRAINT_THUMB(X, C)                                   \
   ((C) == 'Q' ? (GET_CODE (X) == MEM                                   \
@@ -1188,13 +1257,18 @@ enum reg_class
    
 /* If we need to load shorts byte-at-a-time, then we need a scratch. */
 #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X)           \
+  /* Cannot load constants into Cirrus registers.  */          \
+  ((TARGET_CIRRUS                                              \
+     && (CLASS) == CIRRUS_REGS                                 \
+     && (CONSTANT_P (X) || GET_CODE (X) == SYMBOL_REF))                \
+    ? GENERAL_REGS :                                           \
   (TARGET_ARM ?                                                        \
    (((MODE) == HImode && ! arm_arch4 && TARGET_MMU_TRAPS       \
      && (GET_CODE (X) == MEM                                   \
         || ((GET_CODE (X) == REG || GET_CODE (X) == SUBREG)    \
             && true_regnum (X) == -1)))                        \
     ? GENERAL_REGS : NO_REGS)                                  \
-   : THUMB_SECONDARY_INPUT_RELOAD_CLASS (CLASS, MODE, X))
+   : THUMB_SECONDARY_INPUT_RELOAD_CLASS (CLASS, MODE, X)))
 
 /* Try a machine-dependent way of reloading an illegitimate address
    operand.  If we find one, push the reload and jump to WIN.  This
@@ -1217,6 +1291,9 @@ enum reg_class
                                                                           \
          if (MODE == DImode || (TARGET_SOFT_FLOAT && MODE == DFmode))     \
            low = ((val & 0xf) ^ 0x8) - 0x8;                               \
+         else if (TARGET_CIRRUS)                                          \
+           /* Need to be careful, -256 is not a valid offset.  */         \
+           low = val >= 0 ? (val & 0xff) : -((-val) & 0xff);              \
          else if (MODE == SImode                                          \
                   || (MODE == SFmode && TARGET_SOFT_FLOAT)                \
                   || ((MODE == HImode || MODE == QImode) && ! arm_arch4)) \
@@ -1289,13 +1366,19 @@ enum reg_class
    needed to represent mode MODE in a register of class CLASS.
    ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */
 #define CLASS_MAX_NREGS(CLASS, MODE)  \
-  ((CLASS) == FPU_REGS ? 1 : ARM_NUM_REGS (MODE))
+  (((CLASS) == FPU_REGS || (CLASS) == CIRRUS_REGS) ? 1 : ARM_NUM_REGS (MODE))
+
+/* If defined, gives a class of registers that cannot be used as the
+   operand of a SUBREG that changes the mode of the object illegally.  */
 
 /* Moves between FPU_REGS and GENERAL_REGS are two memory insns.  */
 #define REGISTER_MOVE_COST(MODE, FROM, TO)             \
   (TARGET_ARM ?                                                \
    ((FROM) == FPU_REGS && (TO) != FPU_REGS ? 20 :      \
-    (FROM) != FPU_REGS && (TO) == FPU_REGS ? 20 : 2)   \
+    (FROM) != FPU_REGS && (TO) == FPU_REGS ? 20 :      \
+    (FROM) == CIRRUS_REGS && (TO) != CIRRUS_REGS ? 20 :        \
+    (FROM) != CIRRUS_REGS && (TO) == CIRRUS_REGS ? 20 :        \
+   2)                                                  \
    :                                                   \
    ((FROM) == HI_REGS || (TO) == HI_REGS) ? 4 : 2)
 \f
@@ -1347,6 +1430,8 @@ enum reg_class
 #define LIBCALL_VALUE(MODE)  \
   (TARGET_ARM && TARGET_HARD_FLOAT && GET_MODE_CLASS (MODE) == MODE_FLOAT \
    ? gen_rtx_REG (MODE, FIRST_ARM_FP_REGNUM) \
+   : TARGET_ARM && TARGET_CIRRUS && GET_MODE_CLASS (MODE) == MODE_FLOAT \
+   ? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM)                        \
    : gen_rtx_REG (MODE, ARG_REGISTER (1)))
 
 /* Define how to find the value returned by a function.
@@ -1358,8 +1443,10 @@ enum reg_class
 
 /* 1 if N is a possible register number for a function value.
    On the ARM, only r0 and f0 can return results.  */
+/* On a Cirrus chip, mvf0 can return results.  */
 #define FUNCTION_VALUE_REGNO_P(REGNO)  \
   ((REGNO) == ARG_REGISTER (1) \
+   || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) && TARGET_CIRRUS) \
    || (TARGET_ARM && ((REGNO) == FIRST_ARM_FP_REGNUM) && TARGET_HARD_FLOAT))
 
 /* How large values are returned */
@@ -2449,6 +2536,9 @@ extern int making_const_table;
   {"multi_register_push", {PARALLEL}},                                 \
   {"cc_register", {REG}},                                              \
   {"logical_binary_operator", {AND, IOR, XOR}},                                \
+  {"cirrus_register_operand", {REG}},                                  \
+  {"cirrus_fp_register", {REG}},                                       \
+  {"cirrus_shift_const", {CONST_INT}},                                 \
   {"dominant_cc_register", {REG}},
 
 /* Define this if you have special predicates that know special things
index b35041a4b74a924e614c9fb4edf908d1240a4ae0..705d22dbf01443d86c25cf1649349b4d97883785 100644 (file)
   (and (eq_attr "core_cycles" "multi")
        (eq_attr "type" "!mult,load,store1,store2,store3,store4")) 32 32)
 \f
+(include "cirrus.md")
+
 ;;---------------------------------------------------------------------------
 ;; Insn patterns
 ;;
 ;; Note: For DImode insns, there is normally no reason why operands should
 ;; not be in the same register, what we don't want is for something being
 ;; written to partially overlap something that is an input.
+;; Cirrus 64bit additions should not be split because we have a native
+;; 64bit addition instructions.
 
 (define_expand "adddi3"
  [(parallel
     (clobber (reg:CC CC_REGNUM))])]
   "TARGET_EITHER"
   "
+  if (TARGET_CIRRUS)
+    {
+      if (!cirrus_fp_register (operands[0], DImode))
+        operands[0] = force_reg (DImode, operands[0]);
+      if (!cirrus_fp_register (operands[1], DImode))
+        operands[1] = force_reg (DImode, operands[1]);
+      emit_insn (gen_cirrus_adddi3 (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+
   if (TARGET_THUMB)
     {
       if (GET_CODE (operands[1]) != REG)
        (plus:DI (match_operand:DI 1 "s_register_operand" "%0, 0")
                 (match_operand:DI 2 "s_register_operand" "r,  0")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM"
+  "TARGET_ARM && !TARGET_CIRRUS"
   "#"
   "TARGET_ARM && reload_completed"
   [(parallel [(set (reg:CC_C CC_REGNUM)
                  (match_operand:SI 2 "s_register_operand" "r,r"))
                 (match_operand:DI 1 "s_register_operand" "r,0")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM"
+  "TARGET_ARM && !TARGET_CIRRUS"
   "#"
   "TARGET_ARM && reload_completed"
   [(parallel [(set (reg:CC_C CC_REGNUM)
                  (match_operand:SI 2 "s_register_operand" "r,r"))
                 (match_operand:DI 1 "s_register_operand" "r,0")))
    (clobber (reg:CC CC_REGNUM))]
-  "TARGET_ARM"
+  "TARGET_ARM && !TARGET_CIRRUS"
   "#"
   "TARGET_ARM && reload_completed"
   [(parallel [(set (reg:CC_C CC_REGNUM)
    (set_attr "length" "4,8")]
 )
 
-(define_insn "addsf3"
+(define_insn "*arm_addsf3"
   [(set (match_operand:SF          0 "s_register_operand" "=f,f")
        (plus:SF (match_operand:SF 1 "s_register_operand" "%f,f")
                 (match_operand:SF 2 "fpu_add_operand"    "fG,H")))]
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "adddf3"
+(define_insn "*arm_adddf3"
   [(set (match_operand:DF          0 "s_register_operand" "=f,f")
        (plus:DF (match_operand:DF 1 "s_register_operand" "%f,f")
                 (match_operand:DF 2 "fpu_add_operand"    "fG,H")))]
     (clobber (reg:CC CC_REGNUM))])]
   "TARGET_EITHER"
   "
+  if (TARGET_CIRRUS
+      && TARGET_ARM
+      && cirrus_fp_register (operands[0], DImode)
+      && cirrus_fp_register (operands[1], DImode))
+    {
+      emit_insn (gen_cirrus_subdi3 (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+
   if (TARGET_THUMB)
     {
       if (GET_CODE (operands[1]) != REG)
    (set_attr "length" "*,8")]
 )
 
-(define_insn "subsf3"
+(define_insn "*arm_subsf3"
   [(set (match_operand:SF 0 "s_register_operand" "=f,f")
        (minus:SF (match_operand:SF 1 "fpu_rhs_operand" "f,G")
                  (match_operand:SF 2 "fpu_rhs_operand" "fG,f")))]
   [(set_attr "type" "farith")]
 )
 
-(define_insn "subdf3"
+(define_insn "*arm_subdf3"
   [(set (match_operand:DF           0 "s_register_operand" "=f,f")
        (minus:DF (match_operand:DF 1 "fpu_rhs_operand"     "f,G")
                  (match_operand:DF 2 "fpu_rhs_operand"    "fG,f")))]
   "smlalbb%?\\t%Q0, %R0, %2, %3"
 [(set_attr "type" "mult")])
 
-(define_insn "mulsf3"
+(define_insn "*arm_mulsf3"
   [(set (match_operand:SF 0 "s_register_operand" "=f")
        (mult:SF (match_operand:SF 1 "s_register_operand" "f")
                 (match_operand:SF 2 "fpu_rhs_operand" "fG")))]
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "muldf3"
+(define_insn "*arm_muldf3"
   [(set (match_operand:DF 0 "s_register_operand" "=f")
        (mult:DF (match_operand:DF 1 "s_register_operand" "f")
                 (match_operand:DF 2 "fpu_rhs_operand" "fG")))]
   [(set_attr "length" "2")]
 )
 
+(define_expand "ashldi3"
+  [(set (match_operand:DI            0 "s_register_operand" "")
+       (ashift:DI (match_operand:DI 1 "general_operand"    "")
+                  (match_operand:SI 2 "general_operand"    "")))]
+  "TARGET_ARM && (TARGET_CIRRUS)"
+  "
+  if (! s_register_operand (operands[1], DImode))
+    operands[1] = copy_to_mode_reg (DImode, operands[1]);
+  if (! s_register_operand (operands[2], SImode))
+    operands[2] = copy_to_mode_reg (SImode, operands[2]);
+  "
+)
+
 (define_insn "*arm_shiftsi3"
   [(set (match_operand:SI   0 "s_register_operand" "=r")
        (match_operator:SI  3 "shift_operator"
   [(set_attr "length" "2")]
 )
 
-(define_insn "negsf2"
+(define_insn "*arm_negsf2"
   [(set (match_operand:SF         0 "s_register_operand" "=f")
        (neg:SF (match_operand:SF 1 "s_register_operand" "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "negdf2"
+(define_insn "*arm_negdf2"
   [(set (match_operand:DF         0 "s_register_operand" "=f")
        (neg:DF (match_operand:DF 1 "s_register_operand" "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
 ;; it does, but tell the final scan operator the truth.  Similarly for
 ;; (neg (abs...))
 
-(define_insn "abssi2"
+(define_insn "*arm_abssi2"
   [(set (match_operand:SI         0 "s_register_operand" "=r,&r")
        (abs:SI (match_operand:SI 1 "s_register_operand" "0,r")))
    (clobber (reg:CC CC_REGNUM))]
    (set_attr "length" "8")]
 )
 
-(define_insn "abssf2"
+(define_insn "*arm_abssf2"
   [(set (match_operand:SF          0 "s_register_operand" "=f")
         (abs:SF (match_operand:SF 1 "s_register_operand" "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "absdf2"
+(define_insn "*arm_absdf2"
   [(set (match_operand:DF         0 "s_register_operand" "=f")
        (abs:DF (match_operand:DF 1 "s_register_operand" "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
 \f
 ;; Fixed <--> Floating conversion insns
 
-(define_insn "floatsisf2"
+(define_insn "*arm_floatsisf2"
   [(set (match_operand:SF           0 "s_register_operand" "=f")
        (float:SF (match_operand:SI 1 "s_register_operand" "r")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "floatsidf2"
+(define_insn "*arm_floatsidf2"
   [(set (match_operand:DF           0 "s_register_operand" "=f")
        (float:DF (match_operand:SI 1 "s_register_operand" "r")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "fix_truncsfsi2"
+(define_insn "*arm_fix_truncsfsi2"
   [(set (match_operand:SI         0 "s_register_operand" "=r")
        (fix:SI (match_operand:SF 1 "s_register_operand" "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
    (set_attr "predicable" "yes")]
 )
 
-(define_insn "fix_truncdfsi2"
+(define_insn "*arm_fix_truncdfsi2"
   [(set (match_operand:SI         0 "s_register_operand" "=r")
        (fix:SI (match_operand:DF 1 "s_register_operand" "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
 
 ;; Truncation insns
 
-(define_insn "truncdfsf2"
+(define_insn "*arm_truncdfsf2"
   [(set (match_operand:SF 0 "s_register_operand" "=f")
        (float_truncate:SF
         (match_operand:DF 1 "s_register_operand" "f")))]
    (set_attr "pool_range" "32,32")]
 )
 
-(define_insn "extendsfdf2"
+(define_insn "*arm_extendsfdf2"
   [(set (match_operand:DF                  0 "s_register_operand" "=f")
        (float_extend:DF (match_operand:SF 1 "s_register_operand"  "f")))]
   "TARGET_ARM && TARGET_HARD_FLOAT"
 (define_insn "*arm_movdi"
   [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r, r, o<>")
        (match_operand:DI 1 "di_operand"              "rIK,mi,r"))]
-  "TARGET_ARM"
+  "TARGET_ARM && !TARGET_CIRRUS"
   "*
   return (output_move_double (operands));
   "
   [(set (match_operand:DI 0 "nonimmediate_operand" "=l,l,l,l,>,l, m,*r")
        (match_operand:DI 1 "general_operand"      "l, I,J,>,l,mi,l,*r"))]
   "TARGET_THUMB
+   && !TARGET_CIRRUS
    && (   register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))"
   "*
   [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m")
        (match_operand:SF 1 "general_operand"  "r,mE,r"))]
   "TARGET_ARM
+   && !TARGET_CIRRUS
    && TARGET_SOFT_FLOAT
    && (GET_CODE (operands[0]) != MEM
        || register_operand (operands[1], SFmode))"
   [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=r,r,m")
        (match_operand:DF 1 "soft_df_operand" "r,mF,r"))]
   "TARGET_ARM && TARGET_SOFT_FLOAT
+   && !TARGET_CIRRUS
   "
   "* return output_move_double (operands);"
   [(set_attr "length" "8,8,8")
 (define_expand "cmpsf"
   [(match_operand:SF 0 "s_register_operand" "")
    (match_operand:SF 1 "fpu_rhs_operand" "")]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
   "
+  if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], SFmode))
+    operands[1] = force_reg (SFmode, operands[1]);
+
   arm_compare_op0 = operands[0];
   arm_compare_op1 = operands[1];
   DONE;
 (define_expand "cmpdf"
   [(match_operand:DF 0 "s_register_operand" "")
    (match_operand:DF 1 "fpu_rhs_operand" "")]
-  "TARGET_ARM && TARGET_HARD_FLOAT"
+  "TARGET_ARM && TARGET_ANY_HARD_FLOAT"
   "
+  if (TARGET_CIRRUS && !cirrus_fp_register (operands[1], DFmode))
+    operands[1] = force_reg (DFmode, operands[1]);
+
   arm_compare_op0 = operands[0];
   arm_compare_op1 = operands[1];
   DONE;
    (set_attr "type" "f_2_r")]
 )
 
+;; There is no CCFPE or CCFP modes in the code below so we can have
+;; one pattern to match either one.  Besides, we're pretty sure we
+;; have either CCFPE or CCFP because we made the patterns
+;; (arm_gen_compare_reg).
+
+;; Cirrus SF compare instruction
+(define_insn "*cirrus_cmpsf"
+  [(set (reg:CCFP CC_REGNUM)
+       (compare:CCFP (match_operand:SF 0 "cirrus_fp_register" "v")
+                     (match_operand:SF 1 "cirrus_fp_register" "v")))]
+  "TARGET_ARM && TARGET_CIRRUS"
+  "cfcmps%?\\tr15, %V0, %V1"
+  [(set_attr "cirrus_type" "farith")
+   (set_attr "cirrus" "compare")]
+)
+
+;; Cirrus DF compare instruction
+(define_insn "*cirrus_cmpdf"
+  [(set (reg:CCFP CC_REGNUM)
+       (compare:CCFP (match_operand:DF 0 "cirrus_fp_register" "v")
+                     (match_operand:DF 1 "cirrus_fp_register" "v")))]
+  "TARGET_ARM && TARGET_CIRRUS"
+  "cfcmpd%?\\tr15, %V0, %V1"
+  [(set_attr "cirrus_type" "farith")
+   (set_attr "cirrus" "compare")]
+)
+
+;; Cirrus DI compare instruction
+(define_expand "cmpdi"
+  [(match_operand:DI 0 "cirrus_fp_register" "")
+   (match_operand:DI 1 "cirrus_fp_register" "")]
+  "TARGET_ARM && TARGET_CIRRUS"
+  "{
+     arm_compare_op0 = operands[0];
+     arm_compare_op1 = operands[1];
+     DONE;
+   }")
+
+(define_insn "*cirrus_cmpdi"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_operand:DI 0 "cirrus_fp_register" "v")
+                   (match_operand:DI 1 "cirrus_fp_register" "v")))]
+  "TARGET_ARM && TARGET_CIRRUS"
+  "cfcmp64%?\\tr15, %V0, %V1"
+  [(set_attr "cirrus_type" "farith")
+   (set_attr "cirrus" "compare")]
+)
+
+;; Cirrus SI compare instruction
+(define_insn "*cirrus_cmpsi_1"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_operand:SI 0 "cirrus_fp_register" "v")
+                   (match_operand:SI 1 "cirrus_fp_register" "v")))]
+  "TARGET_ARM && TARGET_CIRRUS && 0"
+  "cfcmp32%?\\tr15, %V0, %V1"
+  [(set_attr "cirrus_type" "farith")
+   (set_attr "cirrus" "compare")]
+)
+
 (define_insn "*cmpsf_trap"
   [(set (reg:CCFPE CC_REGNUM)
        (compare:CCFPE (match_operand:SF 0 "s_register_operand" "f,f")
 )
 
 (define_insn "*call_value_reg"
-  [(set (match_operand 0 "" "=r,f")
-        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r"))
+  [(set (match_operand 0 "" "=r,f,v")
+        (call (mem:SI (match_operand:SI 1 "s_register_operand" "r,r,r"))
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_insn "*call_value_mem"
-  [(set (match_operand 0 "" "=r,f")
-       (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m"))
+  [(set (match_operand 0 "" "=r,f,v")
+       (call (mem:SI (match_operand:SI 1 "memory_operand" "m,m,m"))
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_insn "*call_value_symbol"
-  [(set (match_operand 0 "s_register_operand" "=r,f")
-       (call (mem:SI (match_operand:SI 1 "" "X,X"))
+  [(set (match_operand 0 "s_register_operand" "=r,f,v")
+       (call (mem:SI (match_operand:SI 1 "" "X,X,X"))
        (match_operand:SI 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
 )
 
 (define_insn "*sibcall_value_insn"
- [(set (match_operand 0 "s_register_operand" "=r,f")
-       (call (mem:SI (match_operand:SI 1 "" "X,X"))
+ [(set (match_operand 0 "s_register_operand" "=r,f,v")
+       (call (mem:SI (match_operand:SI 1 "" "X,X,X"))
             (match_operand 2 "" "")))
   (return)
   (use (match_operand 3 "" ""))]
    (set (reg:CC CC_REGNUM)
        (compare:CC (match_dup 1) (const_int 0)))]
   "TARGET_ARM
+   && (!TARGET_CIRRUS
+       || (!cirrus_fp_register (operands[0], SImode)
+           && !cirrus_fp_register (operands[1], SImode)))
   "
   [(parallel [(set (reg:CC CC_REGNUM) (compare:CC (match_dup 1) (const_int 0)))
              (set (match_dup 0) (match_dup 1))])]
index 0011b2a8d025f4af21a6b8e873efe13297c27ba3..79506fb5a62648fdd36e9ac1fb70ff7bce429435 100644 (file)
@@ -24,6 +24,10 @@ dp-bit.c: $(srcdir)/config/fp-bit.c
 MULTILIB_OPTIONS     = marm/mthumb
 MULTILIB_DIRNAMES    = arm thumb
 MULTILIB_EXCEPTIONS  = 
+
+# MULTILIB_OPTIONS    += mcpu=ep9312
+# MULTILIB_DIRNAMES   += ep9312
+# MULTILIB_EXCEPTIONS += *mthumb/*mcpu=ep9312*
        
 # MULTILIB_OPTIONS     += mlittle-endian/mbig-endian
 # MULTILIB_DIRNAMES    += le be
index c8f0086a423497bbdbd5e833dc4aaa21f35d8a11..cfcf4dc9e0880dcccc3c5f83aadc498f41fb39d6 100644 (file)
@@ -386,6 +386,7 @@ in the following sections.
 -msingle-pic-base  -mno-single-pic-base @gol
 -mpic-register=@var{reg} @gol
 -mnop-fun-dllimport @gol
+-mcirrus-fix-invalid-insns -mno-cirrus-fix-invalid-insns @gol
 -mpoke-function-name @gol
 -mthumb  -marm @gol
 -mtpcs-frame  -mtpcs-leaf-frame @gol
@@ -6132,7 +6133,7 @@ assembly code.  Permissible names are: @samp{arm2}, @samp{arm250},
 @samp{strongarm}, @samp{strongarm110}, @samp{strongarm1100},
 @samp{arm8}, @samp{arm810}, @samp{arm9}, @samp{arm9e}, @samp{arm920},
 @samp{arm920t}, @samp{arm940t}, @samp{arm9tdmi}, @samp{arm10tdmi},
-@samp{arm1020t}, @samp{xscale}.
+@samp{arm1020t}, @samp{xscale}, @samp{ep9312}.
 
 @itemx -mtune=@var{name}
 @opindex mtune
@@ -6152,7 +6153,7 @@ name to determine what kind of instructions it can emit when generating
 assembly code.  This option can be used in conjunction with or instead
 of the @option{-mcpu=} option.  Permissible names are: @samp{armv2},
 @samp{armv2a}, @samp{armv3}, @samp{armv3m}, @samp{armv4}, @samp{armv4t},
-@samp{armv5}, @samp{armv5t}, @samp{armv5te}.
+@samp{armv5}, @samp{armv5t}, @samp{armv5te}, @samp{ep9312}.
 
 @item -mfpe=@var{number}
 @itemx -mfp=@var{number}
@@ -6224,6 +6225,18 @@ before execution begins.
 Specify the register to be used for PIC addressing.  The default is R10
 unless stack-checking is enabled, when R9 is used.
 
+@item -mcirrus-fix-invalid-insns
+@opindex -mcirrus-fix-invalid-insns
+@opindex -mno-cirrus-fix-invalid-insns
+Insert NOPs into the instruction stream to in order to work around
+problems with invalid Maverick instruction combinations.  This option
+is only valid if the @option{-mcpu=ep9312} option has been used to
+enable generation of instructions for the Cirrus Maverick floating
+point co-processor.  This option is not enabled by default, since the
+problem is only present in older Maverick implemenations.  The default
+can be re-enabled by use of the @option{-mno-cirrus-fix-invalid-insns}
+switch.
+
 @item -mpoke-function-name
 @opindex mpoke-function-name
 Write the name of each function into the text section, directly