OSDN Git Service

2009-11-09 Paul Brook <paul@codesourcery.com>
authorpbrook <pbrook@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 9 Nov 2009 13:50:38 +0000 (13:50 +0000)
committerpbrook <pbrook@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 9 Nov 2009 13:50:38 +0000 (13:50 +0000)
Daniel Jacobowitz  <dan@codesourcery.com>
Sandra Loosemore  <sandra@codesourcery.com>

gcc/
* doc/extend.texi (Half-Precision): Update wording to reflect
that there are now multiple -mfpu options that enable fp16
hardware support.
* doc/invoke.texi: Update list of ARM -mfpu= options.
* config.gcc: Update ARM --with-fpu option list.
* config/arm/arm.c (all_fpus): Add vfpv3-fp16, vfpv3-d16-fp16,
vfpv3xd and vfpv3xd-fp16.
(use_vfp_abi): New function.
(aapcs_vfp_is_call_or_return_candidate): Avoid double precision regs
when undesirable.
(aapcs_vfp_is_return_candidate, aapcs_vfp_is_call_candidate,
aapcs_vfp_allocate_return_reg): Use use_vfp_abi.
        (arm_rtx_costs_1, arm_size_rtx_costs, arm_fastmul_rtx_costs,
        arm_9e_rtx_costs): Only expect double-precision operations if the FPU
        provides them.
(coproc_secondary_reload_class): Reload HFmode via GENERAL_REGS if no
NEON.
(arm_print_operand): Handle 'p' modifier.
(arm_hard_regno_mode_ok): : Allow HFmode in VFP registers if
TARGET_FP16.
* config/arm/arm.h (TARGET_VFP_SINGLE, TARGET_VFP_DOUBLE): Define.
(TARGET_FP16): Define.
* config/arm/vfp.md: Disable double-precision patterns if the FPU
does not provide them.
(arm_movdi_vfp, thumb2_movdi_vfp): Use fcpys to move
double-precision values on a single-precision FPU.
        (movdf_vfp, thumb2_movdf_vfp): Likewise.  Use "Dy" for
        double-precision constants.
(movhf_vfp_neon): New pattern (was movhf_vfp).
(movhf_vfp): Remove NEON instructions.
* config/arm/constraints.md: Add new "Dy" constraint for
double-precision constants.  Update description of "Dv".
* config/arm/arm.md: Disable double-precision patterns if the FPU
does not provide them

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

gcc/ChangeLog
gcc/config.gcc
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/constraints.md
gcc/config/arm/vfp.md
gcc/doc/extend.texi
gcc/doc/invoke.texi

index 8301826..b6d48d8 100644 (file)
@@ -1,3 +1,42 @@
+2009-11-09  Paul Brook  <paul@codesourcery.com>
+       Daniel Jacobowitz  <dan@codesourcery.com>
+       Sandra Loosemore  <sandra@codesourcery.com>
+
+       * doc/extend.texi (Half-Precision): Update wording to reflect
+       that there are now multiple -mfpu options that enable fp16
+       hardware support.
+       * doc/invoke.texi: Update list of ARM -mfpu= options.
+       * config.gcc: Update ARM --with-fpu option list.
+       * config/arm/arm.c (all_fpus): Add vfpv3-fp16, vfpv3-d16-fp16,
+       vfpv3xd and vfpv3xd-fp16.
+       (use_vfp_abi): New function.
+       (aapcs_vfp_is_call_or_return_candidate): Avoid double precision regs
+       when undesirable.
+       (aapcs_vfp_is_return_candidate, aapcs_vfp_is_call_candidate,
+       aapcs_vfp_allocate_return_reg): Use use_vfp_abi.
+        (arm_rtx_costs_1, arm_size_rtx_costs, arm_fastmul_rtx_costs,
+        arm_9e_rtx_costs): Only expect double-precision operations if the FPU
+        provides them.
+       (coproc_secondary_reload_class): Reload HFmode via GENERAL_REGS if no
+       NEON.
+       (arm_print_operand): Handle 'p' modifier.
+       (arm_hard_regno_mode_ok): : Allow HFmode in VFP registers if
+       TARGET_FP16.
+       * config/arm/arm.h (TARGET_VFP_SINGLE, TARGET_VFP_DOUBLE): Define.
+       (TARGET_FP16): Define.
+       * config/arm/vfp.md: Disable double-precision patterns if the FPU
+       does not provide them.
+       (arm_movdi_vfp, thumb2_movdi_vfp): Use fcpys to move
+       double-precision values on a single-precision FPU.
+        (movdf_vfp, thumb2_movdf_vfp): Likewise.  Use "Dy" for
+        double-precision constants.
+       (movhf_vfp_neon): New pattern (was movhf_vfp).
+       (movhf_vfp): Remove NEON instructions.
+       * config/arm/constraints.md: Add new "Dy" constraint for
+       double-precision constants.  Update description of "Dv".
+       * config/arm/arm.md: Disable double-precision patterns if the FPU
+       does not provide them
+
 2009-11-09  Jakub Jelinek  <jakub@redhat.com>
 
        * config/i386/i386.c (print_operand) <case 'D'>: Fix formatting.
 2009-11-09  Jakub Jelinek  <jakub@redhat.com>
 
        * config/i386/i386.c (print_operand) <case 'D'>: Fix formatting.
index 1d3c3fc..999ba21 100644 (file)
@@ -2817,7 +2817,7 @@ case "${target}" in
 
                case "$with_fpu" in
                "" \
 
                case "$with_fpu" in
                "" \
-               | fpa | fpe2 | fpe3 | maverick | vfp | vfp3 | neon )
+               | fpa | fpe2 | fpe3 | maverick | vfp | vfp3 | vfpv3 | vfpv3-fp16 | vfpv3-d16 | vfpv3-d16-fp16 | vfpv3xd | vfpv3xd-fp16 | neon | neon-fp16 )
                        # OK
                        ;;
                *)
                        # OK
                        ;;
                *)
index 4c7fcb6..205bff2 100644 (file)
@@ -816,7 +816,11 @@ static const struct arm_fpu_desc all_fpus[] =
   {"maverick",         ARM_FP_MODEL_MAVERICK, 0, 0, false, false},
   {"vfp",              ARM_FP_MODEL_VFP, 2, VFP_REG_D16, false, false},
   {"vfpv3",            ARM_FP_MODEL_VFP, 3, VFP_REG_D32, false, false},
   {"maverick",         ARM_FP_MODEL_MAVERICK, 0, 0, false, false},
   {"vfp",              ARM_FP_MODEL_VFP, 2, VFP_REG_D16, false, false},
   {"vfpv3",            ARM_FP_MODEL_VFP, 3, VFP_REG_D32, false, false},
+  {"vfpv3-fp16",       ARM_FP_MODEL_VFP, 3, VFP_REG_D32, false, true},
   {"vfpv3-d16",                ARM_FP_MODEL_VFP, 3, VFP_REG_D16, false, false},
   {"vfpv3-d16",                ARM_FP_MODEL_VFP, 3, VFP_REG_D16, false, false},
+  {"vfpv3-d16-fp16",   ARM_FP_MODEL_VFP, 3, VFP_REG_D16, false, true},
+  {"vfpv3xd",          ARM_FP_MODEL_VFP, 3, VFP_REG_SINGLE, false, false},
+  {"vfpv3xd-fp16",     ARM_FP_MODEL_VFP, 3, VFP_REG_SINGLE, false, true},
   {"neon",             ARM_FP_MODEL_VFP, 3, VFP_REG_D32, true , false},
   {"neon-fp16",                ARM_FP_MODEL_VFP, 3, VFP_REG_D32, true , true },
   /* Compatibility aliases.  */
   {"neon",             ARM_FP_MODEL_VFP, 3, VFP_REG_D32, true , false},
   {"neon-fp16",                ARM_FP_MODEL_VFP, 3, VFP_REG_D32, true , true },
   /* Compatibility aliases.  */
@@ -3817,38 +3821,57 @@ aapcs_vfp_sub_candidate (const_tree type, enum machine_mode *modep)
   return -1;
 }
 
   return -1;
 }
 
+/* Return true if PCS_VARIANT should use VFP registers.  */
 static bool
 static bool
-aapcs_vfp_is_call_or_return_candidate (enum machine_mode mode, const_tree type,
-                                      enum machine_mode *base_mode,
-                                      int *count)
+use_vfp_abi (enum arm_pcs pcs_variant, bool is_double)
 {
 {
+  if (pcs_variant == ARM_PCS_AAPCS_VFP)
+    return true;
+
+  if (pcs_variant != ARM_PCS_AAPCS_LOCAL)
+    return false;
+
+  return (TARGET_32BIT && TARGET_VFP && TARGET_HARD_FLOAT &&
+         (TARGET_VFP_DOUBLE || !is_double));
+}
+
+static bool
+aapcs_vfp_is_call_or_return_candidate (enum arm_pcs pcs_variant,
+                                      enum machine_mode mode, const_tree type,
+                                      int *base_mode, int *count)
+{
+  enum machine_mode new_mode = VOIDmode;
+
   if (GET_MODE_CLASS (mode) == MODE_FLOAT
       || GET_MODE_CLASS (mode) == MODE_VECTOR_INT
       || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
     {
       *count = 1;
   if (GET_MODE_CLASS (mode) == MODE_FLOAT
       || GET_MODE_CLASS (mode) == MODE_VECTOR_INT
       || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
     {
       *count = 1;
-      *base_mode = mode;
-      return true;
+      new_mode = mode;
     }
   else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
     {
       *count = 2;
     }
   else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
     {
       *count = 2;
-      *base_mode = (mode == DCmode ? DFmode : SFmode);
-      return true;
+      new_mode = (mode == DCmode ? DFmode : SFmode);
     }
   else if (type && (mode == BLKmode || TREE_CODE (type) == VECTOR_TYPE))
     {
     }
   else if (type && (mode == BLKmode || TREE_CODE (type) == VECTOR_TYPE))
     {
-      enum machine_mode aggregate_mode = VOIDmode;
-      int ag_count = aapcs_vfp_sub_candidate (type, &aggregate_mode);
+      int ag_count = aapcs_vfp_sub_candidate (type, &new_mode);
 
       if (ag_count > 0 && ag_count <= 4)
 
       if (ag_count > 0 && ag_count <= 4)
-       {
-         *count = ag_count;
-         *base_mode = aggregate_mode;
-         return true;
-       }
+       *count = ag_count;
+      else
+       return false;
     }
     }
-  return false;
+  else
+    return false;
+
+
+  if (!use_vfp_abi (pcs_variant, ARM_NUM_REGS (new_mode) > 1))
+    return false;
+
+  *base_mode = new_mode;
+  return true;
 }
 
 static bool
 }
 
 static bool
@@ -3858,22 +3881,20 @@ aapcs_vfp_is_return_candidate (enum arm_pcs pcs_variant,
   int count ATTRIBUTE_UNUSED;
   enum machine_mode ag_mode ATTRIBUTE_UNUSED;
 
   int count ATTRIBUTE_UNUSED;
   enum machine_mode ag_mode ATTRIBUTE_UNUSED;
 
-  if (!(pcs_variant == ARM_PCS_AAPCS_VFP
-       || (pcs_variant == ARM_PCS_AAPCS_LOCAL
-           && TARGET_32BIT && TARGET_VFP && TARGET_HARD_FLOAT)))
+  if (!use_vfp_abi (pcs_variant, false))
     return false;
     return false;
-  return aapcs_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &count);
+  return aapcs_vfp_is_call_or_return_candidate (pcs_variant, mode, type,
+                                               &ag_mode, &count);
 }
 
 static bool
 aapcs_vfp_is_call_candidate (CUMULATIVE_ARGS *pcum, enum machine_mode mode, 
                             const_tree type)
 {
 }
 
 static bool
 aapcs_vfp_is_call_candidate (CUMULATIVE_ARGS *pcum, enum machine_mode mode, 
                             const_tree type)
 {
-  if (!(pcum->pcs_variant == ARM_PCS_AAPCS_VFP
-       || (pcum->pcs_variant == ARM_PCS_AAPCS_LOCAL
-           && TARGET_32BIT && TARGET_VFP && TARGET_HARD_FLOAT)))
+  if (!use_vfp_abi (pcum->pcs_variant, false))
     return false;
     return false;
-  return aapcs_vfp_is_call_or_return_candidate (mode, type,
+
+  return aapcs_vfp_is_call_or_return_candidate (pcum->pcs_variant, mode, type,
                                                &pcum->aapcs_vfp_rmode,
                                                &pcum->aapcs_vfp_rcount);
 }
                                                &pcum->aapcs_vfp_rmode,
                                                &pcum->aapcs_vfp_rcount);
 }
@@ -3934,10 +3955,9 @@ aapcs_vfp_allocate_return_reg (enum arm_pcs pcs_variant ATTRIBUTE_UNUSED,
                               enum machine_mode mode,
                               const_tree type ATTRIBUTE_UNUSED)
 {
                               enum machine_mode mode,
                               const_tree type ATTRIBUTE_UNUSED)
 {
-  if (!(pcs_variant == ARM_PCS_AAPCS_VFP
-       || (pcs_variant == ARM_PCS_AAPCS_LOCAL
-           && TARGET_32BIT && TARGET_VFP && TARGET_HARD_FLOAT)))
+  if (!use_vfp_abi (pcs_variant, false))
     return false;
     return false;
+
   if (mode == BLKmode || (mode == TImode && !TARGET_NEON))
     {
       int count;
   if (mode == BLKmode || (mode == TImode && !TARGET_NEON))
     {
       int count;
@@ -3946,7 +3966,8 @@ aapcs_vfp_allocate_return_reg (enum arm_pcs pcs_variant ATTRIBUTE_UNUSED,
       rtx par;
       int shift;
       
       rtx par;
       int shift;
       
-      aapcs_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &count);
+      aapcs_vfp_is_call_or_return_candidate (pcs_variant, mode, type,
+                                            &ag_mode, &count);
 
       if (!TARGET_NEON)
        {
 
       if (!TARGET_NEON)
        {
@@ -6316,7 +6337,7 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
     case UMOD:
       if (TARGET_HARD_FLOAT && mode == SFmode)
        *total = COSTS_N_INSNS (2);
     case UMOD:
       if (TARGET_HARD_FLOAT && mode == SFmode)
        *total = COSTS_N_INSNS (2);
-      else if (TARGET_HARD_FLOAT && mode == DFmode)
+      else if (TARGET_HARD_FLOAT && mode == DFmode && !TARGET_VFP_SINGLE)
        *total = COSTS_N_INSNS (4);
       else
        *total = COSTS_N_INSNS (20);
        *total = COSTS_N_INSNS (4);
       else
        *total = COSTS_N_INSNS (20);
@@ -6394,7 +6415,9 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
-         if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode))
+         if (TARGET_HARD_FLOAT
+             && (mode == SFmode
+                 || (mode == DFmode && !TARGET_VFP_SINGLE)))
            {
              *total = COSTS_N_INSNS (1);
              if (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
            {
              *total = COSTS_N_INSNS (1);
              if (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
@@ -6489,7 +6512,9 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
-         if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode))
+         if (TARGET_HARD_FLOAT
+             && (mode == SFmode
+                 || (mode == DFmode && !TARGET_VFP_SINGLE)))
            {
              *total = COSTS_N_INSNS (1);
              if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
            {
              *total = COSTS_N_INSNS (1);
              if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
@@ -6602,7 +6627,9 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
     case NEG:
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
     case NEG:
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
-         if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode))
+         if (TARGET_HARD_FLOAT
+             && (mode == SFmode
+                 || (mode == DFmode && !TARGET_VFP_SINGLE)))
            {
              *total = COSTS_N_INSNS (1);
              return false;
            {
              *total = COSTS_N_INSNS (1);
              return false;
@@ -6751,7 +6778,9 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
     case ABS:
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
     case ABS:
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
-         if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode))
+         if (TARGET_HARD_FLOAT
+             && (mode == SFmode
+                 || (mode == DFmode && !TARGET_VFP_SINGLE)))
            {
              *total = COSTS_N_INSNS (1);
              return false;
            {
              *total = COSTS_N_INSNS (1);
              return false;
@@ -6854,7 +6883,8 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
       return true;
 
     case CONST_DOUBLE:
       return true;
 
     case CONST_DOUBLE:
-      if (TARGET_HARD_FLOAT && vfp3_const_double_rtx (x))
+      if (TARGET_HARD_FLOAT && vfp3_const_double_rtx (x)
+         && (mode == SFmode || !TARGET_VFP_SINGLE))
        *total = COSTS_N_INSNS (1);
       else
        *total = COSTS_N_INSNS (4);
        *total = COSTS_N_INSNS (1);
       else
        *total = COSTS_N_INSNS (4);
@@ -6929,7 +6959,8 @@ arm_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       return false;
 
     case MINUS:
       return false;
 
     case MINUS:
-      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
+         && (mode == SFmode || !TARGET_VFP_SINGLE))
        {
          *total = COSTS_N_INSNS (1);
          return false;
        {
          *total = COSTS_N_INSNS (1);
          return false;
@@ -6959,7 +6990,8 @@ arm_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       return false;
 
     case PLUS:
       return false;
 
     case PLUS:
-      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
+         && (mode == SFmode || !TARGET_VFP_SINGLE))
        {
          *total = COSTS_N_INSNS (1);
          return false;
        {
          *total = COSTS_N_INSNS (1);
          return false;
@@ -6999,7 +7031,8 @@ arm_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       return false;
 
     case NEG:
       return false;
 
     case NEG:
-      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
+         && (mode == SFmode || !TARGET_VFP_SINGLE))
        {
          *total = COSTS_N_INSNS (1);
          return false;
        {
          *total = COSTS_N_INSNS (1);
          return false;
@@ -7023,7 +7056,8 @@ arm_size_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
       return false;
 
     case ABS:
       return false;
 
     case ABS:
-      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+      if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT
+         && (mode == SFmode || !TARGET_VFP_SINGLE))
        *total = COSTS_N_INSNS (1);
       else
        *total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
        *total = COSTS_N_INSNS (1);
       else
        *total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
@@ -7245,7 +7279,9 @@ arm_fastmul_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
-         if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode))
+         if (TARGET_HARD_FLOAT
+             && (mode == SFmode
+                 || (mode == DFmode && !TARGET_VFP_SINGLE)))
            {
              *total = COSTS_N_INSNS (1);
              return false;
            {
              *total = COSTS_N_INSNS (1);
              return false;
@@ -7402,7 +7438,9 @@ arm_9e_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        {
-         if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode))
+         if (TARGET_HARD_FLOAT
+             && (mode == SFmode
+                 || (mode == DFmode && !TARGET_VFP_SINGLE)))
            {
              *total = COSTS_N_INSNS (1);
              return false;
            {
              *total = COSTS_N_INSNS (1);
              return false;
@@ -8341,6 +8379,8 @@ coproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
 {
   if (mode == HFmode)
     {
 {
   if (mode == HFmode)
     {
+      if (!TARGET_NEON_FP16)
+       return GENERAL_REGS;
       if (s_register_operand (x, mode) || neon_vector_mem_operand (x, 2))
        return NO_REGS;
       return GENERAL_REGS;
       if (s_register_operand (x, mode) || neon_vector_mem_operand (x, 2))
        return NO_REGS;
       return GENERAL_REGS;
@@ -15055,6 +15095,30 @@ arm_print_operand (FILE *stream, rtx x, int code)
        }
       return;
 
        }
       return;
 
+    /* Print the high single-precision register of a VFP double-precision
+       register.  */
+    case 'p':
+      {
+        int mode = GET_MODE (x);
+        int regno;
+
+        if (GET_MODE_SIZE (mode) != 8 || GET_CODE (x) != REG)
+          {
+           output_operand_lossage ("invalid operand for code '%c'", code);
+           return;
+          }
+
+        regno = REGNO (x);
+        if (!VFP_REGNO_OK_FOR_DOUBLE (regno))
+          {
+           output_operand_lossage ("invalid operand for code '%c'", code);
+           return;
+          }
+
+       fprintf (stream, "s%d", regno - FIRST_VFP_REGNUM + 1);
+      }
+      return;
+
     /* Print a VFP/Neon double precision or quad precision register name.  */
     case 'P':
     case 'q':
     /* Print a VFP/Neon double precision or quad precision register name.  */
     case 'P':
     case 'q':
@@ -15973,10 +16037,9 @@ arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
        return VFP_REGNO_OK_FOR_DOUBLE (regno);
 
       /* VFP registers can hold HFmode values, but there is no point in
        return VFP_REGNO_OK_FOR_DOUBLE (regno);
 
       /* VFP registers can hold HFmode values, but there is no point in
-        putting them there unless we have the NEON extensions for
-        loading/storing them, too.  */
+        putting them there unless we have hardware conversion insns. */
       if (mode == HFmode)
       if (mode == HFmode)
-       return TARGET_NEON_FP16 && VFP_REGNO_OK_FOR_SINGLE (regno);
+       return TARGET_FP16 && VFP_REGNO_OK_FOR_SINGLE (regno);
 
       if (TARGET_NEON)
         return (VALID_NEON_DREG_MODE (mode) && VFP_REGNO_OK_FOR_DOUBLE (regno))
 
       if (TARGET_NEON)
         return (VALID_NEON_DREG_MODE (mode) && VFP_REGNO_OK_FOR_DOUBLE (regno))
index 2dfd22d..65d6708 100644 (file)
@@ -230,10 +230,19 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
 /* FPU supports VFPv3 instructions.  */
 #define TARGET_VFP3 (TARGET_VFP && arm_fpu_desc->rev >= 3)
 
 /* FPU supports VFPv3 instructions.  */
 #define TARGET_VFP3 (TARGET_VFP && arm_fpu_desc->rev >= 3)
 
-/* FPU supports NEON/VFP half-precision floating-point.  */
+/* FPU only supports VFP single-precision instructions.  */
+#define TARGET_VFP_SINGLE (TARGET_VFP && arm_fpu_desc->regs == VFP_REG_SINGLE)
+
+/* FPU supports VFP double-precision instructions.  */
+#define TARGET_VFP_DOUBLE (TARGET_VFP && arm_fpu_desc->regs != VFP_REG_SINGLE)
+
+/* FPU supports half-precision floating-point with NEON element load/store.  */
 #define TARGET_NEON_FP16 \
   (TARGET_VFP && arm_fpu_desc->neon && arm_fpu_desc->fp16)
 
 #define TARGET_NEON_FP16 \
   (TARGET_VFP && arm_fpu_desc->neon && arm_fpu_desc->fp16)
 
+/* FPU supports VFP half-precision floating-point.  */
+#define TARGET_FP16 (TARGET_VFP && arm_fpu_desc->fp16)
+
 /* FPU supports Neon instructions.  The setting of this macro gets
    revealed via __ARM_NEON__ so we add extra guards upon TARGET_32BIT
    and TARGET_HARD_FLOAT to ensure that NEON instructions are
 /* FPU supports Neon instructions.  The setting of this macro gets
    revealed via __ARM_NEON__ so we add extra guards upon TARGET_32BIT
    and TARGET_HARD_FLOAT to ensure that NEON instructions are
index 52edcba..691bd55 100644 (file)
   [(set (match_operand:DF          0 "s_register_operand" "")
        (plus:DF (match_operand:DF 1 "s_register_operand" "")
                 (match_operand:DF 2 "arm_float_add_operand" "")))]
   [(set (match_operand:DF          0 "s_register_operand" "")
        (plus:DF (match_operand:DF 1 "s_register_operand" "")
                 (match_operand:DF 2 "arm_float_add_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "
   if (TARGET_MAVERICK
       && !cirrus_fp_register (operands[2], DFmode))
   "
   if (TARGET_MAVERICK
       && !cirrus_fp_register (operands[2], DFmode))
   [(set (match_operand:DF           0 "s_register_operand" "")
        (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
                  (match_operand:DF 2 "arm_float_rhs_operand" "")))]
   [(set (match_operand:DF           0 "s_register_operand" "")
        (minus:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
                  (match_operand:DF 2 "arm_float_rhs_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "
   if (TARGET_MAVERICK)
     {
   "
   if (TARGET_MAVERICK)
     {
   [(set (match_operand:DF          0 "s_register_operand" "")
        (mult:DF (match_operand:DF 1 "s_register_operand" "")
                 (match_operand:DF 2 "arm_float_rhs_operand" "")))]
   [(set (match_operand:DF          0 "s_register_operand" "")
        (mult:DF (match_operand:DF 1 "s_register_operand" "")
                 (match_operand:DF 2 "arm_float_rhs_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "
   if (TARGET_MAVERICK
       && !cirrus_fp_register (operands[2], DFmode))
   "
   if (TARGET_MAVERICK
       && !cirrus_fp_register (operands[2], DFmode))
   [(set (match_operand:DF 0 "s_register_operand" "")
        (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
                (match_operand:DF 2 "arm_float_rhs_operand" "")))]
   [(set (match_operand:DF 0 "s_register_operand" "")
        (div:DF (match_operand:DF 1 "arm_float_rhs_operand" "")
                (match_operand:DF 2 "arm_float_rhs_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP_DOUBLE)"
   "")
 \f
 ;; Modulo insns
   "")
 \f
 ;; Modulo insns
 (define_expand "negdf2"
   [(set (match_operand:DF         0 "s_register_operand" "")
        (neg:DF (match_operand:DF 1 "s_register_operand" "")))]
 (define_expand "negdf2"
   [(set (match_operand:DF         0 "s_register_operand" "")
        (neg:DF (match_operand:DF 1 "s_register_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP_DOUBLE)"
   "")
 
 ;; abssi2 doesn't really clobber the condition codes if a different register
   "")
 
 ;; abssi2 doesn't really clobber the condition codes if a different register
 (define_expand "absdf2"
   [(set (match_operand:DF         0 "s_register_operand" "")
        (abs:DF (match_operand:DF 1 "s_register_operand" "")))]
 (define_expand "absdf2"
   [(set (match_operand:DF         0 "s_register_operand" "")
        (abs:DF (match_operand:DF 1 "s_register_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "")
 
 (define_expand "sqrtsf2"
   "")
 
 (define_expand "sqrtsf2"
 (define_expand "sqrtdf2"
   [(set (match_operand:DF 0 "s_register_operand" "")
        (sqrt:DF (match_operand:DF 1 "s_register_operand" "")))]
 (define_expand "sqrtdf2"
   [(set (match_operand:DF 0 "s_register_operand" "")
        (sqrt:DF (match_operand:DF 1 "s_register_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP_DOUBLE)"
   "")
 
 (define_insn_and_split "one_cmpldi2"
   "")
 
 (define_insn_and_split "one_cmpldi2"
 (define_expand "floatsidf2"
   [(set (match_operand:DF           0 "s_register_operand" "")
        (float:DF (match_operand:SI 1 "s_register_operand" "")))]
 (define_expand "floatsidf2"
   [(set (match_operand:DF           0 "s_register_operand" "")
        (float:DF (match_operand:SI 1 "s_register_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "
   if (TARGET_MAVERICK)
     {
   "
   if (TARGET_MAVERICK)
     {
 (define_expand "fix_truncdfsi2"
   [(set (match_operand:SI         0 "s_register_operand" "")
        (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand"  ""))))]
 (define_expand "fix_truncdfsi2"
   [(set (match_operand:SI         0 "s_register_operand" "")
        (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand"  ""))))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "
   if (TARGET_MAVERICK)
     {
   "
   if (TARGET_MAVERICK)
     {
   [(set (match_operand:SF  0 "s_register_operand" "")
        (float_truncate:SF
         (match_operand:DF 1 "s_register_operand" "")))]
   [(set (match_operand:SF  0 "s_register_operand" "")
        (float_truncate:SF
         (match_operand:DF 1 "s_register_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   ""
 )
 
   ""
 )
 
 (define_expand "extendsfdf2"
   [(set (match_operand:DF                  0 "s_register_operand" "")
        (float_extend:DF (match_operand:SF 1 "s_register_operand"  "")))]
 (define_expand "extendsfdf2"
   [(set (match_operand:DF                  0 "s_register_operand" "")
        (float_extend:DF (match_operand:SF 1 "s_register_operand"  "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   ""
 )
 
   ""
 )
 
 (define_insn "*arm32_movhf"
   [(set (match_operand:HF 0 "nonimmediate_operand" "=r,m,r,r")
        (match_operand:HF 1 "general_operand"      " m,r,r,F"))]
 (define_insn "*arm32_movhf"
   [(set (match_operand:HF 0 "nonimmediate_operand" "=r,m,r,r")
        (match_operand:HF 1 "general_operand"      " m,r,r,F"))]
-  "TARGET_32BIT && !(TARGET_HARD_FLOAT && TARGET_NEON_FP16)
+  "TARGET_32BIT && !(TARGET_HARD_FLOAT && TARGET_FP16)
    && (          s_register_operand (operands[0], HFmode)
        || s_register_operand (operands[1], HFmode))"
   "*
    && (          s_register_operand (operands[0], HFmode)
        || s_register_operand (operands[1], HFmode))"
   "*
                (match_operand:DF 2 "arm_float_compare_operand" "")])
              (label_ref (match_operand 3 "" ""))
              (pc)))]
                (match_operand:DF 2 "arm_float_compare_operand" "")])
              (label_ref (match_operand 3 "" ""))
              (pc)))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
   "emit_jump_insn (gen_cbranch_cc (operands[0], operands[1], operands[2],
                                   operands[3])); DONE;"
 )
   "emit_jump_insn (gen_cbranch_cc (operands[0], operands[1], operands[2],
                                   operands[3])); DONE;"
 )
        (if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
                         (match_operand:DF 2 "s_register_operand" "")
                         (match_operand:DF 3 "arm_float_add_operand" "")))]
        (if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
                         (match_operand:DF 2 "s_register_operand" "")
                         (match_operand:DF 3 "arm_float_add_operand" "")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP)"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP_DOUBLE)"
   "
   {
     enum rtx_code code = GET_CODE (operands[1]);
   "
   {
     enum rtx_code code = GET_CODE (operands[1]);
index edb0215..c40d695 100644 (file)
@@ -29,7 +29,7 @@
 ;; in Thumb-1 state: I, J, K, L, M, N, O
 
 ;; The following multi-letter normal constraints have been used:
 ;; in Thumb-1 state: I, J, K, L, M, N, O
 
 ;; The following multi-letter normal constraints have been used:
-;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv
+;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy
 ;; in Thumb-1 state: Pa, Pb
 
 ;; The following memory constraints have been used:
 ;; in Thumb-1 state: Pa, Pb
 
 ;; The following memory constraints have been used:
 (define_constraint "Dv"
  "@internal
   In ARM/Thumb-2 state a const_double which can be used with a VFP fconsts
 (define_constraint "Dv"
  "@internal
   In ARM/Thumb-2 state a const_double which can be used with a VFP fconsts
-  or fconstd instruction."
+  instruction."
  (and (match_code "const_double")
       (match_test "TARGET_32BIT && vfp3_const_double_rtx (op)")))
 
  (and (match_code "const_double")
       (match_test "TARGET_32BIT && vfp3_const_double_rtx (op)")))
 
+(define_constraint "Dy"
+ "@internal
+  In ARM/Thumb-2 state a const_double which can be used with a VFP fconstd
+  instruction."
+ (and (match_code "const_double")
+      (match_test "TARGET_32BIT && TARGET_VFP_DOUBLE && vfp3_const_double_rtx (op)")))
+
 (define_memory_constraint "Ut"
  "@internal
   In ARM/Thumb-2 state an address valid for loading/storing opaque structure
 (define_memory_constraint "Ut"
  "@internal
   In ARM/Thumb-2 state an address valid for loading/storing opaque structure
index 77c99d2..57c2192 100644 (file)
     case 4:
       return \"fmrrd%?\\t%Q0, %R0, %P1\\t%@ int\";
     case 5:
     case 4:
       return \"fmrrd%?\\t%Q0, %R0, %P1\\t%@ int\";
     case 5:
-      return \"fcpyd%?\\t%P0, %P1\\t%@ int\";
+      if (TARGET_VFP_SINGLE)
+       return \"fcpys%?\\t%0, %1\\t%@ int\;fcpys%?\\t%p0, %p1\\t%@ int\";
+      else
+       return \"fcpyd%?\\t%P0, %P1\\t%@ int\";
     case 6: case 7:
       return output_move_vfp (operands);
     default:
     case 6: case 7:
       return output_move_vfp (operands);
     default:
     }
   "
   [(set_attr "type" "*,load2,store2,r_2_f,f_2_r,ffarithd,f_loadd,f_stored")
     }
   "
   [(set_attr "type" "*,load2,store2,r_2_f,f_2_r,ffarithd,f_loadd,f_stored")
-   (set_attr "length" "8,8,8,4,4,4,4,4")
+   (set (attr "length") (cond [(eq_attr "alternative" "0,1,2") (const_int 8)
+                              (eq_attr "alternative" "5")
+                               (if_then_else
+                                (eq (symbol_ref "TARGET_VFP_SINGLE")
+                                    (const_int 1))
+                                (const_int 8)
+                                (const_int 4))]
+                             (const_int 4)))
    (set_attr "predicable"    "yes")
    (set_attr "pool_range"     "*,1020,*,*,*,*,1020,*")
    (set_attr "neg_pool_range" "*,1008,*,*,*,*,1008,*")]
    (set_attr "predicable"    "yes")
    (set_attr "pool_range"     "*,1020,*,*,*,*,1020,*")
    (set_attr "neg_pool_range" "*,1008,*,*,*,*,1008,*")]
     case 4:
       return \"fmrrd%?\\t%Q0, %R0, %P1\\t%@ int\";
     case 5:
     case 4:
       return \"fmrrd%?\\t%Q0, %R0, %P1\\t%@ int\";
     case 5:
-      return \"fcpyd%?\\t%P0, %P1\\t%@ int\";
+      if (TARGET_VFP_SINGLE)
+       return \"fcpys%?\\t%0, %1\\t%@ int\;fcpys%?\\t%p0, %p1\\t%@ int\";
+      else
+       return \"fcpyd%?\\t%P0, %P1\\t%@ int\";
     case 6: case 7:
       return output_move_vfp (operands);
     default:
     case 6: case 7:
       return output_move_vfp (operands);
     default:
     }
   "
   [(set_attr "type" "*,load2,store2,r_2_f,f_2_r,ffarithd,f_load,f_store")
     }
   "
   [(set_attr "type" "*,load2,store2,r_2_f,f_2_r,ffarithd,f_load,f_store")
-   (set_attr "length" "8,8,8,4,4,4,4,4")
+   (set (attr "length") (cond [(eq_attr "alternative" "0,1,2") (const_int 8)
+                              (eq_attr "alternative" "5")
+                               (if_then_else
+                                (eq (symbol_ref "TARGET_VFP_SINGLE")
+                                    (const_int 1))
+                                (const_int 8)
+                                (const_int 4))]
+                             (const_int 4)))
    (set_attr "pool_range"     "*,4096,*,*,*,*,1020,*")
    (set_attr "neg_pool_range" "*,   0,*,*,*,*,1008,*")]
 )
 
 ;; HFmode moves
    (set_attr "pool_range"     "*,4096,*,*,*,*,1020,*")
    (set_attr "neg_pool_range" "*,   0,*,*,*,*,1008,*")]
 )
 
 ;; HFmode moves
-(define_insn "*movhf_vfp"
+(define_insn "*movhf_vfp_neon"
   [(set (match_operand:HF 0 "nonimmediate_operand" "= t,Um,r,m,t,r,t,r,r")
        (match_operand:HF 1 "general_operand"      " Um, t,m,r,t,r,r,t,F"))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_NEON_FP16
   [(set (match_operand:HF 0 "nonimmediate_operand" "= t,Um,r,m,t,r,t,r,r")
        (match_operand:HF 1 "general_operand"      " Um, t,m,r,t,r,r,t,F"))]
   "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_NEON_FP16
    (set_attr "length" "4,4,4,4,4,4,4,4,8")]
 )
 
    (set_attr "length" "4,4,4,4,4,4,4,4,8")]
 )
 
+;; FP16 without element load/store instructions.
+(define_insn "*movhf_vfp"
+  [(set (match_operand:HF 0 "nonimmediate_operand" "=r,m,t,r,t,r,r")
+       (match_operand:HF 1 "general_operand"      " m,r,t,r,r,t,F"))]
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_FP16 && !TARGET_NEON_FP16
+   && (   s_register_operand (operands[0], HFmode)
+       || s_register_operand (operands[1], HFmode))"
+  "*
+  switch (which_alternative)
+    {
+    case 0:     /* ARM register from memory */
+      return \"ldrh\\t%0, %1\\t%@ __fp16\";
+    case 1:     /* memory from ARM register */
+      return \"strh\\t%1, %0\\t%@ __fp16\";
+    case 2:    /* S register from S register */
+      return \"fcpys\\t%0, %1\";
+    case 3:    /* ARM register from ARM register */
+      return \"mov\\t%0, %1\\t%@ __fp16\";
+    case 4:    /* S register from ARM register */
+      return \"fmsr\\t%0, %1\";
+    case 5:    /* ARM register from S register */
+      return \"fmrs\\t%0, %1\";
+    case 6:    /* ARM register from constant */
+      {
+        REAL_VALUE_TYPE r;
+       long bits;
+       rtx ops[4];
+
+        REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
+       bits = real_to_target (NULL, &r, HFmode);
+       ops[0] = operands[0];
+       ops[1] = GEN_INT (bits);
+       ops[2] = GEN_INT (bits & 0xff00);
+       ops[3] = GEN_INT (bits & 0x00ff);
+
+       if (arm_arch_thumb2)
+         output_asm_insn (\"movw\\t%0, %1\", ops);
+       else
+         output_asm_insn (\"mov\\t%0, %2\;orr\\t%0, %0, %3\", ops);
+       return \"\";
+       }
+    default:
+      gcc_unreachable ();
+    }
+  "
+  [(set_attr "conds" "unconditional")
+   (set_attr "type" "load1,store1,fcpys,*,r_2_f,f_2_r,*")
+   (set_attr "length" "4,4,4,4,4,4,8")]
+)
+
 
 ;; SFmode moves
 ;; Disparage the w<->r cases because reloading an invalid address is
 
 ;; SFmode moves
 ;; Disparage the w<->r cases because reloading an invalid address is
 
 (define_insn "*movdf_vfp"
   [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,r, m,w  ,Uv,w,r")
 
 (define_insn "*movdf_vfp"
   [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,r, m,w  ,Uv,w,r")
-       (match_operand:DF 1 "soft_df_operand"              " ?r,w,Dv,mF,r,UvF,w, w,r"))]
+       (match_operand:DF 1 "soft_df_operand"              " ?r,w,Dy,mF,r,UvF,w, w,r"))]
   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
    && (   register_operand (operands[0], DFmode)
        || register_operand (operands[1], DFmode))"
   "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
    && (   register_operand (operands[0], DFmode)
        || register_operand (operands[1], DFmode))"
       case 1:
        return \"fmrrd%?\\t%Q0, %R0, %P1\";
       case 2:
       case 1:
        return \"fmrrd%?\\t%Q0, %R0, %P1\";
       case 2:
+       gcc_assert (TARGET_VFP_DOUBLE);
         return \"fconstd%?\\t%P0, #%G1\";
       case 3: case 4:
        return output_move_double (operands);
       case 5: case 6:
        return output_move_vfp (operands);
       case 7:
         return \"fconstd%?\\t%P0, #%G1\";
       case 3: case 4:
        return output_move_double (operands);
       case 5: case 6:
        return output_move_vfp (operands);
       case 7:
-       return \"fcpyd%?\\t%P0, %P1\";
+       if (TARGET_VFP_SINGLE)
+         return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";
+       else
+         return \"fcpyd%?\\t%P0, %P1\";
       case 8:
         return \"#\";
       default:
       case 8:
         return \"#\";
       default:
   "
   [(set_attr "type"
      "r_2_f,f_2_r,fconstd,f_loadd,f_stored,load2,store2,ffarithd,*")
   "
   [(set_attr "type"
      "r_2_f,f_2_r,fconstd,f_loadd,f_stored,load2,store2,ffarithd,*")
-   (set_attr "length" "4,4,4,8,8,4,4,4,8")
+   (set (attr "length") (cond [(eq_attr "alternative" "3,4,8") (const_int 8)
+                              (eq_attr "alternative" "7")
+                               (if_then_else
+                                (eq (symbol_ref "TARGET_VFP_SINGLE")
+                                    (const_int 1))
+                                (const_int 8)
+                                (const_int 4))]
+                             (const_int 4)))
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "*,*,*,1020,*,1020,*,*,*")
    (set_attr "neg_pool_range" "*,*,*,1008,*,1008,*,*,*")]
    (set_attr "predicable" "yes")
    (set_attr "pool_range" "*,*,*,1020,*,1020,*,*,*")
    (set_attr "neg_pool_range" "*,*,*,1008,*,1008,*,*,*")]
 
 (define_insn "*thumb2_movdf_vfp"
   [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,r, m,w  ,Uv,w,r")
 
 (define_insn "*thumb2_movdf_vfp"
   [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,r, m,w  ,Uv,w,r")
-       (match_operand:DF 1 "soft_df_operand"              " ?r,w,Dv,mF,r,UvF,w, w,r"))]
+       (match_operand:DF 1 "soft_df_operand"              " ?r,w,Dy,mF,r,UvF,w, w,r"))]
   "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP"
   "*
   {
   "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP"
   "*
   {
       case 1:
        return \"fmrrd%?\\t%Q0, %R0, %P1\";
       case 2:
       case 1:
        return \"fmrrd%?\\t%Q0, %R0, %P1\";
       case 2:
+       gcc_assert (TARGET_VFP_DOUBLE);
        return \"fconstd%?\\t%P0, #%G1\";
       case 3: case 4: case 8:
        return output_move_double (operands);
       case 5: case 6:
        return output_move_vfp (operands);
       case 7:
        return \"fconstd%?\\t%P0, #%G1\";
       case 3: case 4: case 8:
        return output_move_double (operands);
       case 5: case 6:
        return output_move_vfp (operands);
       case 7:
-       return \"fcpyd%?\\t%P0, %P1\";
+       if (TARGET_VFP_SINGLE)
+         return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";
+       else
+         return \"fcpyd%?\\t%P0, %P1\";
       default:
        abort ();
       }
       default:
        abort ();
       }
   "
   [(set_attr "type"
      "r_2_f,f_2_r,fconstd,load2,store2,f_load,f_store,ffarithd,*")
   "
   [(set_attr "type"
      "r_2_f,f_2_r,fconstd,load2,store2,f_load,f_store,ffarithd,*")
-   (set_attr "length" "4,4,4,8,8,4,4,4,8")
+   (set (attr "length") (cond [(eq_attr "alternative" "3,4,8") (const_int 8)
+                              (eq_attr "alternative" "7")
+                               (if_then_else
+                                (eq (symbol_ref "TARGET_VFP_SINGLE")
+                                    (const_int 1))
+                                (const_int 8)
+                                (const_int 4))]
+                             (const_int 4)))
    (set_attr "pool_range" "*,*,*,4096,*,1020,*,*,*")
    (set_attr "neg_pool_range" "*,*,*,0,*,1008,*,*,*")]
 )
    (set_attr "pool_range" "*,*,*,4096,*,1020,*,*,*")
    (set_attr "neg_pool_range" "*,*,*,0,*,1008,*,*,*")]
 )
            [(match_operand 4 "cc_register" "") (const_int 0)])
          (match_operand:DF 1 "s_register_operand" "0,w,w,0,?r,?r,0,w,w")
          (match_operand:DF 2 "s_register_operand" "w,0,w,?r,0,?r,w,0,w")))]
            [(match_operand 4 "cc_register" "") (const_int 0)])
          (match_operand:DF 1 "s_register_operand" "0,w,w,0,?r,?r,0,w,w")
          (match_operand:DF 2 "s_register_operand" "w,0,w,?r,0,?r,w,0,w")))]
-  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "@
    fcpyd%D3\\t%P0, %P2
    fcpyd%d3\\t%P0, %P1
   "@
    fcpyd%D3\\t%P0, %P2
    fcpyd%d3\\t%P0, %P1
            [(match_operand 4 "cc_register" "") (const_int 0)])
          (match_operand:DF 1 "s_register_operand" "0,w,w,0,?r,?r,0,w,w")
          (match_operand:DF 2 "s_register_operand" "w,0,w,?r,0,?r,w,0,w")))]
            [(match_operand 4 "cc_register" "") (const_int 0)])
          (match_operand:DF 1 "s_register_operand" "0,w,w,0,?r,?r,0,w,w")
          (match_operand:DF 2 "s_register_operand" "w,0,w,?r,0,?r,w,0,w")))]
-  "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "@
    it\\t%D3\;fcpyd%D3\\t%P0, %P2
    it\\t%d3\;fcpyd%d3\\t%P0, %P1
   "@
    it\\t%D3\;fcpyd%D3\\t%P0, %P2
    it\\t%d3\;fcpyd%d3\\t%P0, %P1
 (define_insn "*absdf2_vfp"
   [(set (match_operand:DF        0 "s_register_operand" "=w")
        (abs:DF (match_operand:DF 1 "s_register_operand" "w")))]
 (define_insn "*absdf2_vfp"
   [(set (match_operand:DF        0 "s_register_operand" "=w")
        (abs:DF (match_operand:DF 1 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fabsd%?\\t%P0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "ffarithd")]
   "fabsd%?\\t%P0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "ffarithd")]
 (define_insn_and_split "*negdf2_vfp"
   [(set (match_operand:DF        0 "s_register_operand" "=w,?r,?r")
        (neg:DF (match_operand:DF 1 "s_register_operand" "w,0,r")))]
 (define_insn_and_split "*negdf2_vfp"
   [(set (match_operand:DF        0 "s_register_operand" "=w,?r,?r")
        (neg:DF (match_operand:DF 1 "s_register_operand" "w,0,r")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "@
    fnegd%?\\t%P0, %P1
    #
    #"
   "@
    fnegd%?\\t%P0, %P1
    #
    #"
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP && reload_completed
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE && reload_completed
    && arm_general_register_operand (operands[0], DFmode)"
   [(set (match_dup 0) (match_dup 1))]
   "
    && arm_general_register_operand (operands[0], DFmode)"
   [(set (match_dup 0) (match_dup 1))]
   "
   [(set (match_operand:DF         0 "s_register_operand" "=w")
        (plus:DF (match_operand:DF 1 "s_register_operand" "w")
                 (match_operand:DF 2 "s_register_operand" "w")))]
   [(set (match_operand:DF         0 "s_register_operand" "=w")
        (plus:DF (match_operand:DF 1 "s_register_operand" "w")
                 (match_operand:DF 2 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "faddd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "faddd")]
   "faddd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "faddd")]
   [(set (match_operand:DF          0 "s_register_operand" "=w")
        (minus:DF (match_operand:DF 1 "s_register_operand" "w")
                  (match_operand:DF 2 "s_register_operand" "w")))]
   [(set (match_operand:DF          0 "s_register_operand" "=w")
        (minus:DF (match_operand:DF 1 "s_register_operand" "w")
                  (match_operand:DF 2 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fsubd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "faddd")]
   "fsubd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "faddd")]
   [(set (match_operand:DF        0 "s_register_operand" "+w")
        (div:DF (match_operand:DF 1 "s_register_operand" "w")
                (match_operand:DF 2 "s_register_operand" "w")))]
   [(set (match_operand:DF        0 "s_register_operand" "+w")
        (div:DF (match_operand:DF 1 "s_register_operand" "w")
                (match_operand:DF 2 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fdivd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fdivd")]
   "fdivd%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fdivd")]
   [(set (match_operand:DF         0 "s_register_operand" "+w")
        (mult:DF (match_operand:DF 1 "s_register_operand" "w")
                 (match_operand:DF 2 "s_register_operand" "w")))]
   [(set (match_operand:DF         0 "s_register_operand" "+w")
        (mult:DF (match_operand:DF 1 "s_register_operand" "w")
                 (match_operand:DF 2 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fmuld%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmuld")]
   "fmuld%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmuld")]
   [(set (match_operand:DF                 0 "s_register_operand" "+w")
        (mult:DF (neg:DF (match_operand:DF 1 "s_register_operand" "w"))
                 (match_operand:DF         2 "s_register_operand" "w")))]
   [(set (match_operand:DF                 0 "s_register_operand" "+w")
        (mult:DF (neg:DF (match_operand:DF 1 "s_register_operand" "w"))
                 (match_operand:DF         2 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fnmuld%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmuld")]
   "fnmuld%?\\t%P0, %P1, %P2"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmuld")]
        (plus:DF (mult:DF (match_operand:DF 2 "s_register_operand" "w")
                          (match_operand:DF 3 "s_register_operand" "w"))
                 (match_operand:DF          1 "s_register_operand" "0")))]
        (plus:DF (mult:DF (match_operand:DF 2 "s_register_operand" "w")
                          (match_operand:DF 3 "s_register_operand" "w"))
                 (match_operand:DF          1 "s_register_operand" "0")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fmacd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
   "fmacd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
        (minus:DF (mult:DF (match_operand:DF 2 "s_register_operand" "w")
                           (match_operand:DF 3 "s_register_operand" "w"))
                  (match_operand:DF          1 "s_register_operand" "0")))]
        (minus:DF (mult:DF (match_operand:DF 2 "s_register_operand" "w")
                           (match_operand:DF 3 "s_register_operand" "w"))
                  (match_operand:DF          1 "s_register_operand" "0")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fmscd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
   "fmscd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
        (minus:DF (match_operand:DF          1 "s_register_operand" "0")
                  (mult:DF (match_operand:DF 2 "s_register_operand" "w")
                           (match_operand:DF 3 "s_register_operand" "w"))))]
        (minus:DF (match_operand:DF          1 "s_register_operand" "0")
                  (mult:DF (match_operand:DF 2 "s_register_operand" "w")
                           (match_operand:DF 3 "s_register_operand" "w"))))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fnmacd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
   "fnmacd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
                    (neg:DF (match_operand:DF 2 "s_register_operand" "w"))
                    (match_operand:DF         3 "s_register_operand" "w"))
                  (match_operand:DF           1 "s_register_operand" "0")))]
                    (neg:DF (match_operand:DF 2 "s_register_operand" "w"))
                    (match_operand:DF         3 "s_register_operand" "w"))
                  (match_operand:DF           1 "s_register_operand" "0")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fnmscd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
   "fnmscd%?\\t%P0, %P2, %P3"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fmacd")]
 (define_insn "*extendsfdf2_vfp"
   [(set (match_operand:DF                 0 "s_register_operand" "=w")
        (float_extend:DF (match_operand:SF 1 "s_register_operand" "t")))]
 (define_insn "*extendsfdf2_vfp"
   [(set (match_operand:DF                 0 "s_register_operand" "=w")
        (float_extend:DF (match_operand:SF 1 "s_register_operand" "t")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fcvtds%?\\t%P0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "fcvtds%?\\t%P0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "*truncdfsf2_vfp"
   [(set (match_operand:SF                 0 "s_register_operand" "=t")
        (float_truncate:SF (match_operand:DF 1 "s_register_operand" "w")))]
 (define_insn "*truncdfsf2_vfp"
   [(set (match_operand:SF                 0 "s_register_operand" "=t")
        (float_truncate:SF (match_operand:DF 1 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fcvtsd%?\\t%0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "fcvtsd%?\\t%0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "extendhfsf2"
   [(set (match_operand:SF                 0 "s_register_operand" "=t")
        (float_extend:SF (match_operand:HF 1 "s_register_operand" "t")))]
 (define_insn "extendhfsf2"
   [(set (match_operand:SF                 0 "s_register_operand" "=t")
        (float_extend:SF (match_operand:HF 1 "s_register_operand" "t")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_NEON_FP16"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_FP16"
   "vcvtb%?.f32.f16\\t%0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "vcvtb%?.f32.f16\\t%0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "truncsfhf2"
   [(set (match_operand:HF                 0 "s_register_operand" "=t")
        (float_truncate:HF (match_operand:SF 1 "s_register_operand" "t")))]
 (define_insn "truncsfhf2"
   [(set (match_operand:HF                 0 "s_register_operand" "=t")
        (float_truncate:HF (match_operand:SF 1 "s_register_operand" "t")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_NEON_FP16"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_FP16"
   "vcvtb%?.f16.f32\\t%0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "vcvtb%?.f16.f32\\t%0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "*truncsidf2_vfp"
   [(set (match_operand:SI                0 "s_register_operand" "=t")
        (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "w"))))]
 (define_insn "*truncsidf2_vfp"
   [(set (match_operand:SI                0 "s_register_operand" "=t")
        (fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "w"))))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "ftosizd%?\\t%0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "ftosizd%?\\t%0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "fixuns_truncdfsi2"
   [(set (match_operand:SI                0 "s_register_operand" "=t")
        (unsigned_fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "t"))))]
 (define_insn "fixuns_truncdfsi2"
   [(set (match_operand:SI                0 "s_register_operand" "=t")
        (unsigned_fix:SI (fix:DF (match_operand:DF 1 "s_register_operand" "t"))))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "ftouizd%?\\t%0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "ftouizd%?\\t%0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "*floatsidf2_vfp"
   [(set (match_operand:DF          0 "s_register_operand" "=w")
        (float:DF (match_operand:SI 1 "s_register_operand" "t")))]
 (define_insn "*floatsidf2_vfp"
   [(set (match_operand:DF          0 "s_register_operand" "=w")
        (float:DF (match_operand:SI 1 "s_register_operand" "t")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fsitod%?\\t%P0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "fsitod%?\\t%P0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "floatunssidf2"
   [(set (match_operand:DF          0 "s_register_operand" "=w")
        (unsigned_float:DF (match_operand:SI 1 "s_register_operand" "t")))]
 (define_insn "floatunssidf2"
   [(set (match_operand:DF          0 "s_register_operand" "=w")
        (unsigned_float:DF (match_operand:SI 1 "s_register_operand" "t")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fuitod%?\\t%P0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
   "fuitod%?\\t%P0, %1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "f_cvt")]
 (define_insn "*sqrtdf2_vfp"
   [(set (match_operand:DF         0 "s_register_operand" "=w")
        (sqrt:DF (match_operand:DF 1 "s_register_operand" "w")))]
 (define_insn "*sqrtdf2_vfp"
   [(set (match_operand:DF         0 "s_register_operand" "=w")
        (sqrt:DF (match_operand:DF 1 "s_register_operand" "w")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "fsqrtd%?\\t%P0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fdivd")]
   "fsqrtd%?\\t%P0, %P1"
   [(set_attr "predicable" "yes")
    (set_attr "type" "fdivd")]
   [(set (reg:CCFP CC_REGNUM)
        (compare:CCFP (match_operand:DF 0 "s_register_operand"  "w")
                      (match_operand:DF 1 "vfp_compare_operand" "wG")))]
   [(set (reg:CCFP CC_REGNUM)
        (compare:CCFP (match_operand:DF 0 "s_register_operand"  "w")
                      (match_operand:DF 1 "vfp_compare_operand" "wG")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "#"
   "#"
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   [(set (reg:CCFP VFPCC_REGNUM)
        (compare:CCFP (match_dup 0)
                       (match_dup 1)))
   [(set (reg:CCFP VFPCC_REGNUM)
        (compare:CCFP (match_dup 0)
                       (match_dup 1)))
   [(set (reg:CCFPE CC_REGNUM)
        (compare:CCFPE (match_operand:DF 0 "s_register_operand"  "w")
                       (match_operand:DF 1 "vfp_compare_operand" "wG")))]
   [(set (reg:CCFPE CC_REGNUM)
        (compare:CCFPE (match_operand:DF 0 "s_register_operand"  "w")
                       (match_operand:DF 1 "vfp_compare_operand" "wG")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "#"
   "#"
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   [(set (reg:CCFPE VFPCC_REGNUM)
        (compare:CCFPE (match_dup 0)
                       (match_dup 1)))
   [(set (reg:CCFPE VFPCC_REGNUM)
        (compare:CCFPE (match_dup 0)
                       (match_dup 1)))
   [(set (reg:CCFP VFPCC_REGNUM)
        (compare:CCFP (match_operand:DF 0 "s_register_operand"  "w,w")
                      (match_operand:DF 1 "vfp_compare_operand" "w,G")))]
   [(set (reg:CCFP VFPCC_REGNUM)
        (compare:CCFP (match_operand:DF 0 "s_register_operand"  "w,w")
                      (match_operand:DF 1 "vfp_compare_operand" "w,G")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "@
    fcmpd%?\\t%P0, %P1
    fcmpzd%?\\t%P0"
   "@
    fcmpd%?\\t%P0, %P1
    fcmpzd%?\\t%P0"
   [(set (reg:CCFPE VFPCC_REGNUM)
        (compare:CCFPE (match_operand:DF 0 "s_register_operand"  "w,w")
                       (match_operand:DF 1 "vfp_compare_operand" "w,G")))]
   [(set (reg:CCFPE VFPCC_REGNUM)
        (compare:CCFPE (match_operand:DF 0 "s_register_operand"  "w,w")
                       (match_operand:DF 1 "vfp_compare_operand" "w,G")))]
-  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP"
+  "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP_DOUBLE"
   "@
    fcmped%?\\t%P0, %P1
    fcmpezd%?\\t%P0"
   "@
    fcmped%?\\t%P0, %P1
    fcmpezd%?\\t%P0"
index e09c9ee..c9c759d 100644 (file)
@@ -960,8 +960,9 @@ direct conversion.
 ARM provides hardware support for conversions between 
 @code{__fp16} and @code{float} values
 as an extension to VFP and NEON (Advanced SIMD).  GCC generates
 ARM provides hardware support for conversions between 
 @code{__fp16} and @code{float} values
 as an extension to VFP and NEON (Advanced SIMD).  GCC generates
-code using the instructions provided by this extension if you compile
-with the options @option{-mfpu=neon-fp16 -mfloat-abi=softfp},
+code using these hardware instructions if you compile with
+options to select an FPU that provides them; 
+for example, @option{-mfpu=neon-fp16 -mfloat-abi=softfp},
 in addition to the @option{-mfp16-format} option to select
 a half-precision format.  
 
 in addition to the @option{-mfp16-format} option to select
 a half-precision format.  
 
index 20a9395..3b49707 100644 (file)
@@ -9788,10 +9788,12 @@ of the @option{-mcpu=} option.  Permissible names are: @samp{armv2},
 @opindex mfp
 This specifies what floating point hardware (or hardware emulation) is
 available on the target.  Permissible names are: @samp{fpa}, @samp{fpe2},
 @opindex mfp
 This specifies what floating point hardware (or hardware emulation) is
 available on the target.  Permissible names are: @samp{fpa}, @samp{fpe2},
-@samp{fpe3}, @samp{maverick}, @samp{vfp}, @samp{vfpv3}, @samp{vfpv3-d16},
-@samp{neon}, and @samp{neon-fp16}.  @option{-mfp} and @option{-mfpe}
-are synonyms for @option{-mfpu}=@samp{fpe}@var{number}, for compatibility
-with older versions of GCC@.
+@samp{fpe3}, @samp{maverick}, @samp{vfp}, @samp{vfpv3}, @samp{vfpv3-fp16},
+@samp{vfpv3-d16}, @samp{vfpv3-d16-fp16}, @samp{vfpv3xd}, @samp{vfpv3xd-fp16},
+@samp{neon}, and @samp{neon-fp16}.
+@option{-mfp} and @option{-mfpe} are synonyms for
+@option{-mfpu}=@samp{fpe}@var{number}, for compatibility with older versions
+of GCC@.
 
 If @option{-msoft-float} is specified this specifies the format of
 floating point values.
 
 If @option{-msoft-float} is specified this specifies the format of
 floating point values.