[Patch 16/17 libgcc ARM] Half to double precision conversions
authorJames Greenhalgh <james.greenhalgh@arm.com>
Wed, 23 Nov 2016 17:33:39 +0000 (17:33 +0000)
committerJames Greenhalgh <jgreenhalgh@gcc.gnu.org>
Wed, 23 Nov 2016 17:33:39 +0000 (17:33 +0000)
gcc/

* config/arm/arm.c (arm_convert_to_type): Delete.
(TARGET_CONVERT_TO_TYPE): Delete.
(arm_init_libfuncs): Enable trunc_optab from DFmode to HFmode.
(arm_libcall_uses_aapcs_base): Add trunc_optab from DF- to HFmode.
* config/arm/arm.h (TARGET_FP16_TO_DOUBLE): New.
* config/arm/arm.md (truncdfhf2): Only convert through SFmode if we
are in fast math mode, and have no single step hardware instruction.
(extendhfdf2): Only expand through SFmode if we don't have a
single-step hardware instruction.
* config/arm/vfp.md (*truncdfhf2): New.
(extendhfdf2): Likewise.

gcc/testsuite/

* gcc.target/arm/fp16-rounding-alt-1.c (ROUNDED): Change expected
result.
* gcc.target/arm/fp16-rounding-ieee-1.c (ROUNDED): Change expected
result.

From-SVN: r242783

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/vfp.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/fp16-rounding-alt-1.c
gcc/testsuite/gcc.target/arm/fp16-rounding-ieee-1.c

index 5a19b6052053fed18e67fb2f734ea0503c0b3df3..4ab87a9d009ca0876881b4f4f459393db9a8fe57 100644 (file)
@@ -1,3 +1,17 @@
+2016-11-23  James Greenhalgh  <james.greenhalgh@arm.com>
+
+       * config/arm/arm.c (arm_convert_to_type): Delete.
+       (TARGET_CONVERT_TO_TYPE): Delete.
+       (arm_init_libfuncs): Enable trunc_optab from DFmode to HFmode.
+       (arm_libcall_uses_aapcs_base): Add trunc_optab from DF- to HFmode.
+       * config/arm/arm.h (TARGET_FP16_TO_DOUBLE): New.
+       * config/arm/arm.md (truncdfhf2): Only convert through SFmode if we
+       are in fast math mode, and have no single step hardware instruction.
+       (extendhfdf2): Only expand through SFmode if we don't have a
+       single-step hardware instruction.
+       * config/arm/vfp.md (*truncdfhf2): New.
+       (extendhfdf2): Likewise.
+
 2016-11-23  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * targhooks.c (default_floatn_mode): Enable _Float16 if a target
index abd3276f13125e87fe7a88b60f0bf98cd580e7fb..118b93b94308a1e2411d330faaeff8c873b39264 100644 (file)
@@ -245,7 +245,6 @@ static bool arm_output_addr_const_extra (FILE *, rtx);
 static bool arm_allocate_stack_slots_for_args (void);
 static bool arm_warn_func_return (tree);
 static tree arm_promoted_type (const_tree t);
-static tree arm_convert_to_type (tree type, tree expr);
 static bool arm_scalar_mode_supported_p (machine_mode);
 static bool arm_frame_pointer_required (void);
 static bool arm_can_eliminate (const int, const int);
@@ -654,9 +653,6 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_PROMOTED_TYPE
 #define TARGET_PROMOTED_TYPE arm_promoted_type
 
-#undef TARGET_CONVERT_TO_TYPE
-#define TARGET_CONVERT_TO_TYPE arm_convert_to_type
-
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p
 
@@ -2535,6 +2531,11 @@ arm_init_libfuncs (void)
                         ? "__gnu_h2f_ieee"
                         : "__gnu_h2f_alternative"));
 
+      set_conv_libfunc (trunc_optab, HFmode, DFmode,
+                       (arm_fp16_format == ARM_FP16_FORMAT_IEEE
+                        ? "__gnu_d2h_ieee"
+                        : "__gnu_d2h_alternative"));
+
       /* Arithmetic.  */
       set_optab_libfunc (add_optab, HFmode, NULL);
       set_optab_libfunc (sdiv_optab, HFmode, NULL);
@@ -5259,6 +5260,8 @@ arm_libcall_uses_aapcs_base (const_rtx libcall)
                                                        SFmode));
       add_libcall (libcall_htab, convert_optab_libfunc (trunc_optab, SFmode,
                                                        DFmode));
+      add_libcall (libcall_htab,
+                  convert_optab_libfunc (trunc_optab, HFmode, DFmode));
     }
 
   return libcall && libcall_htab->find (libcall) != NULL;
@@ -22514,23 +22517,6 @@ arm_promoted_type (const_tree t)
   return NULL_TREE;
 }
 
-/* Implement TARGET_CONVERT_TO_TYPE.
-   Specifically, this hook implements the peculiarity of the ARM
-   half-precision floating-point C semantics that requires conversions between
-   __fp16 to or from double to do an intermediate conversion to float.  */
-
-static tree
-arm_convert_to_type (tree type, tree expr)
-{
-  tree fromtype = TREE_TYPE (expr);
-  if (!SCALAR_FLOAT_TYPE_P (fromtype) || !SCALAR_FLOAT_TYPE_P (type))
-    return NULL_TREE;
-  if ((TYPE_PRECISION (fromtype) == 16 && TYPE_PRECISION (type) > 32)
-      || (TYPE_PRECISION (type) == 16 && TYPE_PRECISION (fromtype) > 32))
-    return convert (type, convert (float_type_node, expr));
-  return NULL_TREE;
-}
-
 /* Implement TARGET_SCALAR_MODE_SUPPORTED_P.
    This simply adds HFmode as a supported mode; even though we don't
    implement arithmetic on this type directly, it's supported by
index 7ad0fbf0d803cfc9015b78ffdb4e8d2f94f43d1e..15930f0ca8fa148f1b02745574cc6994f0c5f837 100644 (file)
@@ -179,6 +179,11 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
 #define TARGET_FP16                                                    \
   (ARM_FPU_FSET_HAS (TARGET_FPU_FEATURES, FPU_FL_FP16))
 
+/* FPU supports converting between HFmode and DFmode in a single hardware
+   step.  */
+#define TARGET_FP16_TO_DOUBLE                                          \
+  (TARGET_HARD_FLOAT && (TARGET_FP16 && TARGET_VFP5))
+
 /* FPU supports fused-multiply-add operations.  */
 #define TARGET_FMA (TARGET_FPU_REV >= 4)
 
index ccae728bd16e403cbcada323463b473ad0397b67..5523baf5099cb7c35a6ad3c8a39e5c31efd32f17 100644 (file)
   ""
 )
 
-;; DFmode to HFmode conversions have to go through SFmode.
+;; DFmode to HFmode conversions on targets without a single-step hardware
+;; instruction for it would have to go through SFmode.  This is dangerous
+;; as it introduces double rounding.
+;;
+;; Disable this pattern unless we are in an unsafe math mode, or we have
+;; a single-step instruction.
+
 (define_expand "truncdfhf2"
-  [(set (match_operand:HF  0 "general_operand" "")
+  [(set (match_operand:HF  0 "s_register_operand" "")
        (float_truncate:HF
-        (match_operand:DF 1 "general_operand" "")))]
-  "TARGET_EITHER"
-  "
-  {
-    rtx op1;
-    op1 = convert_to_mode (SFmode, operands[1], 0);
-    op1 = convert_to_mode (HFmode, op1, 0);
-    emit_move_insn (operands[0], op1);
-    DONE;
-  }"
+        (match_operand:DF 1 "s_register_operand" "")))]
+  "(TARGET_EITHER && flag_unsafe_math_optimizations)
+   || (TARGET_32BIT && TARGET_FP16_TO_DOUBLE)"
+{
+  /* We don't have a direct instruction for this, so we must be in
+     an unsafe math mode, and going via SFmode.  */
+
+  if (!(TARGET_32BIT && TARGET_FP16_TO_DOUBLE))
+    {
+      rtx op1;
+      op1 = convert_to_mode (SFmode, operands[1], 0);
+      op1 = convert_to_mode (HFmode, op1, 0);
+      emit_move_insn (operands[0], op1);
+      DONE;
+    }
+  /* Otherwise, we will pick this up as a single instruction with
+     no intermediary rounding.  */
+}
 )
 \f
 ;; Zero and sign extension instructions.
   ""
 )
 
-;; HFmode -> DFmode conversions have to go through SFmode.
+;; HFmode -> DFmode conversions where we don't have an instruction for it
+;; must go through SFmode.
+;;
+;; This is always safe for an extend.
+
 (define_expand "extendhfdf2"
-  [(set (match_operand:DF                  0 "general_operand" "")
-       (float_extend:DF (match_operand:HF 1 "general_operand"  "")))]
+  [(set (match_operand:DF                 0 "s_register_operand" "")
+       (float_extend:DF (match_operand:HF 1 "s_register_operand" "")))]
   "TARGET_EITHER"
-  "
-  {
-    rtx op1;
-    op1 = convert_to_mode (SFmode, operands[1], 0);
-    op1 = convert_to_mode (DFmode, op1, 0);
-    emit_insn (gen_movdf (operands[0], op1));
-    DONE;
-  }"
+{
+  /* We don't have a direct instruction for this, so go via SFmode.  */
+  if (!(TARGET_32BIT && TARGET_FP16_TO_DOUBLE))
+    {
+      rtx op1;
+      op1 = convert_to_mode (SFmode, operands[1], 0);
+      op1 = convert_to_mode (DFmode, op1, 0);
+      emit_insn (gen_movdf (operands[0], op1));
+      DONE;
+    }
+  /* Otherwise, we're done producing RTL and will pick up the correct
+     pattern to do this with one rounding-step in a single instruction.  */
+}
 )
 \f
 ;; Move insns (including loads and stores)
index ce56e160c043264fd41077e075896760644cd9a5..f83dc9b130e4288faa49e40ee8285a0cd7d325b1 100644 (file)
    (set_attr "type" "f_cvt")]
 )
 
+(define_insn "*truncdfhf2"
+  [(set (match_operand:HF                 0 "s_register_operand" "=t")
+       (float_truncate:HF (match_operand:DF 1 "s_register_operand" "w")))]
+  "TARGET_32BIT && TARGET_FP16_TO_DOUBLE"
+  "vcvtb%?.f16.f64\\t%0, %P1"
+  [(set_attr "predicable" "yes")
+   (set_attr "predicable_short_it" "no")
+   (set_attr "type" "f_cvt")]
+)
+
+(define_insn "*extendhfdf2"
+  [(set (match_operand:DF                 0 "s_register_operand" "=w")
+       (float_extend:DF (match_operand:HF 1 "s_register_operand" "t")))]
+  "TARGET_32BIT && TARGET_FP16_TO_DOUBLE"
+  "vcvtb%?.f64.f16\\t%P0, %1"
+  [(set_attr "predicable" "yes")
+   (set_attr "predicable_short_it" "no")
+   (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")))]
index 44c1f262e3542999326b33f6e90f97231aaca065..0d5909052d44c00c92cad6186c4fc132d81cc120 100644 (file)
@@ -1,3 +1,10 @@
+2016-11-23  James Greenhalgh  <james.greenhalgh@arm.com>
+
+       * gcc.target/arm/fp16-rounding-alt-1.c (ROUNDED): Change expected
+       result.
+       * gcc.target/arm/fp16-rounding-ieee-1.c (ROUNDED): Change expected
+       result.
+
 2016-11-23  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * lib/target-supports.exp (check_effective_target_float16): Add
index 1c15b613239de8610bb52b127ce5b143d1038804..27bb40dcfee837587e79af6e2be90290a572c06f 100644 (file)
@@ -1,6 +1,6 @@
-/* Test intermediate rounding of double to float and then to __fp16, using
-   an example of a number that would round differently if it went directly
-   from double to __fp16.  */
+/* Test that rounding double to __fp16 happens directly, using an example
+   of a number that would round differently if it went from double to
+   __fp16 via float.  */
 
 /* { dg-do run } */
 /* { dg-require-effective-target arm_fp16_alternative_ok } */
@@ -11,8 +11,8 @@
 /* The original double value.  */
 #define ORIG 0x1.0020008p0
 
-/* The expected (double)((__fp16)((float)ORIG)) value.  */
-#define ROUNDED 0x1.0000000p0
+/* The expected (double)((__fp16)ORIG) value.  */
+#define ROUNDED 0x1.0040000p0
 
 typedef union u {
   __fp16 f;
index 866d4d82403c8ff42126a820a8f0442181e3810a..194dc9dc3bdff9721c5a37e0ec06b1a7d6627a4c 100644 (file)
@@ -1,6 +1,6 @@
-/* Test intermediate rounding of double to float and then to __fp16, using
-   an example of a number that would round differently if it went directly
-   from double to __fp16.  */
+/* Test that rounding double to __fp16 happens directly, using an example
+   of a number that would round differently if it went from double to
+   __fp16 via float.  */
 
 /* { dg-do run } */
 /* { dg-options "-mfp16-format=ieee" } */
@@ -10,8 +10,8 @@
 /* The original double value.  */
 #define ORIG 0x1.0020008p0
 
-/* The expected (double)((__fp16)((float)ORIG)) value.  */
-#define ROUNDED 0x1.0000000p0
+/* The expected (double)((__fp16)ORIG) value.  */
+#define ROUNDED 0x1.0040000p0
 
 typedef union u {
   __fp16 f;