+2016-11-23 James Greenhalgh <james.greenhalgh@arm.com>
+
+ PR target/63250
+ * config/arm/arm-builtins.c (arm_simd_floatHF_type_node): Rename to...
+ (arm_fp16_type_node): ...This, make visibile.
+ (arm_simd_builtin_std_type): Rename arm_simd_floatHF_type_node to
+ arm_fp16_type_node.
+ (arm_init_simd_builtin_types): Likewise.
+ (arm_init_fp16_builtins): Likewise.
+ * config/arm/arm.c (arm_excess_precision): New.
+ (arm_floatn_mode): Likewise.
+ (TARGET_C_EXCESS_PRECISION): Likewise.
+ (TARGET_FLOATN_MODE): Likewise.
+ (arm_promoted_type): Only promote arm_fp16_type_node.
+ * config/arm/arm.h (arm_fp16_type_node): Declare.
+
2016-11-23 James Greenhalgh <james.greenhalgh@arm.com>
* config/arm/arm.c (arm_convert_to_type): Delete.
};
#undef ENTRY
-static tree arm_simd_floatHF_type_node = NULL_TREE;
+/* The user-visible __fp16 type. */
+tree arm_fp16_type_node = NULL_TREE;
static tree arm_simd_intOI_type_node = NULL_TREE;
static tree arm_simd_intEI_type_node = NULL_TREE;
static tree arm_simd_intCI_type_node = NULL_TREE;
case XImode:
return arm_simd_intXI_type_node;
case HFmode:
- return arm_simd_floatHF_type_node;
+ return arm_fp16_type_node;
case SFmode:
return float_type_node;
case DFmode:
/* Continue with standard types. */
/* The __builtin_simd{64,128}_float16 types are kept private unless
we have a scalar __fp16 type. */
- arm_simd_types[Float16x4_t].eltype = arm_simd_floatHF_type_node;
- arm_simd_types[Float16x8_t].eltype = arm_simd_floatHF_type_node;
+ arm_simd_types[Float16x4_t].eltype = arm_fp16_type_node;
+ arm_simd_types[Float16x8_t].eltype = arm_fp16_type_node;
arm_simd_types[Float32x2_t].eltype = float_type_node;
arm_simd_types[Float32x4_t].eltype = float_type_node;
static void
arm_init_fp16_builtins (void)
{
- arm_simd_floatHF_type_node = make_node (REAL_TYPE);
- TYPE_PRECISION (arm_simd_floatHF_type_node) = GET_MODE_PRECISION (HFmode);
- layout_type (arm_simd_floatHF_type_node);
+ arm_fp16_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (arm_fp16_type_node) = GET_MODE_PRECISION (HFmode);
+ layout_type (arm_fp16_type_node);
if (arm_fp16_format)
- (*lang_hooks.types.register_builtin_type) (arm_simd_floatHF_type_node,
+ (*lang_hooks.types.register_builtin_type) (arm_fp16_type_node,
"__fp16");
}
int misalignment,
bool is_packed);
static void arm_conditional_register_usage (void);
+static enum flt_eval_method arm_excess_precision (enum excess_precision_type);
static reg_class_t arm_preferred_rename_class (reg_class_t rclass);
static unsigned int arm_autovectorize_vector_sizes (void);
static int arm_default_branch_cost (bool, bool);
static unsigned int arm_elf_section_type_flags (tree decl, const char *name,
int reloc);
static void arm_expand_divmod_libfunc (rtx, machine_mode, rtx, rtx, rtx *, rtx *);
+static machine_mode arm_floatn_mode (int, bool);
\f
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
#undef TARGET_ASM_INTERNAL_LABEL
#define TARGET_ASM_INTERNAL_LABEL arm_internal_label
+#undef TARGET_FLOATN_MODE
+#define TARGET_FLOATN_MODE arm_floatn_mode
+
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
#define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall
#undef TARGET_EXPAND_DIVMOD_LIBFUNC
#define TARGET_EXPAND_DIVMOD_LIBFUNC arm_expand_divmod_libfunc
+#undef TARGET_C_EXCESS_PRECISION
+#define TARGET_C_EXCESS_PRECISION arm_excess_precision
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Obstack for minipool constant handling. */
static tree
arm_promoted_type (const_tree t)
{
- if (SCALAR_FLOAT_TYPE_P (t) && TYPE_PRECISION (t) == 16)
+ if (SCALAR_FLOAT_TYPE_P (t)
+ && TYPE_PRECISION (t) == 16
+ && TYPE_MAIN_VARIANT (t) == arm_fp16_type_node)
return float_type_node;
return NULL_TREE;
}
return default_scalar_mode_supported_p (mode);
}
+/* Set the value of FLT_EVAL_METHOD.
+ ISO/IEC TS 18661-3 defines two values that we'd like to make use of:
+
+ 0: evaluate all operations and constants, whose semantic type has at
+ most the range and precision of type float, to the range and
+ precision of float; evaluate all other operations and constants to
+ the range and precision of the semantic type;
+
+ N, where _FloatN is a supported interchange floating type
+ evaluate all operations and constants, whose semantic type has at
+ most the range and precision of _FloatN type, to the range and
+ precision of the _FloatN type; evaluate all other operations and
+ constants to the range and precision of the semantic type;
+
+ If we have the ARMv8.2-A extensions then we support _Float16 in native
+ precision, so we should set this to 16. Otherwise, we support the type,
+ but want to evaluate expressions in float precision, so set this to
+ 0. */
+
+static enum flt_eval_method
+arm_excess_precision (enum excess_precision_type type)
+{
+ switch (type)
+ {
+ case EXCESS_PRECISION_TYPE_FAST:
+ case EXCESS_PRECISION_TYPE_STANDARD:
+ /* We can calculate either in 16-bit range and precision or
+ 32-bit range and precision. Make that decision based on whether
+ we have native support for the ARMv8.2-A 16-bit floating-point
+ instructions or not. */
+ return (TARGET_VFP_FP16INST
+ ? FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16
+ : FLT_EVAL_METHOD_PROMOTE_TO_FLOAT);
+ case EXCESS_PRECISION_TYPE_IMPLICIT:
+ return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16;
+ default:
+ gcc_unreachable ();
+ }
+ return FLT_EVAL_METHOD_UNPREDICTABLE;
+}
+
+
+/* Implement TARGET_FLOATN_MODE. Make very sure that we don't provide
+ _Float16 if we are using anything other than ieee format for 16-bit
+ floating point. Otherwise, punt to the default implementation. */
+static machine_mode
+arm_floatn_mode (int n, bool extended)
+{
+ if (!extended && n == 16)
+ return arm_fp16_format == ARM_FP16_FORMAT_IEEE ? HFmode : VOIDmode;
+
+ return default_floatn_mode (n, extended);
+}
+
+
/* Set up OPERANDS for a register copy from SRC to DEST, taking care
not to early-clobber SRC registers in the process.