This patch adds a scalar_float_mode class, which wraps a mode enum that is known to satisfy SCALAR_FLOAT_MODE_P. Things like "SFmode" now give a scalar_float_mode object instead of a machine_mode. This in turn needs a change to the real.h format_helper, so that it can accept both machine_modes and scalar_float_modes.
gcc/ 2016-11-30 Richard Sandiford <richard.sandif...@arm.com> Alan Hayward <alan.hayw...@arm.com> David Sherwood <david.sherw...@arm.com> * coretypes.h (scalar_float_mode): New type. * machmode.h (PROTECT_ENUM_CONVERSION): New macro. (is_a): New function. (as_a): Likewise. (dyn_cast): Likewise. (scalar_float_mode): New class. (scalar_float_mode::includes_p): New function. (scalar_float_mode::from_int): Likewise. * real.h (FLOAT_MODE_FORMAT): Use as_a <scalar_float_mode>. (format_helper::format_helper): Turn into a template. * genmodes.c (get_mode_class): New function. (emit_insn_modes_h): Give modes the class returned by get_mode_class, or machine_mode if none. * config/aarch64/aarch64.c (aarch64_simd_valid_immediate): Use as_a <scalar_float_mode>. * dwarf2out.c (mem_loc_descriptor): Likewise. (insert_float): Likewise. (add_const_value_attribute): Likewise. * simplify-rtx.c (simplify_immed_subreg): Likewise. * optabs.c (expand_absneg_bit): Take a scalar_float_mode. (expand_unop): Update accordingly. (expand_abs_nojump): Likewise. (expand_copysign_absneg): Take a scalar_float_mode. (expand_copysign_bit): Likewise. (expand_copysign): Update accordingly. gcc/ada/ 2016-11-24 Richard Sandiford <richard.sandif...@arm.com> Alan Hayward <alan.hayw...@arm.com> David Sherwood <david.sherw...@arm.com> * gcc-interface/utils.c (gnat_type_for_mode): Use is_a <scalar_float_mode> instead of SCALAR_FLOAT_MODE_P. diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 0ae381f..29e5203 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -3411,8 +3411,10 @@ gnat_type_for_mode (machine_mode mode, int unsignedp) if (COMPLEX_MODE_P (mode)) return NULL_TREE; - if (SCALAR_FLOAT_MODE_P (mode)) - return float_type_for_precision (GET_MODE_PRECISION (mode), mode); + scalar_float_mode float_mode; + if (is_a <scalar_float_mode> (mode, &float_mode)) + return float_type_for_precision (GET_MODE_PRECISION (float_mode), + float_mode); if (SCALAR_INT_MODE_P (mode)) return gnat_type_for_size (GET_MODE_BITSIZE (mode), unsignedp); diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 944577d..cc97b7a 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -11035,8 +11035,12 @@ aarch64_simd_valid_immediate (rtx op, machine_mode mode, bool inverse, if (info) { - info->value = CONST_VECTOR_ELT (op, 0); - info->element_width = GET_MODE_BITSIZE (GET_MODE (info->value)); + rtx elt = CONST_VECTOR_ELT (op, 0); + scalar_float_mode elt_mode + = as_a <scalar_float_mode> (GET_MODE (elt)); + + info->value = elt; + info->element_width = GET_MODE_BITSIZE (elt_mode); info->mvn = false; info->shift = 0; } diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 9f81995..f4c1859 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -56,6 +56,7 @@ struct rtx_def; typedef struct rtx_def *rtx; typedef const struct rtx_def *const_rtx; class machine_mode; +class scalar_float_mode; template<typename> class opt_mode; /* Subclasses of rtx_def, using indentation to show the class diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 8dc8523..5130b64 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -15121,7 +15121,8 @@ mem_loc_descriptor (rtx rtl, machine_mode mode, else #endif { - unsigned int length = GET_MODE_SIZE (mode); + scalar_float_mode float_mode = as_a <scalar_float_mode> (mode); + unsigned int length = GET_MODE_SIZE (float_mode); unsigned char *array = ggc_vec_alloc<unsigned char> (length); insert_float (rtl, array); @@ -18343,11 +18344,12 @@ insert_float (const_rtx rtl, unsigned char *array) { long val[4]; int i; + scalar_float_mode mode = as_a <scalar_float_mode> (GET_MODE (rtl)); - real_to_target (val, CONST_DOUBLE_REAL_VALUE (rtl), GET_MODE (rtl)); + real_to_target (val, CONST_DOUBLE_REAL_VALUE (rtl), mode); /* real_to_target puts 32-bit pieces in each long. Pack them. */ - for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++) + for (i = 0; i < GET_MODE_SIZE (mode) / 4; i++) { insert_int (val[i], 4, array); array += 4; @@ -18391,21 +18393,19 @@ add_const_value_attribute (dw_die_ref die, rtx rtl) floating-point constant. A CONST_DOUBLE is used whenever the constant requires more than one word in order to be adequately represented. */ - { - machine_mode mode = GET_MODE (rtl); - - if (TARGET_SUPPORTS_WIDE_INT == 0 && !SCALAR_FLOAT_MODE_P (mode)) - add_AT_double (die, DW_AT_const_value, - CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); - else - { - unsigned int length = GET_MODE_SIZE (mode); - unsigned char *array = ggc_vec_alloc<unsigned char> (length); + if (TARGET_SUPPORTS_WIDE_INT == 0 + && !SCALAR_FLOAT_MODE_P (GET_MODE (rtl))) + add_AT_double (die, DW_AT_const_value, + CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl)); + else + { + scalar_float_mode mode = as_a <scalar_float_mode> (GET_MODE (rtl)); + unsigned int length = GET_MODE_SIZE (mode); + unsigned char *array = ggc_vec_alloc<unsigned char> (length); - insert_float (rtl, array); - add_AT_vec (die, DW_AT_const_value, length / 4, 4, array); - } - } + insert_float (rtl, array); + add_AT_vec (die, DW_AT_const_value, length / 4, 4, array); + } return true; case CONST_VECTOR: diff --git a/gcc/genmodes.c b/gcc/genmodes.c index 4dbced2..3cc426e 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -1129,6 +1129,23 @@ mode_unit_precision_inline (machine_mode_enum mode)\n\ }\n"); } +/* Return the best machine mode class for MODE, or null if machine_mode + should be used. */ + +static const char * +get_mode_class (struct mode_data *mode) +{ + switch (mode->cl) + { + case MODE_FLOAT: + case MODE_DECIMAL_FLOAT: + return "scalar_float_mode"; + + default: + return NULL; + } +} + static void emit_insn_modes_h (void) { @@ -1158,8 +1175,12 @@ enum machine_mode_enum\n{"); printf ("#ifdef USE_ENUM_MODES\n"); printf ("#define %smode E_%smode\n", m->name, m->name); printf ("#else\n"); - printf ("#define %smode (machine_mode (E_%smode))\n", - m->name, m->name); + if (const char *mode_class = get_mode_class (m)) + printf ("#define %smode (%s::from_int (E_%smode))\n", + m->name, mode_class, m->name); + else + printf ("#define %smode (machine_mode (E_%smode))\n", + m->name, m->name); printf ("#endif\n"); } diff --git a/gcc/machmode.h b/gcc/machmode.h index 44a8ad4..996f991 100644 --- a/gcc/machmode.h +++ b/gcc/machmode.h @@ -29,6 +29,16 @@ extern const unsigned short mode_unit_precision[NUM_MACHINE_MODES]; extern const unsigned char mode_wider[NUM_MACHINE_MODES]; extern const unsigned char mode_2xwider[NUM_MACHINE_MODES]; +/* Allow direct conversion of enums to specific mode classes only + when USE_ENUM_MODES is defined. This is only intended for use + by gencondmd, so that it can tell more easily when .md conditions + are always false. */ +#ifdef USE_ENUM_MODES +#define PROTECT_ENUM_CONVERSION public +#else +#define PROTECT_ENUM_CONVERSION protected +#endif + /* Get the name of mode MODE as a string. */ extern const char * const mode_name[NUM_MACHINE_MODES]; @@ -237,6 +247,85 @@ opt_mode<T>::exists (U *mode) const return false; } +/* Return true if mode M has type T. */ + +template<typename T> +inline bool +is_a (machine_mode_enum m) +{ + return T::includes_p (m); +} + +/* Assert that mode M has type T, and return it in that form. */ + +template<typename T> +inline T +as_a (machine_mode_enum m) +{ + gcc_checking_assert (T::includes_p (m)); + return T::from_int (m); +} + +/* Convert M to an opt_mode<T>. */ + +template<typename T> +inline opt_mode<T> +dyn_cast (machine_mode_enum m) +{ + if (T::includes_p (m)) + return T::from_int (m); + return opt_mode<T> (); +} + +/* Return true if mode M has type T, storing it as a T in *RESULT + if so. */ + +template<typename T, typename U> +inline bool +is_a (machine_mode_enum m, U *result) +{ + if (T::includes_p (m)) + { + *result = T::from_int (m); + return true; + } + return false; +} + +/* Represents a machine mode that is known to be a SCALAR_FLOAT_MODE_P. */ +class scalar_float_mode +{ +public: + ALWAYS_INLINE scalar_float_mode () {} + ALWAYS_INLINE operator machine_mode_enum () const { return m_mode; } + + static bool includes_p (machine_mode_enum); + static scalar_float_mode from_int (int i); + +PROTECT_ENUM_CONVERSION: + ALWAYS_INLINE scalar_float_mode (machine_mode_enum m) : m_mode (m) {} + +protected: + machine_mode_enum m_mode; +}; + +/* Return true if M is a scalar_float_mode. */ + +inline bool +scalar_float_mode::includes_p (machine_mode_enum m) +{ + return SCALAR_FLOAT_MODE_P (m); +} + +/* Return M as a scalar_float_mode. This function should only be used by + utility functions; general code should use as_a<T> instead. */ + +ALWAYS_INLINE scalar_float_mode +scalar_float_mode::from_int (int i) +{ + return machine_mode_enum (i); +} + /* Represents a general machine mode (scalar or non-scalar). */ class machine_mode { diff --git a/gcc/optabs.c b/gcc/optabs.c index 5dab1b4..58c26e4 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -2550,7 +2550,7 @@ lowpart_subreg_maybe_copy (machine_mode omode, rtx val, logical operation on the sign bit. */ static rtx -expand_absneg_bit (enum rtx_code code, machine_mode mode, +expand_absneg_bit (enum rtx_code code, scalar_float_mode mode, rtx op0, rtx target) { const struct real_format *fmt; @@ -2696,6 +2696,7 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target, { enum mode_class mclass = GET_MODE_CLASS (mode); machine_mode wider_mode; + scalar_float_mode float_mode; rtx temp; rtx libfunc; @@ -2886,9 +2887,9 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target, if (optab_to_code (unoptab) == NEG) { /* Try negating floating point values by flipping the sign bit. */ - if (SCALAR_FLOAT_MODE_P (mode)) + if (is_a <scalar_float_mode> (mode, &float_mode)) { - temp = expand_absneg_bit (NEG, mode, op0, target); + temp = expand_absneg_bit (NEG, float_mode, op0, target); if (temp) return temp; } @@ -3085,9 +3086,10 @@ expand_abs_nojump (machine_mode mode, rtx op0, rtx target, return temp; /* For floating point modes, try clearing the sign bit. */ - if (SCALAR_FLOAT_MODE_P (mode)) + scalar_float_mode float_mode; + if (is_a <scalar_float_mode> (mode, &float_mode)) { - temp = expand_absneg_bit (ABS, mode, op0, target); + temp = expand_absneg_bit (ABS, float_mode, op0, target); if (temp) return temp; } @@ -3241,7 +3243,7 @@ expand_one_cmpl_abs_nojump (machine_mode mode, rtx op0, rtx target) and not playing with subregs so much, will help the register allocator. */ static rtx -expand_copysign_absneg (machine_mode mode, rtx op0, rtx op1, rtx target, +expand_copysign_absneg (scalar_float_mode mode, rtx op0, rtx op1, rtx target, int bitpos, bool op0_is_abs) { machine_mode imode; @@ -3325,7 +3327,7 @@ expand_copysign_absneg (machine_mode mode, rtx op0, rtx op1, rtx target, is true if op0 is known to have its sign bit clear. */ static rtx -expand_copysign_bit (machine_mode mode, rtx op0, rtx op1, rtx target, +expand_copysign_bit (scalar_float_mode mode, rtx op0, rtx op1, rtx target, int bitpos, bool op0_is_abs) { machine_mode imode; @@ -3423,12 +3425,12 @@ expand_copysign_bit (machine_mode mode, rtx op0, rtx op1, rtx target, rtx expand_copysign (rtx op0, rtx op1, rtx target) { - machine_mode mode = GET_MODE (op0); + scalar_float_mode mode; const struct real_format *fmt; bool op0_is_abs; rtx temp; - gcc_assert (SCALAR_FLOAT_MODE_P (mode)); + mode = as_a <scalar_float_mode> (GET_MODE (op0)); gcc_assert (GET_MODE (op1) == mode); /* First try to do it with a special instruction. */ diff --git a/gcc/real.h b/gcc/real.h index 59af580..e861b03 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -183,8 +183,7 @@ extern const struct real_format * : (gcc_unreachable (), 0)]) #define FLOAT_MODE_FORMAT(MODE) \ - (REAL_MODE_FORMAT (SCALAR_FLOAT_MODE_P (MODE)? (MODE) \ - : GET_MODE_INNER (MODE))) + (REAL_MODE_FORMAT (as_a <scalar_float_mode> (GET_MODE_INNER (MODE)))) /* The following macro determines whether the floating point format is composite, i.e. may contain non-consecutive mantissa bits, in which @@ -212,7 +211,7 @@ class format_helper { public: format_helper (const real_format *format) : m_format (format) {} - format_helper (machine_mode m); + template<typename T> format_helper (const T &); const real_format *operator-> () const { return m_format; } operator const real_format *() const { return m_format; } @@ -222,7 +221,8 @@ private: const real_format *m_format; }; -inline format_helper::format_helper (machine_mode m) +template<typename T> +inline format_helper::format_helper (const T &m) : m_format (m == VOIDmode ? 0 : REAL_MODE_FORMAT (m)) {} diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 0251bd4..907c1e7 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -5816,9 +5816,11 @@ simplify_immed_subreg (machine_mode outermode, rtx op, { /* This is big enough for anything on the platform. */ long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32]; - int bitsize = GET_MODE_BITSIZE (GET_MODE (el)); + scalar_float_mode el_mode; + + el_mode = as_a <scalar_float_mode> (GET_MODE (el)); + int bitsize = GET_MODE_BITSIZE (el_mode); - gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el))); gcc_assert (bitsize <= elem_bitsize); gcc_assert (bitsize % value_bit == 0);