Commit 5e0f10a0 by James Greenhalgh Committed by James Greenhalgh

[Patch 16/17 libgcc ARM] Half to double precision conversions

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
parent bea64ca3
2016-11-23 James Greenhalgh <james.greenhalgh@arm.com> 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 * targhooks.c (default_floatn_mode): Enable _Float16 if a target
provides HFmode. provides HFmode.
...@@ -245,7 +245,6 @@ static bool arm_output_addr_const_extra (FILE *, rtx); ...@@ -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_allocate_stack_slots_for_args (void);
static bool arm_warn_func_return (tree); static bool arm_warn_func_return (tree);
static tree arm_promoted_type (const_tree t); 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_scalar_mode_supported_p (machine_mode);
static bool arm_frame_pointer_required (void); static bool arm_frame_pointer_required (void);
static bool arm_can_eliminate (const int, const int); static bool arm_can_eliminate (const int, const int);
...@@ -654,9 +653,6 @@ static const struct attribute_spec arm_attribute_table[] = ...@@ -654,9 +653,6 @@ static const struct attribute_spec arm_attribute_table[] =
#undef TARGET_PROMOTED_TYPE #undef TARGET_PROMOTED_TYPE
#define TARGET_PROMOTED_TYPE arm_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 #undef TARGET_SCALAR_MODE_SUPPORTED_P
#define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p #define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p
...@@ -2535,6 +2531,11 @@ arm_init_libfuncs (void) ...@@ -2535,6 +2531,11 @@ arm_init_libfuncs (void)
? "__gnu_h2f_ieee" ? "__gnu_h2f_ieee"
: "__gnu_h2f_alternative")); : "__gnu_h2f_alternative"));
set_conv_libfunc (trunc_optab, HFmode, DFmode,
(arm_fp16_format == ARM_FP16_FORMAT_IEEE
? "__gnu_d2h_ieee"
: "__gnu_d2h_alternative"));
/* Arithmetic. */ /* Arithmetic. */
set_optab_libfunc (add_optab, HFmode, NULL); set_optab_libfunc (add_optab, HFmode, NULL);
set_optab_libfunc (sdiv_optab, HFmode, NULL); set_optab_libfunc (sdiv_optab, HFmode, NULL);
...@@ -5259,6 +5260,8 @@ arm_libcall_uses_aapcs_base (const_rtx libcall) ...@@ -5259,6 +5260,8 @@ arm_libcall_uses_aapcs_base (const_rtx libcall)
SFmode)); SFmode));
add_libcall (libcall_htab, convert_optab_libfunc (trunc_optab, SFmode, add_libcall (libcall_htab, convert_optab_libfunc (trunc_optab, SFmode,
DFmode)); DFmode));
add_libcall (libcall_htab,
convert_optab_libfunc (trunc_optab, HFmode, DFmode));
} }
return libcall && libcall_htab->find (libcall) != NULL; return libcall && libcall_htab->find (libcall) != NULL;
...@@ -22514,23 +22517,6 @@ arm_promoted_type (const_tree t) ...@@ -22514,23 +22517,6 @@ arm_promoted_type (const_tree t)
return NULL_TREE; 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. /* Implement TARGET_SCALAR_MODE_SUPPORTED_P.
This simply adds HFmode as a supported mode; even though we don't This simply adds HFmode as a supported mode; even though we don't
implement arithmetic on this type directly, it's supported by implement arithmetic on this type directly, it's supported by
......
...@@ -179,6 +179,11 @@ extern void (*arm_lang_output_object_attributes_hook)(void); ...@@ -179,6 +179,11 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
#define TARGET_FP16 \ #define TARGET_FP16 \
(ARM_FPU_FSET_HAS (TARGET_FPU_FEATURES, FPU_FL_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. */ /* FPU supports fused-multiply-add operations. */
#define TARGET_FMA (TARGET_FPU_REV >= 4) #define TARGET_FMA (TARGET_FPU_REV >= 4)
......
...@@ -5182,20 +5182,34 @@ ...@@ -5182,20 +5182,34 @@
"" ""
) )
;; 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" (define_expand "truncdfhf2"
[(set (match_operand:HF 0 "general_operand" "") [(set (match_operand:HF 0 "s_register_operand" "")
(float_truncate:HF (float_truncate:HF
(match_operand:DF 1 "general_operand" "")))] (match_operand:DF 1 "s_register_operand" "")))]
"TARGET_EITHER" "(TARGET_EITHER && flag_unsafe_math_optimizations)
" || (TARGET_32BIT && TARGET_FP16_TO_DOUBLE)"
{ {
rtx op1; /* We don't have a direct instruction for this, so we must be in
op1 = convert_to_mode (SFmode, operands[1], 0); an unsafe math mode, and going via SFmode. */
op1 = convert_to_mode (HFmode, op1, 0);
emit_move_insn (operands[0], op1); if (!(TARGET_32BIT && TARGET_FP16_TO_DOUBLE))
DONE; {
}" 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. */
}
) )
;; Zero and sign extension instructions. ;; Zero and sign extension instructions.
...@@ -5689,19 +5703,28 @@ ...@@ -5689,19 +5703,28 @@
"" ""
) )
;; 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" (define_expand "extendhfdf2"
[(set (match_operand:DF 0 "general_operand" "") [(set (match_operand:DF 0 "s_register_operand" "")
(float_extend:DF (match_operand:HF 1 "general_operand" "")))] (float_extend:DF (match_operand:HF 1 "s_register_operand" "")))]
"TARGET_EITHER" "TARGET_EITHER"
" {
{ /* We don't have a direct instruction for this, so go via SFmode. */
rtx op1; if (!(TARGET_32BIT && TARGET_FP16_TO_DOUBLE))
op1 = convert_to_mode (SFmode, operands[1], 0); {
op1 = convert_to_mode (DFmode, op1, 0); rtx op1;
emit_insn (gen_movdf (operands[0], op1)); op1 = convert_to_mode (SFmode, operands[1], 0);
DONE; 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. */
}
) )
;; Move insns (including loads and stores) ;; Move insns (including loads and stores)
......
...@@ -1507,6 +1507,26 @@ ...@@ -1507,6 +1507,26 @@
(set_attr "type" "f_cvt")] (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" (define_insn "truncsfhf2"
[(set (match_operand:HF 0 "s_register_operand" "=t") [(set (match_operand:HF 0 "s_register_operand" "=t")
(float_truncate:HF (match_operand:SF 1 "s_register_operand" "t")))] (float_truncate:HF (match_operand:SF 1 "s_register_operand" "t")))]
......
2016-11-23 James Greenhalgh <james.greenhalgh@arm.com> 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 * lib/target-supports.exp (check_effective_target_float16): Add
options for _Float16. options for _Float16.
(check_effective_target_float32): Add options for _Float32. (check_effective_target_float32): Add options for _Float32.
......
/* Test intermediate rounding of double to float and then to __fp16, using /* Test that rounding double to __fp16 happens directly, using an example
an example of a number that would round differently if it went directly of a number that would round differently if it went from double to
from double to __fp16. */ __fp16 via float. */
/* { dg-do run } */ /* { dg-do run } */
/* { dg-require-effective-target arm_fp16_alternative_ok } */ /* { dg-require-effective-target arm_fp16_alternative_ok } */
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
/* The original double value. */ /* The original double value. */
#define ORIG 0x1.0020008p0 #define ORIG 0x1.0020008p0
/* The expected (double)((__fp16)((float)ORIG)) value. */ /* The expected (double)((__fp16)ORIG) value. */
#define ROUNDED 0x1.0000000p0 #define ROUNDED 0x1.0040000p0
typedef union u { typedef union u {
__fp16 f; __fp16 f;
......
/* Test intermediate rounding of double to float and then to __fp16, using /* Test that rounding double to __fp16 happens directly, using an example
an example of a number that would round differently if it went directly of a number that would round differently if it went from double to
from double to __fp16. */ __fp16 via float. */
/* { dg-do run } */ /* { dg-do run } */
/* { dg-options "-mfp16-format=ieee" } */ /* { dg-options "-mfp16-format=ieee" } */
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
/* The original double value. */ /* The original double value. */
#define ORIG 0x1.0020008p0 #define ORIG 0x1.0020008p0
/* The expected (double)((__fp16)((float)ORIG)) value. */ /* The expected (double)((__fp16)ORIG) value. */
#define ROUNDED 0x1.0000000p0 #define ROUNDED 0x1.0040000p0
typedef union u { typedef union u {
__fp16 f; __fp16 f;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment