]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[ARC] Add single/double IEEE precission FPU support.
authorClaudiu Zissulescu <claziss@synopsys.com>
Tue, 16 Feb 2016 14:11:24 +0000 (15:11 +0100)
committerClaudiu Zissulescu <claziss@gcc.gnu.org>
Tue, 16 Feb 2016 14:11:24 +0000 (15:11 +0100)
gcc/
2016-02-16  Claudiu Zissulescu  <claziss@synopsys.com>

* config/arc/arc-modes.def (CC_FPU, CC_FPU_UNEQ): New modes.
* config/arc/arc-opts.h (FPU_SP, FPU_SF, FPU_SC, FPU_SD, FPU_DP)
(FPU_DF, FPU_DC, FPU_DD, FXP_DP): Define.
* config/arc/arc.c (arc_init): Check FPU options.
(get_arc_condition_code): Handle new CC_FPU* modes.
(arc_select_cc_mode): Likewise.
(arc_conditional_register_usage): Allow 64 bit datum into even-odd
register pair only. Allow access for ARCv2 accumulator.
(gen_compare_reg): Whenever we have FPU support use FPU compare
instructions.
(arc_reorg): Don't generate brcc insns when FPU compare
instructions are involved.
* config/arc/arc.h (TARGET_DPFP): Add TARGET_FP_DPAX condition.
(TARGET_OPTFPE): Add condition when ARC EM can use optimized
floating point emulation.
(ACC_REG_FIRST, ACC_REG_LAST, ACCL_REGNO, ACCH_REGNO): Define.
(REVERSE_CONDITION): Add new CC_FPU* modes.
(TARGET_FP_SP_BASE): Define.
(TARGET_FP_DP_BASE): Likewise.
(TARGET_FP_SP_FUSED): Likewise.
(TARGET_FP_DP_FUSED): Likewise.
(TARGET_FP_SP_CONV): Likewise.
(TARGET_FP_DP_CONV): Likewise.
(TARGET_FP_SP_SQRT): Likewise.
(TARGET_FP_DP_SQRT): Likewise.
(TARGET_FP_DP_AX): Likewise.
* config/arc/arc.md (ARCV2_ACC): New constant.
(type): New fpu type attribute.
(SDF): Conditional iterator.
(cstore<mode>, cbranch<mode>): Change expand condition.
(addsf3, subsf3, mulsf3, adddf3, subdf3, muldf3): New expands,
handles FPU/FPX cases as well.
* config/arc/arc.opt (mfpu): New option.
* config/arc/fpx.md (addsf3_fpx, subsf3_fpx, mulsf3_fpx):
Renamed.
(adddf3, muldf3, subdf3): Removed.
* config/arc/predicates.md (proper_comparison_operator): Recognize
CC_FPU* modes.
* config/arc/fpu.md: New file.
* doc/invoke.texi (ARC Options): Document mfpu option.

From-SVN: r233451

gcc/ChangeLog
gcc/config/arc/arc-modes.def
gcc/config/arc/arc-opts.h
gcc/config/arc/arc.c
gcc/config/arc/arc.h
gcc/config/arc/arc.md
gcc/config/arc/arc.opt
gcc/config/arc/fpu.md [new file with mode: 0644]
gcc/config/arc/fpx.md
gcc/config/arc/predicates.md
gcc/doc/invoke.texi

index a00388cafe6b7930843f06705d49c66ad98bf0cf..d41547a2da020cf85381c47d6b33e7415a90b1cd 100644 (file)
@@ -1,3 +1,46 @@
+2016-02-16  Claudiu Zissulescu  <claziss@synopsys.com>
+
+       * config/arc/arc-modes.def (CC_FPU, CC_FPU_UNEQ): New modes.
+       * config/arc/arc-opts.h (FPU_SP, FPU_SF, FPU_SC, FPU_SD, FPU_DP)
+       (FPU_DF, FPU_DC, FPU_DD, FXP_DP): Define.
+       * config/arc/arc.c (arc_init): Check FPU options.
+       (get_arc_condition_code): Handle new CC_FPU* modes.
+       (arc_select_cc_mode): Likewise.
+       (arc_conditional_register_usage): Allow 64 bit datum into even-odd
+       register pair only. Allow access for ARCv2 accumulator.
+       (gen_compare_reg): Whenever we have FPU support use FPU compare
+       instructions.
+       (arc_reorg): Don't generate brcc insns when FPU compare
+       instructions are involved.
+       * config/arc/arc.h (TARGET_DPFP): Add TARGET_FP_DPAX condition.
+       (TARGET_OPTFPE): Add condition when ARC EM can use optimized
+       floating point emulation.
+       (ACC_REG_FIRST, ACC_REG_LAST, ACCL_REGNO, ACCH_REGNO): Define.
+       (REVERSE_CONDITION): Add new CC_FPU* modes.
+       (TARGET_FP_SP_BASE): Define.
+       (TARGET_FP_DP_BASE): Likewise.
+       (TARGET_FP_SP_FUSED): Likewise.
+       (TARGET_FP_DP_FUSED): Likewise.
+       (TARGET_FP_SP_CONV): Likewise.
+       (TARGET_FP_DP_CONV): Likewise.
+       (TARGET_FP_SP_SQRT): Likewise.
+       (TARGET_FP_DP_SQRT): Likewise.
+       (TARGET_FP_DP_AX): Likewise.
+       * config/arc/arc.md (ARCV2_ACC): New constant.
+       (type): New fpu type attribute.
+       (SDF): Conditional iterator.
+       (cstore<mode>, cbranch<mode>): Change expand condition.
+       (addsf3, subsf3, mulsf3, adddf3, subdf3, muldf3): New expands,
+       handles FPU/FPX cases as well.
+       * config/arc/arc.opt (mfpu): New option.
+       * config/arc/fpx.md (addsf3_fpx, subsf3_fpx, mulsf3_fpx):
+       Renamed.
+       (adddf3, muldf3, subdf3): Removed.
+       * config/arc/predicates.md (proper_comparison_operator): Recognize
+       CC_FPU* modes.
+       * config/arc/fpu.md: New file.
+       * doc/invoke.texi (ARC Options): Document mfpu option.
+
 2016-02-16  Richard Biener  <rguenther@suse.de>
 
        PR rtl-optimization/69291
index b64a596082e9637c0199c071b080a70ce8044f39..921a59876a1956892d6b5f6c25666dbf227cdbaf 100644 (file)
@@ -35,3 +35,7 @@ CC_MODE (CC_FPX);
 VECTOR_MODES (INT, 4);        /*            V4QI V2HI */
 VECTOR_MODES (INT, 8);        /*       V8QI V4HI V2SI */
 VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
+
+/* FPU condition flags.  */
+CC_MODE (CC_FPU);
+CC_MODE (CC_FPU_UNEQ);
index 0f128850431df0d83206195c71299e44dfe2ff2a..1e11ebc41ffb226de71c5d01aaf39da55c3a071a 100644 (file)
@@ -27,3 +27,23 @@ enum processor_type
   PROCESSOR_ARCEM,
   PROCESSOR_ARCHS
 };
+
+/* Single precision floating point.  */
+#define FPU_SP    0x0001
+/* Single precision fused floating point operations.  */
+#define FPU_SF    0x0002
+/* Single precision floating point format conversion operations.  */
+#define FPU_SC    0x0004
+/* Single precision floating point sqrt and div operations.  */
+#define FPU_SD    0x0008
+/* Double precision floating point.  */
+#define FPU_DP    0x0010
+/* Double precision fused floating point operations.  */
+#define FPU_DF    0x0020
+/* Double precision floating point format conversion operations.  */
+#define FPU_DC    0x0040
+/* Double precision floating point sqrt and div operations.  */
+#define FPU_DD    0x0080
+/* Double precision floating point assist operations.  */
+#define FPX_DP    0x0100
+
index b9799a016cbedcbbd73ae3065bdd78f2053c1446..d60db502ef85eb07cca0d582a21265584e51b714 100644 (file)
@@ -719,9 +719,16 @@ arc_init (void)
 
   /* FPX-3. No FPX extensions on pre-ARC600 cores.  */
   if ((TARGET_DPFP || TARGET_SPFP)
-      && !TARGET_ARCOMPACT_FAMILY)
+      && (!TARGET_ARCOMPACT_FAMILY && !TARGET_EM))
     error ("FPX extensions not available on pre-ARC600 cores");
 
+  /* FPX-4.  No FPX extensions mixed with FPU extensions for ARC HS
+     cpus.  */
+  if ((TARGET_DPFP || TARGET_SPFP)
+      && TARGET_HARD_FLOAT
+      && TARGET_HS)
+    error ("No FPX/FPU mixing allowed");
+
   /* Only selected multiplier configurations are available for HS.  */
   if (TARGET_HS && ((arc_mpy_option > 2 && arc_mpy_option < 7)
                    || (arc_mpy_option == 1)))
@@ -743,6 +750,19 @@ arc_init (void)
   if (TARGET_LL64 && !TARGET_HS)
     error ("-mll64 is only supported for ARC HS cores");
 
+  /* FPU support only for V2.  */
+  if (TARGET_HARD_FLOAT)
+    {
+      if (TARGET_EM
+         && (arc_fpu_build & ~(FPU_SP | FPU_SF | FPU_SC | FPU_SD | FPX_DP)))
+       error ("FPU double precision options are available for ARC HS only");
+      if (TARGET_HS && (arc_fpu_build & FPX_DP))
+       error ("FPU double precision assist "
+              "options are not available for ARC HS");
+      if (!TARGET_HS && !TARGET_EM)
+       error ("FPU options are available for ARCv2 architecture only");
+    }
+
   arc_init_reg_tables ();
 
   /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P.  */
@@ -926,6 +946,33 @@ get_arc_condition_code (rtx comparison)
        case UNEQ      : return ARC_CC_LS;
        default : gcc_unreachable ();
        }
+    case CC_FPUmode:
+      switch (GET_CODE (comparison))
+       {
+       case EQ        : return ARC_CC_EQ;
+       case NE        : return ARC_CC_NE;
+       case GT        : return ARC_CC_GT;
+       case GE        : return ARC_CC_GE;
+       case LT        : return ARC_CC_C;
+       case LE        : return ARC_CC_LS;
+       case UNORDERED : return ARC_CC_V;
+       case ORDERED   : return ARC_CC_NV;
+       case UNGT      : return ARC_CC_HI;
+       case UNGE      : return ARC_CC_HS;
+       case UNLT      : return ARC_CC_LT;
+       case UNLE      : return ARC_CC_LE;
+         /* UNEQ and LTGT do not have representation.  */
+       case LTGT      : /* Fall through.  */
+       case UNEQ      : /* Fall through.  */
+       default : gcc_unreachable ();
+       }
+    case CC_FPU_UNEQmode:
+      switch (GET_CODE (comparison))
+       {
+       case LTGT : return ARC_CC_NE;
+       case UNEQ : return ARC_CC_EQ;
+       default : gcc_unreachable ();
+       }
     default : gcc_unreachable ();
     }
   /*NOTREACHED*/
@@ -1009,19 +1056,46 @@ arc_select_cc_mode (enum rtx_code op, rtx x, rtx y)
        return CC_FP_GEmode;
       default: gcc_unreachable ();
       }
-  else if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_OPTFPE)
+  else if (TARGET_HARD_FLOAT
+          && ((mode == SFmode && TARGET_FP_SP_BASE)
+              || (mode == DFmode && TARGET_FP_DP_BASE)))
     switch (op)
       {
-      case EQ: case NE: return CC_Zmode;
-      case LT: case UNGE:
-      case GT: case UNLE: return CC_FP_GTmode;
-      case LE: case UNGT:
-      case GE: case UNLT: return CC_FP_GEmode;
-      case UNEQ: case LTGT: return CC_FP_UNEQmode;
-      case ORDERED: case UNORDERED: return CC_FP_ORDmode;
-      default: gcc_unreachable ();
-      }
+      case EQ:
+      case NE:
+      case UNORDERED:
+      case ORDERED:
+      case UNLT:
+      case UNLE:
+      case UNGT:
+      case UNGE:
+      case LT:
+      case LE:
+      case GT:
+      case GE:
+       return CC_FPUmode;
+
+      case LTGT:
+      case UNEQ:
+       return CC_FPU_UNEQmode;
 
+      default:
+       gcc_unreachable ();
+      }
+  else if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_OPTFPE)
+    {
+      switch (op)
+       {
+       case EQ: case NE: return CC_Zmode;
+       case LT: case UNGE:
+       case GT: case UNLE: return CC_FP_GTmode;
+       case LE: case UNGT:
+       case GE: case UNLT: return CC_FP_GEmode;
+       case UNEQ: case LTGT: return CC_FP_UNEQmode;
+       case ORDERED: case UNORDERED: return CC_FP_ORDmode;
+       default: gcc_unreachable ();
+       }
+    }
   return CCmode;
 }
 
@@ -1148,7 +1222,8 @@ arc_init_reg_tables (void)
             we must explicitly check for them here.  */
          if (i == (int) CCmode || i == (int) CC_ZNmode || i == (int) CC_Zmode
              || i == (int) CC_Cmode
-             || i == CC_FP_GTmode || i == CC_FP_GEmode || i == CC_FP_ORDmode)
+             || i == CC_FP_GTmode || i == CC_FP_GEmode || i == CC_FP_ORDmode
+             || i == CC_FPUmode || i == CC_FPU_UNEQmode)
            arc_mode_class[i] = 1 << (int) C_MODE;
          else
            arc_mode_class[i] = 0;
@@ -1282,6 +1357,16 @@ arc_conditional_register_usage (void)
        arc_hard_regno_mode_ok[60] = 1 << (int) S_MODE;
     }
 
+  /* ARCHS has 64-bit data-path which makes use of the even-odd paired
+     registers.  */
+  if (TARGET_HS)
+    {
+      for (regno = 1; regno < 32; regno +=2)
+       {
+         arc_hard_regno_mode_ok[regno] = S_MODES;
+       }
+    }
+
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       if (i < 29)
@@ -1376,6 +1461,19 @@ arc_conditional_register_usage (void)
 
   /* pc : r63 */
   arc_regno_reg_class[PROGRAM_COUNTER_REGNO] = GENERAL_REGS;
+
+  /*ARCV2 Accumulator.  */
+  if (TARGET_V2
+      && (TARGET_FP_DP_FUSED || TARGET_FP_SP_FUSED))
+  {
+    arc_regno_reg_class[ACCL_REGNO] = WRITABLE_CORE_REGS;
+    arc_regno_reg_class[ACCH_REGNO] = WRITABLE_CORE_REGS;
+    SET_HARD_REG_BIT (reg_class_contents[WRITABLE_CORE_REGS], ACCL_REGNO);
+    SET_HARD_REG_BIT (reg_class_contents[WRITABLE_CORE_REGS], ACCH_REGNO);
+    SET_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], ACCL_REGNO);
+    SET_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], ACCH_REGNO);
+    arc_hard_regno_mode_ok[ACC_REG_FIRST] = D_MODES;
+  }
 }
 
 /* Handle an "interrupt" attribute; arguments as in
@@ -1545,6 +1643,10 @@ gen_compare_reg (rtx comparison, machine_mode omode)
                                                 gen_rtx_REG (CC_FPXmode, 61),
                                                 const0_rtx)));
     }
+  else if (TARGET_HARD_FLOAT
+          && ((cmode == SFmode && TARGET_FP_SP_BASE)
+              || (cmode == DFmode && TARGET_FP_DP_BASE)))
+    emit_insn (gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y)));
   else if (GET_MODE_CLASS (cmode) == MODE_FLOAT && TARGET_OPTFPE)
     {
       rtx op0 = gen_rtx_REG (cmode, 0);
@@ -1638,10 +1740,11 @@ arc_setup_incoming_varargs (cumulative_args_t args_so_far,
   /* We must treat `__builtin_va_alist' as an anonymous arg.  */
 
   next_cum = *get_cumulative_args (args_so_far);
-  arc_function_arg_advance (pack_cumulative_args (&next_cum), mode, type, 1);
+  arc_function_arg_advance (pack_cumulative_args (&next_cum),
+                           mode, type, true);
   first_anon_arg = next_cum;
 
-  if (first_anon_arg < MAX_ARC_PARM_REGS)
+  if (FUNCTION_ARG_REGNO_P (first_anon_arg))
     {
       /* First anonymous (unnamed) argument is in a reg.  */
 
@@ -4856,8 +4959,6 @@ arc_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
   return ret;
 }
 
-
-
 /* This function is used to control a function argument is passed in a
    register, and which register.
 
@@ -4895,8 +4996,10 @@ arc_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
    and the rest are pushed.  */
 
 static rtx
-arc_function_arg (cumulative_args_t cum_v, machine_mode mode,
-                 const_tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED)
+arc_function_arg (cumulative_args_t cum_v,
+                 machine_mode mode,
+                 const_tree type ATTRIBUTE_UNUSED,
+                 bool named ATTRIBUTE_UNUSED)
 {
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   int arg_num = *cum;
@@ -4942,8 +5045,10 @@ arc_function_arg (cumulative_args_t cum_v, machine_mode mode,
    course function_arg_partial_nregs will come into play.  */
 
 static void
-arc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
-                         const_tree type, bool named ATTRIBUTE_UNUSED)
+arc_function_arg_advance (cumulative_args_t cum_v,
+                         machine_mode mode,
+                         const_tree type,
+                         bool named ATTRIBUTE_UNUSED)
 {
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   int bytes = (mode == BLKmode
@@ -6398,6 +6503,11 @@ arc_reorg (void)
 
          pc_target = SET_SRC (pattern);
 
+         /* Avoid FPU instructions.  */
+         if ((GET_MODE (XEXP (XEXP (pc_target, 0), 0)) == CC_FPUmode)
+             || (GET_MODE (XEXP (XEXP (pc_target, 0), 0)) == CC_FPU_UNEQmode))
+           continue;
+
          /* Now go back and search for the set cc insn.  */
 
          label = XEXP (pc_target, 1);
@@ -6420,7 +6530,7 @@ arc_reorg (void)
                      break;
                    }
                }
-             if (! link_insn)
+             if (!link_insn)
                continue;
              else
                /* Check if this is a data dependency.  */
index 27665b0caa7920242fb9460ff103abab580f4165..21c049f98508d5774b8b1f0ff48f85c78952d6be 100644 (file)
@@ -255,7 +255,8 @@ along with GCC; see the file COPYING3.  If not see
 #define TARGET_MIXED_CODE (TARGET_MIXED_CODE_SET)
 
 #define TARGET_SPFP (TARGET_SPFP_FAST_SET || TARGET_SPFP_COMPACT_SET)
-#define TARGET_DPFP (TARGET_DPFP_FAST_SET || TARGET_DPFP_COMPACT_SET)
+#define TARGET_DPFP (TARGET_DPFP_FAST_SET || TARGET_DPFP_COMPACT_SET   \
+                    || TARGET_FP_DP_AX)
 
 #define SUBTARGET_SWITCHES
 
@@ -266,11 +267,12 @@ along with GCC; see the file COPYING3.  If not see
    default for A7, and only for pre A7 cores when -mnorm is given.  */
 #define TARGET_NORM (TARGET_ARC700 || TARGET_NORM_SET || TARGET_HS)
 /* Indicate if an optimized floating point emulation library is available.  */
-#define TARGET_OPTFPE \
- (TARGET_ARC700 \
-  /* We need a barrel shifter and NORM.  */ \
-  || (TARGET_ARC600 && TARGET_NORM_SET) \
-  || TARGET_HS)
+#define TARGET_OPTFPE                          \
+   (TARGET_ARC700                              \
+    /* We need a barrel shifter and NORM.  */  \
+    || (TARGET_ARC600 && TARGET_NORM_SET)      \
+    || TARGET_HS                               \
+    || (TARGET_EM && TARGET_NORM_SET && TARGET_BARREL_SHIFTER))
 
 /* Non-zero means the cpu supports swap instruction.  This flag is set by
    default for A7, and only for pre A7 cores when -mswap is given.  */
@@ -713,6 +715,12 @@ enum reg_class
 #define ARC_FIRST_SIMD_DMA_CONFIG_OUT_REG  136
 #define ARC_LAST_SIMD_DMA_CONFIG_REG       143
 
+/* ARCv2 double-register accumulator.  */
+#define ACC_REG_FIRST 58
+#define ACC_REG_LAST  59
+#define ACCL_REGNO    (TARGET_BIG_ENDIAN ? ACC_REG_FIRST + 1 : ACC_REG_FIRST)
+#define ACCH_REGNO    (TARGET_BIG_ENDIAN ? ACC_REG_FIRST : ACC_REG_FIRST + 1)
+
 /* The same information, inverted:
    Return the class number of the smallest class containing
    reg number REGNO.  This could be a conditional expression
@@ -864,7 +872,7 @@ arc_return_addr_rtx(COUNT,FRAME)
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0.  */
 #define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT,N_NAMED_ARGS) \
-((CUM) = 0)
+  ((CUM) = 0)
 
 /* The number of registers used for parameter passing.  Local to this file.  */
 #define MAX_ARC_PARM_REGS 8
@@ -1656,12 +1664,13 @@ extern enum arc_function_type arc_compute_function_type (struct function *);
    && GET_CODE (PATTERN (X)) != CLOBBER \
    && get_attr_is_##NAME (X) == IS_##NAME##_YES) \
 
-#define REVERSE_CONDITION(CODE,MODE) \
-       (((MODE) == CC_FP_GTmode || (MODE) == CC_FP_GEmode \
-         || (MODE) == CC_FP_UNEQmode || (MODE) == CC_FP_ORDmode \
-         || (MODE) == CC_FPXmode) \
-        ? reverse_condition_maybe_unordered ((CODE)) \
-        : reverse_condition ((CODE)))
+#define REVERSE_CONDITION(CODE,MODE)                            \
+  (((MODE) == CC_FP_GTmode || (MODE) == CC_FP_GEmode            \
+    || (MODE) == CC_FP_UNEQmode || (MODE) == CC_FP_ORDmode      \
+    || (MODE) == CC_FPXmode || (MODE) == CC_FPU_UNEQmode        \
+    || (MODE) == CC_FPUmode)                                    \
+   ? reverse_condition_maybe_unordered ((CODE))                         \
+   : reverse_condition ((CODE)))
 
 #define ADJUST_INSN_LENGTH(X, LENGTH) \
   ((LENGTH) \
@@ -1724,4 +1733,26 @@ enum
    been written to by an ordinary instruction.  */
 #define TARGET_LP_WR_INTERLOCK (!TARGET_ARC600_FAMILY)
 
+/* FPU defines.  */
+/* Any FPU support.  */
+#define TARGET_HARD_FLOAT (arc_fpu_build != 0)
+/* Single precision floating point support.  */
+#define TARGET_FP_SP_BASE   ((arc_fpu_build & FPU_SP) != 0)
+/* Double precision floating point support.  */
+#define TARGET_FP_DP_BASE   ((arc_fpu_build & FPU_DP) != 0)
+/* Single precision floating point support with fused operation.  */
+#define TARGET_FP_SP_FUSED  ((arc_fpu_build & FPU_SF) != 0)
+/* Double precision floating point support with fused operation.  */
+#define TARGET_FP_DP_FUSED  ((arc_fpu_build & FPU_DF) != 0)
+/* Single precision floating point conversion instruction support.  */
+#define TARGET_FP_SP_CONV   ((arc_fpu_build & FPU_SC) != 0)
+/* Double precision floating point conversion instruction support.  */
+#define TARGET_FP_DP_CONV   ((arc_fpu_build & FPU_DC) != 0)
+/* Single precision floating point SQRT/DIV instruction support.  */
+#define TARGET_FP_SP_SQRT   ((arc_fpu_build & FPU_SD) != 0)
+/* Double precision floating point SQRT/DIV instruction support.  */
+#define TARGET_FP_DP_SQRT   ((arc_fpu_build & FPU_DD) != 0)
+/* Double precision floating point assist instruction support.  */
+#define TARGET_FP_DP_AX     ((arc_fpu_build & FPX_DP) != 0)
+
 #endif /* GCC_ARC_H */
index 6a8ec83b2863f3d7f4d75335fc8895ce1f9978a8..4193d2610f19fe761ded21b055b3f6a7c24e8364 100644 (file)
    (ILINK2_REGNUM 30)
    (RETURN_ADDR_REGNUM 31)
    (MUL64_OUT_REG 58)
+   (ARCV2_ACC 58)
 
    (LP_COUNT 60)
    (CC_REG 61)
    simd_varith_with_acc, simd_vlogic, simd_vlogic_with_acc,
    simd_vcompare, simd_vpermute, simd_vpack, simd_vpack_with_acc,
    simd_valign, simd_valign_with_acc, simd_vcontrol,
-   simd_vspecial_3cycle, simd_vspecial_4cycle, simd_dma, mul16_em, div_rem"
+   simd_vspecial_3cycle, simd_vspecial_4cycle, simd_dma, mul16_em, div_rem,
+   fpu"
   (cond [(eq_attr "is_sfunc" "yes")
         (cond [(match_test "!TARGET_LONG_CALLS_SET && (!TARGET_MEDIUM_CALLS || GET_CODE (PATTERN (insn)) != COND_EXEC)") (const_string "call")
                (match_test "flag_pic") (const_string "sfunc")]
 
 })
 
-(define_mode_iterator SDF [SF DF])
+(define_mode_iterator SDF [(SF "TARGET_FP_SP_BASE || TARGET_OPTFPE")
+                          (DF "TARGET_OPTFPE")])
 
 (define_expand "cstore<mode>4"
   [(set (reg:CC CC_REG)
        (match_operator:SI 1 "comparison_operator" [(reg CC_REG)
                                                    (const_int 0)]))]
 
-  "TARGET_OPTFPE"
+  "TARGET_FP_SP_BASE || TARGET_OPTFPE"
 {
   gcc_assert (XEXP (operands[1], 0) == operands[2]);
   gcc_assert (XEXP (operands[1], 1) == operands[3]);
                    (match_operand:SDF 2 "register_operand" "")))
    (set (pc)
        (if_then_else
-             (match_operator 0 "comparison_operator" [(reg CC_REG)
-                                                      (const_int 0)])
-             (label_ref (match_operand 3 "" ""))
-             (pc)))]
+        (match_operator 0 "comparison_operator" [(reg CC_REG)
+                                                     (const_int 0)])
+        (label_ref (match_operand 3 "" ""))
+        (pc)))]
 
-  "TARGET_OPTFPE"
+  "TARGET_FP_SP_BASE || TARGET_OPTFPE"
 {
   gcc_assert (XEXP (operands[0], 0) == operands[1]);
   gcc_assert (XEXP (operands[0], 1) == operands[2]);
   [(set_attr "length" "4")
    (set_attr "type" "misc")])
 
+
+;; FPU/FPX expands
+
+;;add
+(define_expand "addsf3"
+  [(set (match_operand:SF 0 "register_operand"           "")
+       (plus:SF (match_operand:SF 1 "nonmemory_operand" "")
+                (match_operand:SF 2 "nonmemory_operand" "")))]
+  "TARGET_FP_SP_BASE || TARGET_SPFP"
+  "
+  if (!register_operand (operands[1], SFmode)
+      && !register_operand (operands[2], SFmode))
+    operands[1] = force_reg (SFmode, operands[1]);
+  ")
+
+;;sub
+(define_expand "subsf3"
+  [(set (match_operand:SF 0 "register_operand"            "")
+       (minus:SF (match_operand:SF 1 "nonmemory_operand" "")
+                 (match_operand:SF 2 "nonmemory_operand" "")))]
+  "TARGET_FP_SP_BASE || TARGET_SPFP"
+  "
+  if (!register_operand (operands[1], SFmode)
+      && !register_operand (operands[2], SFmode))
+    operands[1] = force_reg (SFmode, operands[1]);
+  ")
+
+;;mul
+(define_expand "mulsf3"
+  [(set (match_operand:SF 0 "register_operand"           "")
+       (mult:SF (match_operand:SF 1 "nonmemory_operand" "")
+                (match_operand:SF 2 "nonmemory_operand" "")))]
+  "TARGET_FP_SP_BASE || TARGET_SPFP"
+  "
+  if (!register_operand (operands[1], SFmode)
+      && !register_operand (operands[2], SFmode))
+    operands[1] = force_reg (SFmode, operands[1]);
+  ")
+
+;;add
+(define_expand "adddf3"
+  [(set (match_operand:DF 0 "double_register_operand"           "")
+       (plus:DF (match_operand:DF 1 "double_register_operand"  "")
+                (match_operand:DF 2 "nonmemory_operand" "")))]
+ "TARGET_FP_DP_BASE || TARGET_DPFP"
+ "
+  if (TARGET_DPFP)
+   {
+    if (GET_CODE (operands[2]) == CONST_DOUBLE)
+     {
+        rtx high, low, tmp;
+        split_double (operands[2], &low, &high);
+        tmp = force_reg (SImode, high);
+        emit_insn (gen_adddf3_insn (operands[0], operands[1],
+                                    operands[2], tmp, const0_rtx));
+     }
+    else
+     emit_insn (gen_adddf3_insn (operands[0], operands[1],
+                                 operands[2], const1_rtx, const1_rtx));
+   DONE;
+  }
+ else if (TARGET_FP_DP_BASE)
+  {
+   if (!even_register_operand (operands[2], DFmode))
+      operands[2] = force_reg (DFmode, operands[2]);
+
+   if (!even_register_operand (operands[1], DFmode))
+      operands[1] = force_reg (DFmode, operands[1]);
+  }
+ else
+  gcc_unreachable ();
+ ")
+
+;;sub
+(define_expand "subdf3"
+  [(set (match_operand:DF 0 "double_register_operand"            "")
+       (minus:DF (match_operand:DF 1 "nonmemory_operand" "")
+                 (match_operand:DF 2 "nonmemory_operand" "")))]
+  "TARGET_FP_DP_BASE || TARGET_DPFP"
+  "
+   if (TARGET_DPFP)
+    {
+     if ((GET_CODE (operands[1]) == CONST_DOUBLE)
+          || GET_CODE (operands[2]) == CONST_DOUBLE)
+      {
+        rtx high, low, tmp;
+        int const_index = ((GET_CODE (operands[1]) == CONST_DOUBLE) ? 1 : 2);
+        split_double (operands[const_index], &low, &high);
+        tmp = force_reg (SImode, high);
+        emit_insn (gen_subdf3_insn (operands[0], operands[1],
+                                    operands[2], tmp, const0_rtx));
+      }
+    else
+     emit_insn (gen_subdf3_insn (operands[0], operands[1],
+                                 operands[2], const1_rtx, const1_rtx));
+    DONE;
+   }
+  else if (TARGET_FP_DP_BASE)
+   {
+    if (!even_register_operand (operands[2], DFmode))
+       operands[2] = force_reg (DFmode, operands[2]);
+
+    if (!even_register_operand (operands[1], DFmode))
+       operands[1] = force_reg (DFmode, operands[1]);
+   }
+  else
+   gcc_unreachable ();
+  ")
+
+;;mul
+(define_expand "muldf3"
+  [(set (match_operand:DF 0 "double_register_operand"           "")
+       (mult:DF (match_operand:DF 1 "double_register_operand"  "")
+                (match_operand:DF 2 "nonmemory_operand" "")))]
+  "TARGET_FP_DP_BASE || TARGET_DPFP"
+  "
+   if (TARGET_DPFP)
+    {
+     if (GET_CODE (operands[2]) == CONST_DOUBLE)
+      {
+        rtx high, low, tmp;
+        split_double (operands[2], &low, &high);
+        tmp = force_reg (SImode, high);
+        emit_insn (gen_muldf3_insn (operands[0], operands[1],
+                                    operands[2], tmp, const0_rtx));
+      }
+     else
+      emit_insn (gen_muldf3_insn (operands[0], operands[1],
+                                  operands[2], const1_rtx, const1_rtx));
+    DONE;
+   }
+  else if (TARGET_FP_DP_BASE)
+   {
+    if (!even_register_operand (operands[2], DFmode))
+       operands[2] = force_reg (DFmode, operands[2]);
+
+    if (!even_register_operand (operands[1], DFmode))
+       operands[1] = force_reg (DFmode, operands[1]);
+   }
+  else
+   gcc_unreachable ();
+ ")
+
 ;; include the arc-FPX instructions
 (include "fpx.md")
 
+;; include the arc-FPU instructions
+(include "fpu.md")
+
 (include "simdext.md")
 
 ;; include atomic extensions
index 00b98d58f5431b87bde76bef24822eb699646e86..2227b7554c309e6eeb83cc437f21e5e9f3cc2bce 100644 (file)
@@ -413,3 +413,46 @@ Enable atomic instructions.
 mll64
 Target Report Mask(LL64)
 Enable double load/store instructions for ARC HS.
+
+mfpu=
+Target RejectNegative Joined Enum(arc_fpu) Var(arc_fpu_build) Init(0)
+Specify the name of the target floating point configuration.
+
+Enum
+Name(arc_fpu) Type(int)
+
+EnumValue
+Enum(arc_fpu) String(fpus) Value(FPU_SP | FPU_SC)
+
+EnumValue
+Enum(arc_fpu) String(fpud) Value(FPU_SP | FPU_SC | FPU_DP | FPU_DC)
+
+EnumValue
+Enum(arc_fpu) String(fpuda) Value(FPU_SP | FPU_SC | FPX_DP)
+
+EnumValue
+Enum(arc_fpu) String(fpuda_div) Value(FPU_SP | FPU_SC | FPU_SD | FPX_DP)
+
+EnumValue
+Enum(arc_fpu) String(fpuda_fma) Value(FPU_SP | FPU_SC | FPU_SF | FPX_DP)
+
+EnumValue
+Enum(arc_fpu) String(fpuda_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD | FPX_DP)
+
+EnumValue
+Enum(arc_fpu) String(fpus_div) Value(FPU_SP | FPU_SC | FPU_SD)
+
+EnumValue
+Enum(arc_fpu) String(fpud_div) Value(FPU_SP | FPU_SC | FPU_SD | FPU_DP | FPU_DC | FPU_DD)
+
+EnumValue
+Enum(arc_fpu) String(fpus_fma) Value(FPU_SP | FPU_SC | FPU_SF)
+
+EnumValue
+Enum(arc_fpu) String(fpud_fma) Value(FPU_SP | FPU_SC | FPU_SF | FPU_DP | FPU_DC | FPU_DF)
+
+EnumValue
+Enum(arc_fpu) String(fpus_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD)
+
+EnumValue
+Enum(arc_fpu) String(fpud_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD | FPU_DP | FPU_DC | FPU_DF | FPU_DD)
diff --git a/gcc/config/arc/fpu.md b/gcc/config/arc/fpu.md
new file mode 100644 (file)
index 0000000..9b0a65d
--- /dev/null
@@ -0,0 +1,566 @@
+;; ::::::::::::::::::::
+;; ::
+;; :: 32-bit floating point arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_insn "*addsf3_fpu"
+  [(set (match_operand:SF 0 "register_operand"           "=r,r,r,r,r")
+       (plus:SF (match_operand:SF 1 "nonmemory_operand" "%0,r,0,r,F")
+                (match_operand:SF 2 "nonmemory_operand"  "r,r,F,F,r")))]
+  "TARGET_FP_SP_BASE
+   && (register_operand (operands[1], SFmode)
+       || register_operand (operands[2], SFmode))"
+  "fsadd%? %0,%1,%2"
+  [(set_attr "length" "4,4,8,8,8")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no,yes,no,no")
+   (set_attr "cond" "canuse,nocond,canuse_limm,nocond,nocond")
+   ])
+
+;; Subtraction
+(define_insn "*subsf3_fpu"
+  [(set (match_operand:SF 0 "register_operand"           "=r,r,r,r,r")
+       (minus:SF (match_operand:SF 1 "nonmemory_operand" "0,r,0,r,F")
+                 (match_operand:SF 2 "nonmemory_operand" "r,r,F,F,r")))]
+  "TARGET_FP_SP_BASE
+   && (register_operand (operands[1], SFmode)
+       || register_operand (operands[2], SFmode))"
+  "fssub%? %0,%1,%2"
+  [(set_attr "length" "4,4,8,8,8")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no,yes,no,no")
+   (set_attr "cond" "canuse,nocond,canuse_limm,nocond,nocond")
+   ])
+
+;; Multiplication
+(define_insn "*mulsf3_fpu"
+  [(set (match_operand:SF 0 "register_operand"           "=r,r,r,r,r")
+       (mult:SF (match_operand:SF 1 "nonmemory_operand" "%0,r,0,r,F")
+                (match_operand:SF 2 "nonmemory_operand"  "r,r,F,F,r")))]
+  "TARGET_FP_SP_BASE
+   && (register_operand (operands[1], SFmode)
+       || register_operand (operands[2], SFmode))"
+  "fsmul%? %0,%1,%2"
+  [(set_attr "length" "4,4,8,8,8")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no,yes,no,no")
+   (set_attr "cond" "canuse,nocond,canuse_limm,nocond,nocond")
+   ])
+
+;; Multiplication with addition/subtraction
+(define_expand "fmasf4"
+  [(set (match_operand:SF 0 "register_operand" "")
+       (fma:SF (match_operand:SF 1 "nonmemory_operand" "")
+               (match_operand:SF 2 "nonmemory_operand" "")
+               (match_operand:SF 3 "nonmemory_operand" "")))]
+  "TARGET_FP_SP_FUSED"
+  "{
+   rtx tmp;
+   tmp = gen_rtx_REG (SFmode, ACCL_REGNO);
+   emit_move_insn (tmp, operands[3]);
+   operands[3] = tmp;
+   }")
+
+(define_expand "fnmasf4"
+  [(set (match_operand:SF 0 "register_operand" "")
+       (fma:SF (neg:SF (match_operand:SF 1 "nonmemory_operand" ""))
+               (match_operand:SF 2 "nonmemory_operand"         "")
+               (match_operand:SF 3 "nonmemory_operand"         "")))]
+  "TARGET_FP_SP_FUSED"
+  "{
+   rtx tmp;
+   tmp = gen_rtx_REG (SFmode, ACCL_REGNO);
+   emit_move_insn (tmp, operands[3]);
+   operands[3] = tmp;
+}")
+
+(define_insn "fmasf4_fpu"
+  [(set (match_operand:SF 0 "register_operand"          "=r,r,r,r,r")
+       (fma:SF (match_operand:SF 1 "nonmemory_operand" "%0,r,0,r,F")
+               (match_operand:SF 2 "nonmemory_operand"  "r,r,F,F,r")
+               (match_operand:SF 3 "mlo_operand" "")))]
+  "TARGET_FP_SP_FUSED
+   && (register_operand (operands[1], SFmode)
+       || register_operand (operands[2], SFmode))"
+  "fsmadd%? %0,%1,%2"
+  [(set_attr "length" "4,4,8,8,8")
+   (set_attr "predicable" "yes,no,yes,no,no")
+   (set_attr "cond" "canuse,nocond,canuse_limm,nocond,nocond")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")])
+
+(define_insn "fnmasf4_fpu"
+  [(set (match_operand:SF 0 "register_operand"                  "=r,r,r,r,r")
+       (fma:SF (neg:SF (match_operand:SF 1 "nonmemory_operand" "%0,r,0,r,F"))
+               (match_operand:SF 2 "nonmemory_operand"          "r,r,F,F,r")
+               (match_operand:SF 3 "mlo_operand" "")))]
+  "TARGET_FP_SP_FUSED
+   && (register_operand (operands[1], SFmode)
+       || register_operand (operands[2], SFmode))"
+  "fsmsub%? %0,%1,%2"
+  [(set_attr "length" "4,4,8,8,8")
+   (set_attr "predicable" "yes,no,yes,no,no")
+   (set_attr "cond" "canuse,nocond,canuse_limm,nocond,nocond")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")])
+
+(define_expand "fmadf4"
+  [(match_operand:DF 0 "even_register_operand" "")
+   (match_operand:DF 1 "even_register_operand" "")
+   (match_operand:DF 2 "even_register_operand" "")
+   (match_operand:DF 3 "even_register_operand" "")]
+  "TARGET_FP_DP_FUSED"
+  "{
+   emit_insn (gen_fmadf4_split (operands[0], operands[1], operands[2], operands[3]));
+   DONE;
+   }")
+
+(define_insn_and_split "fmadf4_split"
+  [(set (match_operand:DF 0 "even_register_operand"        "")
+       (fma:DF (match_operand:DF 1 "even_register_operand" "")
+               (match_operand:DF 2 "even_register_operand" "")
+               (match_operand:DF 3 "even_register_operand" "")))
+   (clobber (reg:DF ARCV2_ACC))]
+  "TARGET_FP_DP_FUSED"
+  "#"
+  "TARGET_FP_DP_FUSED"
+  [(const_int 0)]
+  "{
+   rtx acc_reg = gen_rtx_REG (DFmode, ACC_REG_FIRST);
+   emit_move_insn (acc_reg, operands[3]);
+   emit_insn (gen_fmadf4_fpu (operands[0], operands[1], operands[2]));
+   DONE;
+  }"
+)
+
+(define_expand "fnmadf4"
+  [(match_operand:DF 0 "even_register_operand" "")
+   (match_operand:DF 1 "even_register_operand" "")
+   (match_operand:DF 2 "even_register_operand" "")
+   (match_operand:DF 3 "even_register_operand" "")]
+  "TARGET_FP_DP_FUSED"
+  "{
+   emit_insn (gen_fnmadf4_split (operands[0], operands[1], operands[2], operands[3]));
+   DONE;
+   }")
+
+(define_insn_and_split "fnmadf4_split"
+  [(set (match_operand:DF 0 "even_register_operand"                 "")
+       (fma:DF (neg:DF (match_operand:DF 1 "even_register_operand" ""))
+               (match_operand:DF 2 "even_register_operand"         "")
+               (match_operand:DF 3 "even_register_operand"         "")))
+   (clobber (reg:DF ARCV2_ACC))]
+  "TARGET_FP_DP_FUSED"
+  "#"
+  "TARGET_FP_DP_FUSED"
+  [(const_int 0)]
+  "{
+   rtx acc_reg = gen_rtx_REG (DFmode, ACC_REG_FIRST);
+   emit_move_insn (acc_reg, operands[3]);
+   emit_insn (gen_fnmadf4_fpu (operands[0], operands[1], operands[2]));
+   DONE;
+  }")
+
+(define_insn "fmadf4_fpu"
+  [(set (match_operand:DF 0 "even_register_operand"         "=r,r")
+       (fma:DF (match_operand:DF 1 "even_register_operand" "%0,r")
+               (match_operand:DF 2 "even_register_operand"  "r,r")
+               (reg:DF ARCV2_ACC)))]
+  "TARGET_FP_DP_FUSED"
+  "fdmadd%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+   (set_attr "predicable" "yes,no")
+   (set_attr "cond" "canuse,nocond")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")])
+
+(define_insn "fnmadf4_fpu"
+  [(set (match_operand:DF 0 "even_register_operand"                 "=r,r")
+       (fma:DF (neg:DF (match_operand:DF 1 "even_register_operand" "%0,r"))
+               (match_operand:DF 2 "even_register_operand"          "r,r")
+               (reg:DF ARCV2_ACC)))]
+  "TARGET_FP_DP_FUSED"
+  "fdmsub%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+   (set_attr "predicable" "yes,no")
+   (set_attr "cond" "canuse,nocond")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")])
+
+;; Division
+(define_insn "divsf3"
+  [(set (match_operand:SF 0 "register_operand"         "=r,r,r,r,r")
+       (div:SF (match_operand:SF 1 "nonmemory_operand" "0,r,0,r,F")
+               (match_operand:SF 2 "nonmemory_operand" "r,r,F,F,r")))]
+  "TARGET_FP_SP_SQRT"
+  "fsdiv%? %0,%1,%2"
+  [(set_attr "length" "4,4,8,8,8")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no,yes,no,no")
+   (set_attr "cond" "canuse,nocond,canuse_limm,nocond,nocond")
+   ])
+
+;; Negation
+;; see pattern in arc.md
+
+;; Absolute value
+;; see pattern in arc.md
+
+;; Square root
+(define_insn "sqrtsf2"
+  [(set (match_operand:SF 0 "register_operand"           "=r,r")
+       (sqrt:SF (match_operand:SF 1 "nonmemory_operand"  "r,F")))]
+  "TARGET_FP_SP_SQRT"
+  "fssqrt %0,%1"
+  [(set_attr "length" "4,8")
+   (set_attr "type" "fpu")])
+
+;; Comparison
+(define_insn "*cmpsf_fpu"
+  [(set (reg:CC_FPU CC_REG)
+       (compare:CC_FPU (match_operand:SF 0 "register_operand"  "r,r")
+                       (match_operand:SF 1 "nonmemory_operand" "r,F")))]
+  "TARGET_FP_SP_BASE"
+  "fscmp%? %0, %1"
+  [(set_attr "length" "4,8")
+   (set_attr "iscompact" "false")
+   (set_attr "cond" "set")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,yes")])
+
+(define_insn "*cmpsf_fpu_uneq"
+  [(set (reg:CC_FPU_UNEQ CC_REG)
+       (compare:CC_FPU_UNEQ
+        (match_operand:SF 0 "register_operand"  "r,r")
+        (match_operand:SF 1 "nonmemory_operand" "r,F")))]
+  "TARGET_FP_SP_BASE"
+  "fscmp %0, %1\\n\\tmov.v.f 0,0\\t;set Z flag"
+  [(set_attr "length" "8,12")
+   (set_attr "iscompact" "false")
+   (set_attr "cond" "set")
+   (set_attr "type" "fpu")])
+
+;; ::::::::::::::::::::
+;; ::
+;; :: 64-bit floating point arithmetic
+;; ::
+;; ::::::::::::::::::::
+
+;; Addition
+(define_insn "*adddf3_fpu"
+  [(set (match_operand:DF 0 "even_register_operand"           "=r,r")
+       (plus:DF (match_operand:DF 1 "even_register_operand"  "%0,r")
+                (match_operand:DF 2 "even_register_operand"   "r,r")))]
+  "TARGET_FP_DP_BASE"
+  "fdadd%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")
+   (set_attr "cond" "canuse,nocond")
+   ])
+
+
+;; Subtraction
+(define_insn "*subdf3_fpu"
+  [(set (match_operand:DF 0 "even_register_operand"           "=r,r")
+       (minus:DF (match_operand:DF 1 "even_register_operand"  "0,r")
+                 (match_operand:DF 2 "even_register_operand"  "r,r")))]
+  "TARGET_FP_DP_BASE"
+  "fdsub%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")
+   (set_attr "cond" "canuse,nocond")
+   ])
+
+;; Multiplication
+(define_insn "*muldf3_fpu"
+  [(set (match_operand:DF 0 "even_register_operand"           "=r,r")
+       (mult:DF (match_operand:DF 1 "even_register_operand"  "%0,r")
+                (match_operand:DF 2 "even_register_operand"   "r,r")))]
+  "TARGET_FP_DP_BASE"
+  "fdmul%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")
+   (set_attr "cond" "canuse,nocond")
+   ])
+
+;; Division
+(define_insn "divdf3"
+  [(set (match_operand:DF 0 "even_register_operand"         "=r,r")
+       (div:DF (match_operand:DF 1 "even_register_operand"  "0,r")
+               (match_operand:DF 2 "even_register_operand"  "r,r")))]
+  "TARGET_FP_DP_SQRT"
+  "fddiv%? %0,%1,%2"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")
+   (set_attr "cond" "canuse,nocond")
+   ])
+
+;; Square root
+(define_insn "sqrtdf2"
+  [(set (match_operand:DF 0 "even_register_operand"          "=r")
+       (sqrt:DF (match_operand:DF 1 "even_register_operand"  "r")))]
+  "TARGET_FP_DP_SQRT"
+  "fdsqrt %0,%1"
+  [(set_attr "length" "4")
+   (set_attr "type" "fpu")])
+
+;; Comparison
+(define_insn "*cmpdf_fpu"
+  [(set (reg:CC_FPU CC_REG)
+       (compare:CC_FPU (match_operand:DF 0 "even_register_operand"  "r")
+                       (match_operand:DF 1 "even_register_operand"  "r")))]
+  "TARGET_FP_DP_BASE"
+  "fdcmp%? %0, %1"
+  [(set_attr "length" "4")
+   (set_attr "iscompact" "false")
+   (set_attr "cond" "set")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes")])
+
+(define_insn "*cmpdf_fpu_uneq"
+  [(set (reg:CC_FPU_UNEQ CC_REG)
+       (compare:CC_FPU_UNEQ
+        (match_operand:DF 0 "even_register_operand"  "r")
+        (match_operand:DF 1 "even_register_operand"  "r")))]
+  "TARGET_FP_DP_BASE"
+  "fdcmp %0, %1\\n\\tmov.v.f 0,0\\t;set Z flag"
+  [(set_attr "length" "8")
+   (set_attr "iscompact" "false")
+   (set_attr "cond" "set")
+   (set_attr "type" "fpu")])
+
+;; ::::::::::::::::::::
+;; ::
+;; :: Conversion routines
+;; ::
+;; ::::::::::::::::::::
+
+;; SF->DF
+(define_insn "extendsfdf2"
+  [(set (match_operand:DF 0 "even_register_operand"             "=r,r")
+       (float_extend:DF (match_operand:SF 1 "register_operand"  "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt32_64%? %0,%1,0x04\\t;fs2d %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; SI->DF
+(define_insn "floatsidf2"
+  [(set (match_operand:DF 0 "even_register_operand"      "=r,r")
+       (float:DF (match_operand:SI 1 "register_operand"  "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt32_64%? %0,%1,0x02\\t;fint2d %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; uSI->DF
+(define_insn "floatunssidf2"
+  [(set (match_operand:DF 0 "even_register_operand"               "=r,r")
+       (unsigned_float:DF (match_operand:SI 1 "register_operand"  "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt32_64%? %0,%1,0x00\\t;fuint2d %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; SF->uDI (using rounding towards zero)
+(define_insn "fixuns_truncsfdi2"
+  [(set (match_operand:DI 0 "even_register_operand"                    "=r,r")
+       (unsigned_fix:DI (fix:SF (match_operand:SF 1 "register_operand" "0,r"))))]
+  "TARGET_FP_DP_CONV"
+  "fcvt32_64%? %0,%1,0x09\\t;fs2ul_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; SF->DI (using rounding towards zero)
+(define_insn "fix_truncsfdi2"
+  [(set (match_operand:DI 0 "even_register_operand"           "=r,r")
+       (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "0,r"))))]
+  "TARGET_FP_DP_CONV"
+  "fcvt32_64%? %0,%1,0x0B\\t;fs2l_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; SI->SF
+(define_insn "floatsisf2"
+  [(set (match_operand:SF 0 "register_operand"           "=r,r")
+       (float:SF (match_operand:SI 1 "register_operand"  "0,r")))]
+  "TARGET_FP_SP_CONV"
+  "fcvt32%? %0,%1,0x02\\t;fint2s %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; uSI->SF
+(define_insn "floatunssisf2"
+  [(set (match_operand:SF 0 "register_operand"                    "=r,r")
+       (unsigned_float:SF (match_operand:SI 1 "register_operand"  "0,r")))]
+  "TARGET_FP_SP_CONV"
+  "fcvt32%? %0,%1,0x00\\t;fuint2s %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; SF->uSI (using rounding towards zero)
+(define_insn "fixuns_truncsfsi2"
+  [(set (match_operand:SI 0 "register_operand"                         "=r,r")
+       (unsigned_fix:SI (fix:SF (match_operand:SF 1 "register_operand" "0,r"))))]
+  "TARGET_FP_SP_CONV"
+  "fcvt32%? %0,%1,0x09\\t;fs2uint_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; SF->SI (using rounding towards zero)
+(define_insn "fix_truncsfsi2"
+  [(set (match_operand:SI 0 "register_operand"                "=r,r")
+       (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "0,r"))))]
+  "TARGET_FP_SP_CONV"
+  "fcvt32%? %0,%1,0x0B\\t;fs2int_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DI->DF
+(define_insn "floatdidf2"
+  [(set (match_operand:DF 0 "even_register_operand"          "=r,r")
+       (float:DF (match_operand:DI 1 "even_register_operand" "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64%? %0,%1,0x02\\t;fl2d %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; uDI->DF
+(define_insn "floatunsdidf2"
+  [(set (match_operand:DF 0 "even_register_operand"                   "=r,r")
+       (unsigned_float:DF (match_operand:DI 1 "even_register_operand" "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64%? %0,%1,0x00\\t;ful2d %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DF->uDI (using rounding towards zero)
+(define_insn "fixuns_truncdfdi2"
+  [(set (match_operand:DI 0 "even_register_operand"                         "=r,r")
+       (unsigned_fix:DI (fix:DF (match_operand:DF 1 "even_register_operand" "0,r"))))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64%? %0,%1,0x09\\t;fd2ul_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DF->DI (using rounding towards zero)
+(define_insn "fix_truncdfdi2"
+  [(set (match_operand:DI 0 "even_register_operand"                "=r,r")
+       (fix:DI (fix:DF (match_operand:DF 1 "even_register_operand" "0,r"))))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64%? %0,%1,0x0B\\t;fd2l_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DF->SF
+(define_insn "truncdfsf2"
+  [(set (match_operand:SF 0 "register_operand"                        "=r,r")
+       (float_truncate:SF (match_operand:DF 1 "even_register_operand" "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64_32%? %0,%1,0x04\\t;fd2s %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DI->SF
+(define_insn "floatdisf2"
+  [(set (match_operand:SF 0 "register_operand"               "=r,r")
+       (float:SF (match_operand:DI 1 "even_register_operand" "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64_32%? %0,%1,0x02\\t;fl2s %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; uDI->SF
+(define_insn "floatunsdisf2"
+  [(set (match_operand:SF 0 "register_operand"                        "=r,r")
+       (unsigned_float:SF (match_operand:DI 1 "even_register_operand" "0,r")))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64_32%? %0,%1,0x00\\t;ful2s %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DF->uSI (using rounding towards zero)
+(define_insn "fixuns_truncdfsi2"
+  [(set (match_operand:SI 0 "register_operand"                              "=r,r")
+       (unsigned_fix:SI (fix:DF (match_operand:DF 1 "even_register_operand" "0,r"))))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64_32%? %0,%1,0x09\\t;fd2uint_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
+
+;; DF->SI (using rounding towards zero)
+(define_insn "fix_truncdfsi2"
+  [(set (match_operand:SI 0 "register_operand"                     "=r,r")
+       (fix:SI (fix:DF (match_operand:DF 1 "even_register_operand" "0,r"))))]
+  "TARGET_FP_DP_CONV"
+  "fcvt64_32%? %0,%1,0x0B\\t;fd2int_rz %0,%1"
+  [(set_attr "length" "4,4")
+   (set_attr "iscompact" "false")
+   (set_attr "type" "fpu")
+   (set_attr "predicable" "yes,no")]
+)
index a4ecc4a9bf2564f3b6620119eb33dd829ecaa6e7..b7906003748955960f38a20f7a53d5947ed2c56b 100644 (file)
@@ -50,7 +50,7 @@
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(define_insn "addsf3"
+(define_insn "*addsf3_fpx"
   [(set (match_operand:SF 0 "register_operand"          "=r,r,r,r,r ")
        (plus:SF (match_operand:SF 1 "nonmemory_operand" "0,r,GCal,r,0")
                 (match_operand:SF 2 "nonmemory_operand" "I,rL,r,GCal,LrCal")))]
@@ -65,7 +65,7 @@
   [(set_attr "type" "spfp")
   (set_attr "length" "4,4,8,8,8")])
 
-(define_insn "subsf3"
+(define_insn "*subsf3_fpx"
   [(set (match_operand:SF 0 "register_operand"          "=r,r,r,r,r ")
        (minus:SF (match_operand:SF 1 "nonmemory_operand" "r,0,GCal,r,0")
                 (match_operand:SF 2 "nonmemory_operand" "rL,I,r,GCal,LrCal")))]
@@ -80,7 +80,7 @@
   [(set_attr "type" "spfp")
   (set_attr "length" "4,4,8,8,8")])
 
-(define_insn "mulsf3"
+(define_insn "*mulsf3_fpx"
   [(set (match_operand:SF 0 "register_operand"          "=r,r,r,r,r ")
        (mult:SF (match_operand:SF 1 "nonmemory_operand" "r,0,GCal,r,0")
                 (match_operand:SF 2 "nonmemory_operand" "rL,I,r,GCal,LrCal")))]
 ;; daddh{0}{1} 0, {reg_pair}2.hi, {reg_pair}2.lo
 ;; OR
 ;; daddh{0}{1} 0, reg3, limm2.lo
-(define_expand "adddf3"
-  [(set (match_operand:DF 0 "arc_double_register_operand"          "")
-       (plus:DF (match_operand:DF 1 "arc_double_register_operand" "")
-                (match_operand:DF 2 "nonmemory_operand" "")))
-     ]
- "TARGET_DPFP"
- " if (GET_CODE (operands[2]) == CONST_DOUBLE)
-     {
-        rtx high, low, tmp;
-        split_double (operands[2], &low, &high);
-        tmp = force_reg (SImode, high);
-        emit_insn(gen_adddf3_insn(operands[0], operands[1], operands[2],tmp,const0_rtx));
-     }
-   else
-     emit_insn(gen_adddf3_insn(operands[0], operands[1], operands[2],const1_rtx,const1_rtx));
-     DONE;
- "
-)
-
 ;; daddh{0}{1} 0, {reg_pair}2.hi, {reg_pair}2.lo  /* operand 4 = 1*/
 ;; OR
 ;; daddh{0}{1} 0, reg3, limm2.lo /* operand 4 = 0 */
 ;; dmulh{0}{1} 0, {reg_pair}2.hi, {reg_pair}2.lo
 ;; OR
 ;; dmulh{0}{1} 0, reg3, limm2.lo
-(define_expand "muldf3"
-  [(set (match_operand:DF 0 "arc_double_register_operand"          "")
-       (mult:DF (match_operand:DF 1 "arc_double_register_operand" "")
-                (match_operand:DF 2 "nonmemory_operand" "")))]
-"TARGET_DPFP"
-"  if (GET_CODE (operands[2]) == CONST_DOUBLE)
-     {
-        rtx high, low, tmp;
-        split_double (operands[2], &low, &high);
-        tmp = force_reg (SImode, high);
-        emit_insn(gen_muldf3_insn(operands[0], operands[1], operands[2],tmp,const0_rtx));
-     }
-   else
-     emit_insn(gen_muldf3_insn(operands[0], operands[1], operands[2],const1_rtx,const1_rtx));
-
-  DONE;
- ")
-
-
 ;; dmulh{0}{1} 0, {reg_pair}2.hi, {reg_pair}2.lo /* operand 4 = 1*/
 ;; OR
 ;; dmulh{0}{1} 0, reg3, limm2.lo /* operand 4 = 0*/
 ;; drsubh{0}{2} 0, {reg_pair}1.hi, {reg_pair}1.lo
 ;; OR
 ;; drsubh{0}{2} 0, reg3, limm1.lo
-(define_expand "subdf3"
-  [(set (match_operand:DF 0 "arc_double_register_operand"          "")
-                   (minus:DF (match_operand:DF 1 "nonmemory_operand" "")
-                                 (match_operand:DF 2 "nonmemory_operand" "")))]
-"TARGET_DPFP"
-"   if (GET_CODE (operands[1]) == CONST_DOUBLE || GET_CODE (operands[2]) == CONST_DOUBLE)
-     {
-        rtx high, low, tmp;
-        int const_index = ((GET_CODE (operands[1]) == CONST_DOUBLE) ? 1: 2);
-        split_double (operands[const_index], &low, &high);
-        tmp = force_reg (SImode, high);
-        emit_insn(gen_subdf3_insn(operands[0], operands[1], operands[2],tmp,const0_rtx));
-     }
-   else
-     emit_insn(gen_subdf3_insn(operands[0], operands[1], operands[2],const1_rtx,const1_rtx));
-
-   DONE;
-  "
-)
-
 ;; dsubh{0}{1} 0, {reg_pair}2.hi, {reg_pair}2.lo /* operand 4 = 1 */
 ;; OR
 ;; dsubh{0}{1} 0, reg3, limm2.lo /* operand 4 = 0*/
index d384d70f7d6fb17af3dadd59c6e387e1fcc8f9dd..85bbf8435588fcd0dc12cd5de6852ee8911c0f7b 100644 (file)
       return (code == EQ || code == NE || code == UNEQ || code == LTGT
              || code == ORDERED || code == UNORDERED);
 
+    case CC_FPUmode:
+      return 1;
+    case CC_FPU_UNEQmode:
+      return 1;
+
     case CCmode:
     case SImode: /* Used for BRcc.  */
       return 1;
    return (REG_P (op) && ((REGNO (op) >= FIRST_PSEUDO_REGISTER)
                          || ((REGNO (op) & 1) == 0)));
   })
+
+(define_predicate "double_register_operand"
+  (ior (match_test "even_register_operand (op, mode)")
+       (match_test "arc_double_register_operand (op, mode)")))
index 666d976f7c4474e4b601834cea4e76bf5ad19b7e..85f222117affdf6abcb251bea6f662ac70c3ba31 100644 (file)
@@ -599,7 +599,7 @@ Objective-C and Objective-C++ Dialects}.
 -mmixed-code -mq-class -mRcq -mRcw -msize-level=@var{level} @gol
 -mtune=@var{cpu} -mmultcost=@var{num} @gol
 -munalign-prob-threshold=@var{probability} -mmpy-option=@var{multo} @gol
--mdiv-rem -mcode-density -mll64}
+-mdiv-rem -mcode-density -mll64 -mfpu=@var{fpu}}
 
 @emph{ARM Options}
 @gccoptlist{-mapcs-frame  -mno-apcs-frame @gol
@@ -13325,6 +13325,88 @@ MPYU, MPYM, MPYMU, and MPY_S.
 
 This option is only available for ARCv2 cores@.
 
+@item -mfpu=@var{fpu}
+@opindex mfpu
+Enables specific floating-point hardware extension for ARCv2
+core.  Supported values for @var{fpu} are:
+
+@table @samp
+
+@item fpus
+@opindex fpus
+Enables support for single precision floating point hardware
+extensions@.
+
+@item fpud
+@opindex fpud
+Enables support for double precision floating point hardware
+extensions.  The single precision floating point extension is also
+enabled.  Not available for ARC EM@.
+
+@item fpuda
+@opindex fpuda
+Enables support for double precision floating point hardware
+extensions using double precision assist instructions.  The single
+precision floating point extension is also enabled.  This option is
+only available for ARC EM@.
+
+@item fpuda_div
+@opindex fpuda_div
+Enables support for double precision floating point hardware
+extensions using double precision assist instructions, and simple
+precision square-root and divide hardware extensions.  The single
+precision floating point extension is also enabled.  This option is
+only available for ARC EM@.
+
+@item fpuda_fma
+@opindex fpuda_fma
+Enables support for double precision floating point hardware
+extensions using double precision assist instructions, and simple
+precision fused multiple and add hardware extension.  The single
+precision floating point extension is also enabled.  This option is
+only available for ARC EM@.
+
+@item fpuda_all
+@opindex fpuda_all
+Enables support for double precision floating point hardware
+extensions using double precision assist instructions, and all simple
+precision hardware extensions.  The single precision floating point
+extension is also enabled.  This option is only available for ARC EM@.
+
+@item fpus_div
+@opindex fpus_div
+Enables support for single precision floating point, and single
+precision square-root and divide hardware extensions@.
+
+@item fpud_div
+@opindex fpud_div
+Enables support for double precision floating point, and double
+precision square-root and divide hardware extensions.  This option
+includes option @samp{fpus_div}. Not available for ARC EM@.
+
+@item fpus_fma
+@opindex fpus_fma
+Enables support for single precision floating point, and single
+precision fused multiple and add hardware extensions@.
+
+@item fpud_fma
+@opindex fpud_fma
+Enables support for double precision floating point, and double
+precision fused multiple and add hardware extensions.  This option
+includes option @samp{fpus_fma}.  Not available for ARC EM@.
+
+@item fpus_all
+@opindex fpus_all
+Enables support for all single precision floating point hardware
+extensions@.
+
+@item fpud_all
+@opindex fpud_all
+Enables support for all single and double precision floating point
+hardware extensions.  Not available for ARC EM@.
+
+@end table
+
 @end table
 
 The following options are passed through to the assembler, and also