There are 3 patches left in the basic IEEE 128-bit floating point support for the compiler. I will submit these at the same time. They are split to make the review process similar. Patch #5 and #6 are indpendent of each other and can be applied in either order. Patch #7 assumes that patches 1-6 have been applied.
Patch #5 adds the following: * Support for the reload handlers that will be enabled in patch #7. * Adds IFmode/KFmode to other iterators as appropriate. * Adds the basic negate, absolute value, and negative absolute value support. * Adds the insns for the 128-bit pack/unpack routines. Patch #6 adds the following: * Adds support for comparisons. * Updates the cannot change mode support. Patch #7 finishes up the initial basic support. * It defines macros for IEEE 128-bit floating point users. * It defines the basic move support. * It sets up the calling sequence. * It registers the __float128 and __ibm128 keywords. * It sets up the various handler functions. * It adds 'q' and 'Q' as the suffix for IEEE 128-bit floating point. * It adds target attribute/pragma support for the IEEE 128-bit options. * It treats IEEE 128-bit in VSX register modes as vector. * It uses a unique mangling for IEEE 128-bit in VSX registers. * It moves vector modes tieable above scalar floating point. * It adds a simple minded test to make sure IEEE args are passed as vectors. Things to be done: * Work with GDB to add debug support. * Work with GLIBC to add basic software emulation support. * Work with GLIBC on other IEEE 128-bit support. * Look into Complex support. * Look into libquadmath support. * Enable -mfloat128-software if -mvsx. * Add more tests. * Fix bugs that show up if -mabi=ieeelongdouble is used. Each patch bootstraps without error and has no regressions. Are they ok to install in the trunk? This is patch #7: [gcc] 2015-08-13 Michael Meissner <meiss...@linux.vnet.ibm.com> * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define user macros for IEEE 128-bit floating point in VSX registers. * config/rs6000/rs6000.c (TARGET_C_MODE_FOR_SUFFIX): Add 'q' or 'Q' as the suffix for IEEE 128-bit floating point in VSX registers. (rs6000_c_mode_for_suffix): Likewise. (rs6000_init_hard_regno_mode_ok): Set up IEEE 128-bit floating point in VSX register mode support. (rs6000_gen_le_vsx_permute): Use ROTATE instead of VEC_SELECT for IEEE 128-bit floating point in VSX registers. (init_cumulative_args): When calling the library support functions, suppress passing values to IEEE 128-bit floating point in VSX registers in both the GPRs and VSX registers. (rs6000_function_arg): Likewise. (rs6000_arg_partial_bytes): Likewise. (rs6000_init_builtins): Likewise. (init_float128_ibm): Split 128-bit floating point support into two functions, and add support for IEEE 128-bit floating point in VSX registers. (init_float128_ieee): Likewise. (rs6000_init_libfuncs): Likewise. (rs6000_mangle_type): Use U10__float128 as the mangled type for IEEE 128-bit floating point in VSX registers. (struct rs6000_opt_var): Fix typo. (struct rs6000_float128_var): Add target attribute and pragma support for the IEEE 128-bit floating point in VSX registers. (rs6000_float128_vars): Likewise. (rs6000_inner_target_options): Likewise. * config/rs6000/rs6000.h (ALTIVEC_VECTOR_MODE): Treat IEEE 128-bit floating point in vector registers as a vector type. (MODES_TIEABLE_P): Move vector tests above floating point scalar tests, so that IEEE 128-bit floating point in VSX registers ties like a vector operand and not a scalar floating point operand. (struct rs6000_args): Add libcall field to support IEEE 128-bit floating point in VSX registers. * doc/extend.texi (additional floating types): Document PowerPC use of __float128 and __ibm128 types. * doc/invoke.texi (RS/6000 and PowerPC Options): Document -mfloat128-software and -mfloat128-none. [gcc/testsuite] 2015-08-13 Michael Meissner <meiss...@linux.vnet.ibm.com> * gcc.target/powerpc/float128-call.c: New function, test whether IEEE 128-bit floating point in VSX registers is passed correctly. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-c.c =================================================================== --- gcc/config/rs6000/rs6000-c.c (revision 226838) +++ gcc/config/rs6000/rs6000-c.c (working copy) @@ -410,6 +410,10 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi builtin_define ("__RSQRTE__"); if (TARGET_FRSQRTES) builtin_define ("__RSQRTEF__"); + if (TARGET_FLOAT128) + builtin_define ("__FLOAT128__"); + if (TARGET_FLOAT128 == FLOAT128_SW) + builtin_define ("__FLOAT128_SOFTWARE__"); if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM) { @@ -483,6 +487,11 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi { builtin_define ("__LONG_DOUBLE_128__"); builtin_define ("__LONGDOUBLE128"); + + if (TARGET_IEEEQUAD) + builtin_define ("__LONG_DOUBLE_IEEE128__"); + else + builtin_define ("__LONG_DOUBLE_IBM128__"); } switch (TARGET_CMODEL) Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 226872) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -1688,6 +1688,9 @@ static const struct attribute_spec rs600 #define TARGET_LIBGCC_SHIFT_COUNT_MODE rs6000_abi_word_mode #undef TARGET_UNWIND_WORD_MODE #define TARGET_UNWIND_WORD_MODE rs6000_abi_word_mode + +#undef TARGET_C_MODE_FOR_SUFFIX +#define TARGET_C_MODE_FOR_SUFFIX rs6000_c_mode_for_suffix /* Processor table. */ @@ -2671,6 +2674,20 @@ rs6000_init_hard_regno_mode_ok (bool glo align32 = 128; } + /* KF mode (ieee 128-bit) where we can pass it as a vector. We do not have + arithmetic, so only set the memory modes. */ + if (TARGET_FLOAT128) + { + rs6000_vector_mem[KFmode] = VECTOR_VSX; + rs6000_vector_align[KFmode] = 128; + + if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) + { + rs6000_vector_mem[TFmode] = VECTOR_VSX; + rs6000_vector_align[TFmode] = 128; + } + } + /* V2DF mode, VSX only. */ if (TARGET_VSX) { @@ -2887,6 +2904,8 @@ rs6000_init_hard_regno_mode_ok (bool glo reg_addr[V4SFmode].reload_load = CODE_FOR_reload_v4sf_di_load; reg_addr[V2DFmode].reload_store = CODE_FOR_reload_v2df_di_store; reg_addr[V2DFmode].reload_load = CODE_FOR_reload_v2df_di_load; + reg_addr[KFmode].reload_store = CODE_FOR_reload_kf_di_store; + reg_addr[KFmode].reload_load = CODE_FOR_reload_kf_di_load; reg_addr[DFmode].reload_store = CODE_FOR_reload_df_di_store; reg_addr[DFmode].reload_load = CODE_FOR_reload_df_di_load; reg_addr[DDmode].reload_store = CODE_FOR_reload_dd_di_store; @@ -2894,6 +2913,12 @@ rs6000_init_hard_regno_mode_ok (bool glo reg_addr[SFmode].reload_store = CODE_FOR_reload_sf_di_store; reg_addr[SFmode].reload_load = CODE_FOR_reload_sf_di_load; + if (TARGET_IEEEQUAD && TARGET_FLOAT128) + { + reg_addr[TFmode].reload_store = CODE_FOR_reload_tf_di_store; + reg_addr[TFmode].reload_load = CODE_FOR_reload_tf_di_load; + } + /* Only provide a reload handler for SDmode if lfiwzx/stfiwx are available. */ if (TARGET_NO_SDMODE_STACK) @@ -2947,6 +2972,8 @@ rs6000_init_hard_regno_mode_ok (bool glo reg_addr[V4SFmode].reload_load = CODE_FOR_reload_v4sf_si_load; reg_addr[V2DFmode].reload_store = CODE_FOR_reload_v2df_si_store; reg_addr[V2DFmode].reload_load = CODE_FOR_reload_v2df_si_load; + reg_addr[KFmode].reload_store = CODE_FOR_reload_kf_si_store; + reg_addr[KFmode].reload_load = CODE_FOR_reload_kf_si_load; reg_addr[DFmode].reload_store = CODE_FOR_reload_df_si_store; reg_addr[DFmode].reload_load = CODE_FOR_reload_df_si_load; reg_addr[DDmode].reload_store = CODE_FOR_reload_dd_si_store; @@ -2954,6 +2981,12 @@ rs6000_init_hard_regno_mode_ok (bool glo reg_addr[SFmode].reload_store = CODE_FOR_reload_sf_si_store; reg_addr[SFmode].reload_load = CODE_FOR_reload_sf_si_load; + if (TARGET_IEEEQUAD && TARGET_FLOAT128) + { + reg_addr[TFmode].reload_store = CODE_FOR_reload_tf_si_store; + reg_addr[TFmode].reload_load = CODE_FOR_reload_tf_si_load; + } + /* Only provide a reload handler for SDmode if lfiwzx/stfiwx are available. */ if (TARGET_NO_SDMODE_STACK) @@ -8421,8 +8454,14 @@ rs6000_const_vec (machine_mode mode) rtx rs6000_gen_le_vsx_permute (rtx source, machine_mode mode) { - rtx par = gen_rtx_PARALLEL (VOIDmode, rs6000_const_vec (mode)); - return gen_rtx_VEC_SELECT (mode, source, par); + /* Use ROTATE instead of VEC_SELECT on IEEE 128-bit floating point. */ + if (FLOAT128_VECTOR_P (mode)) + return gen_rtx_ROTATE (mode, source, GEN_INT (64)); + else + { + rtx par = gen_rtx_PARALLEL (VOIDmode, rs6000_const_vec (mode)); + return gen_rtx_VEC_SELECT (mode, source, par); + } } /* Emit a little-endian load from vector memory location SOURCE to VSX @@ -9401,6 +9440,7 @@ init_cumulative_args (CUMULATIVE_ARGS *c ? CALL_LIBCALL : CALL_NORMAL); cum->sysv_gregno = GP_ARG_MIN_REG; cum->stdarg = stdarg_p (fntype); + cum->libcall = libcall; cum->nargs_prototype = 0; if (incoming || cum->prototype) @@ -10563,9 +10603,11 @@ rs6000_function_arg (cumulative_args_t c rtx r, off; int i, k = 0; - /* Do we also need to pass this argument in the parameter - save area? */ - if (TARGET_64BIT && ! cum->prototype) + /* Do we also need to pass this argument in the parameter save area? + Library support functions for IEEE 128-bit are assumed to not need the + value passed both in GPRs and in vector registers. */ + if (TARGET_64BIT && !cum->prototype + && (!cum->libcall || !FLOAT128_VECTOR_P (elt_mode))) { int align_words = (cum->words + 1) & ~1; k = rs6000_psave_function_arg (mode, type, align_words, rvec); @@ -10796,11 +10838,14 @@ rs6000_arg_partial_bytes (cumulative_arg if (USE_ALTIVEC_FOR_ARG_P (cum, elt_mode, named)) { - /* If we are passing this arg in the fixed parameter save area - (gprs or memory) as well as VRs, we do not use the partial - bytes mechanism; instead, rs6000_function_arg will return a - PARALLEL including a memory element as necessary. */ - if (TARGET_64BIT && ! cum->prototype) + /* If we are passing this arg in the fixed parameter save area (gprs or + memory) as well as VRs, we do not use the partial bytes mechanism; + instead, rs6000_function_arg will return a PARALLEL including a memory + element as necessary. Library support functions for IEEE 128-bit are + assumed to not need the value passed both in GPRs and in vector + registers. */ + if (TARGET_64BIT && !cum->prototype + && (!cum->libcall || !FLOAT128_VECTOR_P (elt_mode))) return 0; /* Otherwise, we pass in VRs only. Check for partial copies. */ @@ -14480,6 +14525,14 @@ rs6000_init_builtins (void) layout_type (ibm128_float_type_node); SET_TYPE_MODE (ibm128_float_type_node, ibm128_mode); + if (TARGET_FLOAT128) + { + lang_hooks.types.register_builtin_type (ieee128_float_type_node, + "__float128"); + lang_hooks.types.register_builtin_type (ibm128_float_type_node, + "__ibm128"); + } + /* Initialize the modes for builtin_function_type, mapping a machine mode to tree type node. */ builtin_mode_to_type[QImode][0] = integer_type_node; @@ -15984,78 +16037,150 @@ rs6000_common_init_builtins (void) } } +/* Set up AIX/Darwin/64-bit Linux quad floating point routines. */ static void -rs6000_init_libfuncs (void) +init_float128_ibm (machine_mode mode) { - if (!TARGET_IEEEQUAD) - /* AIX/Darwin/64-bit Linux quad floating point routines. */ - if (!TARGET_XL_COMPAT) - { - set_optab_libfunc (add_optab, TFmode, "__gcc_qadd"); - set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub"); - set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul"); - set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv"); + if (!TARGET_XL_COMPAT) + { + set_optab_libfunc (add_optab, mode, "__gcc_qadd"); + set_optab_libfunc (sub_optab, mode, "__gcc_qsub"); + set_optab_libfunc (smul_optab, mode, "__gcc_qmul"); + set_optab_libfunc (sdiv_optab, mode, "__gcc_qdiv"); - if (!(TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE))) - { - set_optab_libfunc (neg_optab, TFmode, "__gcc_qneg"); - set_optab_libfunc (eq_optab, TFmode, "__gcc_qeq"); - set_optab_libfunc (ne_optab, TFmode, "__gcc_qne"); - set_optab_libfunc (gt_optab, TFmode, "__gcc_qgt"); - set_optab_libfunc (ge_optab, TFmode, "__gcc_qge"); - set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt"); - set_optab_libfunc (le_optab, TFmode, "__gcc_qle"); - - set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq"); - set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq"); - set_conv_libfunc (trunc_optab, SFmode, TFmode, "__gcc_qtos"); - set_conv_libfunc (trunc_optab, DFmode, TFmode, "__gcc_qtod"); - set_conv_libfunc (sfix_optab, SImode, TFmode, "__gcc_qtoi"); - set_conv_libfunc (ufix_optab, SImode, TFmode, "__gcc_qtou"); - set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq"); - set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq"); - } + if (!(TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE))) + { + set_optab_libfunc (neg_optab, mode, "__gcc_qneg"); + set_optab_libfunc (eq_optab, mode, "__gcc_qeq"); + set_optab_libfunc (ne_optab, mode, "__gcc_qne"); + set_optab_libfunc (gt_optab, mode, "__gcc_qgt"); + set_optab_libfunc (ge_optab, mode, "__gcc_qge"); + set_optab_libfunc (lt_optab, mode, "__gcc_qlt"); + set_optab_libfunc (le_optab, mode, "__gcc_qle"); - if (!(TARGET_HARD_FLOAT && TARGET_FPRS)) - set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord"); - } - else - { - set_optab_libfunc (add_optab, TFmode, "_xlqadd"); - set_optab_libfunc (sub_optab, TFmode, "_xlqsub"); - set_optab_libfunc (smul_optab, TFmode, "_xlqmul"); - set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv"); - } + set_conv_libfunc (sext_optab, mode, SFmode, "__gcc_stoq"); + set_conv_libfunc (sext_optab, mode, DFmode, "__gcc_dtoq"); + set_conv_libfunc (trunc_optab, SFmode, mode, "__gcc_qtos"); + set_conv_libfunc (trunc_optab, DFmode, mode, "__gcc_qtod"); + set_conv_libfunc (sfix_optab, SImode, mode, "__gcc_qtoi"); + set_conv_libfunc (ufix_optab, SImode, mode, "__gcc_qtou"); + set_conv_libfunc (sfloat_optab, mode, SImode, "__gcc_itoq"); + set_conv_libfunc (ufloat_optab, mode, SImode, "__gcc_utoq"); + } + + if (!(TARGET_HARD_FLOAT && TARGET_FPRS)) + set_optab_libfunc (unord_optab, mode, "__gcc_qunord"); + } else { - /* 32-bit SVR4 quad floating point routines. */ + set_optab_libfunc (add_optab, mode, "_xlqadd"); + set_optab_libfunc (sub_optab, mode, "_xlqsub"); + set_optab_libfunc (smul_optab, mode, "_xlqmul"); + set_optab_libfunc (sdiv_optab, mode, "_xlqdiv"); + } +} + +/* Set up IEEE 128-bit floating point routines. Use different names if the + arguments can be passed in a vector register. The historical PowerPC + implementation of IEEE 128-bit floating point used _q_<op> for the names, so + continue to use that if we can't pass IEEE 128-bit in a VSX vector register. - set_optab_libfunc (add_optab, TFmode, "_q_add"); - set_optab_libfunc (sub_optab, TFmode, "_q_sub"); - set_optab_libfunc (neg_optab, TFmode, "_q_neg"); - set_optab_libfunc (smul_optab, TFmode, "_q_mul"); - set_optab_libfunc (sdiv_optab, TFmode, "_q_div"); + Add _vector to clarify that this function is called with the argument in a + vector register, and _fpr when we are not passing IEEE 128-bit in a vector + register. */ + +static void +init_float128_ieee (machine_mode mode) +{ + if (FLOAT128_VECTOR_P (mode)) + { + set_optab_libfunc (add_optab, mode, "__addkf3"); + set_optab_libfunc (sub_optab, mode, "__subkf3"); + set_optab_libfunc (neg_optab, mode, "__negkf2"); + set_optab_libfunc (smul_optab, mode, "__mulkf3"); + set_optab_libfunc (sdiv_optab, mode, "__divkf3"); + set_optab_libfunc (sqrt_optab, mode, "__sqrtkf2"); + set_optab_libfunc (abs_optab, mode, "__abstkf2"); + + set_optab_libfunc (eq_optab, mode, "__eqkf2"); + set_optab_libfunc (ne_optab, mode, "__nekf2"); + set_optab_libfunc (gt_optab, mode, "__gtkf2"); + set_optab_libfunc (ge_optab, mode, "__gekf2"); + set_optab_libfunc (lt_optab, mode, "__ltkf2"); + set_optab_libfunc (le_optab, mode, "__lekf2"); + set_optab_libfunc (unord_optab, mode, "__unordkf2"); + set_optab_libfunc (cmp_optab, mode, "__cmpkf2"); + + set_conv_libfunc (sext_optab, mode, SFmode, "__extendsfkf2"); + set_conv_libfunc (sext_optab, mode, DFmode, "__extenddfkf2"); + set_conv_libfunc (trunc_optab, SFmode, mode, "__trunckfsf2"); + set_conv_libfunc (trunc_optab, DFmode, mode, "__trunckfdf2"); + + set_conv_libfunc (sfix_optab, SImode, mode, "__fixkfsi"); + set_conv_libfunc (ufix_optab, SImode, mode, "__fixunskfsi"); + set_conv_libfunc (sfix_optab, DImode, mode, "__fixkfdi"); + set_conv_libfunc (ufix_optab, DImode, mode, "__fixunskfdi"); + + set_conv_libfunc (sfloat_optab, mode, SImode, "__floatsikf"); + set_conv_libfunc (ufloat_optab, mode, SImode, "__floatunsikf"); + set_conv_libfunc (sfloat_optab, mode, DImode, "__floatdikf"); + set_conv_libfunc (ufloat_optab, mode, DImode, "__floatundikf"); + + if (mode == KFmode) + { + set_conv_libfunc (sext_optab, IFmode, KFmode, "__extendkftf2"); + set_conv_libfunc (trunc_optab, KFmode, IFmode, "__trunctfkf2"); + + if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) + { + set_conv_libfunc (sext_optab, TFmode, KFmode, "__extendkftf2"); + set_conv_libfunc (trunc_optab, mode, KFmode, "__trunctfkf2"); + } + } + } + + else + { + set_optab_libfunc (add_optab, mode, "_q_add"); + set_optab_libfunc (sub_optab, mode, "_q_sub"); + set_optab_libfunc (neg_optab, mode, "_q_neg"); + set_optab_libfunc (smul_optab, mode, "_q_mul"); + set_optab_libfunc (sdiv_optab, mode, "_q_div"); if (TARGET_PPC_GPOPT) - set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt"); + set_optab_libfunc (sqrt_optab, mode, "_q_sqrt"); - set_optab_libfunc (eq_optab, TFmode, "_q_feq"); - set_optab_libfunc (ne_optab, TFmode, "_q_fne"); - set_optab_libfunc (gt_optab, TFmode, "_q_fgt"); - set_optab_libfunc (ge_optab, TFmode, "_q_fge"); - set_optab_libfunc (lt_optab, TFmode, "_q_flt"); - set_optab_libfunc (le_optab, TFmode, "_q_fle"); - - set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq"); - set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq"); - set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos"); - set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod"); - set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi"); - set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou"); - set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq"); - set_conv_libfunc (ufloat_optab, TFmode, SImode, "_q_utoq"); + set_optab_libfunc (eq_optab, mode, "_q_feq"); + set_optab_libfunc (ne_optab, mode, "_q_fne"); + set_optab_libfunc (gt_optab, mode, "_q_fgt"); + set_optab_libfunc (ge_optab, mode, "_q_fge"); + set_optab_libfunc (lt_optab, mode, "_q_flt"); + set_optab_libfunc (le_optab, mode, "_q_fle"); + + set_conv_libfunc (sext_optab, mode, SFmode, "_q_stoq"); + set_conv_libfunc (sext_optab, mode, DFmode, "_q_dtoq"); + set_conv_libfunc (trunc_optab, SFmode, mode, "_q_qtos"); + set_conv_libfunc (trunc_optab, DFmode, mode, "_q_qtod"); + set_conv_libfunc (sfix_optab, SImode, mode, "_q_qtoi"); + set_conv_libfunc (ufix_optab, SImode, mode, "_q_qtou"); + set_conv_libfunc (sfloat_optab, mode, SImode, "_q_itoq"); + set_conv_libfunc (ufloat_optab, mode, SImode, "_q_utoq"); } } +static void +rs6000_init_libfuncs (void) +{ + /* AIX/Darwin/64-bit Linux quad floating point routines. */ + init_float128_ibm (IFmode); + if (!TARGET_IEEEQUAD) + init_float128_ibm (TFmode); + + /* IEEE 128-bit including 32-bit SVR4 quad floating point routines. */ + init_float128_ieee (KFmode); + if (TARGET_IEEEQUAD) + init_float128_ieee (TFmode); +} + /* Expand a block clear operation, and return 1 if successful. Return 0 if we should let the compiler generate normal code. @@ -29763,9 +29888,13 @@ rs6000_mangle_type (const_tree type) if (type == bool_int_type_node) return "U6__booli"; if (type == bool_long_type_node) return "U6__booll"; + /* Use a unique name for __float128 rather than trying to use "e" or "g". */ + if (type == ieee128_float_type_node && TARGET_FLOAT128) + return "U10__float128"; + /* Mangle IBM extended float long double as `g' (__float128) on powerpc*-linux where long-double-64 previously was the default. */ - if (TYPE_MAIN_VARIANT (type) == long_double_type_node + if (type == long_double_type_node && TARGET_ELF && TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD) @@ -33014,6 +33143,26 @@ rs6000_vector_mode_supported_p (machine_ return false; } +/* Target hook for c_mode_for_suffix. */ +static machine_mode +rs6000_c_mode_for_suffix (char suffix) +{ + if (TARGET_FLOAT128 && TARGET_LONG_DOUBLE_128) + { + if (suffix == 'q' || suffix == 'Q') + return (TARGET_IEEEQUAD) ? TFmode : KFmode; + + /* At the moment, we are not defining a suffix for IBM extended double. + If/when the default for -mabi=ieeelongdouble is changed, and we want + to support __ibm128 constants in legacy library code, we may need to + re-evalaute this decision. Currently, c-lex.c only supports 'w' and + 'q' as machine dependent suffixes. The x86_64 port uses 'w' for + __float80 constants. */ + } + + return VOIDmode; +} + /* Target hook for invalid_arg_for_unprototyped_fn. */ static const char * invalid_arg_for_unprototyped_fn (const_tree typelist, const_tree funcdecl, const_tree val) @@ -33175,7 +33324,7 @@ static struct rs6000_opt_mask const rs60 struct rs6000_opt_var { const char *name; /* option name */ size_t global_offset; /* offset of the option in global_options. */ - size_t target_offset; /* offset of the option in target optiosn. */ + size_t target_offset; /* offset of the option in target options. */ }; static struct rs6000_opt_var const rs6000_opt_vars[] = @@ -33230,6 +33379,21 @@ static struct rs6000_opt_var const rs600 offsetof (struct cl_target_option, x_rs6000_warn_cell_microcode), }, }; +/* Float128 options we want to support inside attribute((target)) and #pragma + GCC target operations. */ + +struct rs6000_float128_var { + const char *name; /* option name. */ + enum float128_type_t type; /* float128 type. */ +}; + +static struct rs6000_float128_var const rs6000_float128_vars[] = +{ + { "float128-none", FLOAT128_NONE }, + { "float128-software", FLOAT128_SW }, + { "float128-sw", FLOAT128_SW }, +}; + /* Inner function to handle attribute((target("..."))) and #pragma GCC target parsing. Return true if there were no errors. */ @@ -33322,6 +33486,18 @@ rs6000_inner_target_options (tree args, break; } + if (error_p && !not_valid_p && !invert) + { + for (i = 0; i < ARRAY_SIZE (rs6000_float128_vars); i++) + if (strcmp (r, rs6000_float128_vars[i].name) == 0) + { + TARGET_FLOAT128 = rs6000_float128_vars[i].type; + error_p = false; + not_valid_p = false; + break; + } + } + if (error_p && !not_valid_p) { for (i = 0; i < ARRAY_SIZE (rs6000_opt_vars); i++) Index: gcc/config/rs6000/rs6000.h =================================================================== --- gcc/config/rs6000/rs6000.h (revision 226838) +++ gcc/config/rs6000/rs6000.h (working copy) @@ -1217,11 +1217,16 @@ enum data_align { align_abi, align_opt, ((MODE) == V4SFmode \ || (MODE) == V2DFmode) \ -#define ALTIVEC_VECTOR_MODE(MODE) \ - ((MODE) == V16QImode \ - || (MODE) == V8HImode \ - || (MODE) == V4SFmode \ - || (MODE) == V4SImode) +/* Note KFmode and possibly TFmode (i.e. IEEE 128-bit floating point) are not + really a vector, but we want to treat it as a vector for moves, and + such. */ + +#define ALTIVEC_VECTOR_MODE(MODE) \ + ((MODE) == V16QImode \ + || (MODE) == V8HImode \ + || (MODE) == V4SFmode \ + || (MODE) == V4SImode \ + || FLOAT128_VECTOR_P (MODE)) #define ALTIVEC_OR_VSX_VECTOR_MODE(MODE) \ (ALTIVEC_VECTOR_MODE (MODE) || VSX_VECTOR_MODE (MODE) \ @@ -1248,12 +1253,19 @@ enum data_align { align_abi, align_opt, PTImode cannot tie with other modes because PTImode is restricted to even GPR registers, and TImode can go in any GPR as well as VSX registers (PR - 57744). */ + 57744). + + Altivec/VSX vector tests were moved ahead of scalar float mode, so that IEEE + 128-bit floating point on VSX systems ties with other vectors. */ #define MODES_TIEABLE_P(MODE1, MODE2) \ ((MODE1) == PTImode \ ? (MODE2) == PTImode \ : (MODE2) == PTImode \ ? 0 \ + : ALTIVEC_OR_VSX_VECTOR_MODE (MODE1) \ + ? ALTIVEC_OR_VSX_VECTOR_MODE (MODE2) \ + : ALTIVEC_OR_VSX_VECTOR_MODE (MODE2) \ + ? 0 \ : SCALAR_FLOAT_MODE_P (MODE1) \ ? SCALAR_FLOAT_MODE_P (MODE2) \ : SCALAR_FLOAT_MODE_P (MODE2) \ @@ -1266,10 +1278,6 @@ enum data_align { align_abi, align_opt, ? SPE_VECTOR_MODE (MODE2) \ : SPE_VECTOR_MODE (MODE2) \ ? 0 \ - : ALTIVEC_OR_VSX_VECTOR_MODE (MODE1) \ - ? ALTIVEC_OR_VSX_VECTOR_MODE (MODE2) \ - : ALTIVEC_OR_VSX_VECTOR_MODE (MODE2) \ - ? 0 \ : 1) /* Post-reload, we can't use any new AltiVec registers, as we already @@ -1801,6 +1809,7 @@ typedef struct rs6000_args GPR space (darwin64) */ int named; /* false for varargs params */ int escapes; /* if function visible outside tu */ + int libcall; /* If this is a compiler generated call. */ } CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 226838) +++ gcc/doc/extend.texi (working copy) @@ -929,6 +929,7 @@ examine and set these two fictitious var @cindex additional floating types @cindex @code{__float80} data type @cindex @code{__float128} data type +@cindex @code{__ibm128} data type @cindex @code{w} floating point suffix @cindex @code{q} floating point suffix @cindex @code{W} floating point suffix @@ -941,19 +942,39 @@ Support for additional types includes th add, subtract, multiply, divide; unary arithmetic operators; relational operators; equality operators; and conversions to and from integer and other floating types. Use a suffix @samp{w} or @samp{W} -in a literal constant of type @code{__float80} and @samp{q} or @samp{Q} -for @code{_float128}. You can declare complex types using the -corresponding internal complex type, @code{XCmode} for @code{__float80} -type and @code{TCmode} for @code{__float128} type: +in a literal constant of type @code{__float80} or type +@code{__ibm128}. Use a suffix @samp{q} or @samp{Q} for @code{_float128}. + +On the i386, x86_64, IA-64, and HP-UX targets, you can declare complex +types using the corresponding internal complex type, @code{XCmode} for +@code{__float80} type and @code{TCmode} for @code{__float128} type: @smallexample typedef _Complex float __attribute__((mode(TC))) _Complex128; typedef _Complex float __attribute__((mode(XC))) _Complex80; @end smallexample +On PowerPC Linux, Freebsd and Darwin systems, the default for +@code{long double} is to use the IBM extended floating point format +that uses a pair of @code{double} values to extend the precision. +This means that the mode @code{TCmode} was already used by the +traditional IBM long double format, and you would need to use the mode +@code{KCmode}: + +@smallexample +typedef _Complex float __attribute__((mode(KC))) _Complex128; +@end smallexample + Not all targets support additional floating-point types. @code{__float80} and @code{__float128} types are supported on x86 and IA-64 targets. -The @code{__float128} type is supported on hppa HP-UX targets. +The @code{__float128} type is supported on hppa HP-UX. +The @code{__float128} type is supported on PowerPC systems by default +if the vector scalar instruction set (VSX) is enabled. + +On the PowerPC, @code{__ibm128} provides access to the IBM extended +double format, and it is intended to be used by the library functions +that handle conversions if/when long double is changed to be IEEE +128-bit floating point. @node Half-Precision @section Half-Precision Floating Point @@ -13318,6 +13339,8 @@ uint64_t __builtin_ppc_get_timebase (); unsigned long __builtin_ppc_mftb (); double __builtin_unpack_longdouble (long double, int); long double __builtin_pack_longdouble (double, double); +double __builtin_unpack_ibm128 (long double, int); +__ibm128 __builtin_pack_ibm128 (double, double); @end smallexample The @code{vec_rsqrt}, @code{__builtin_rsqrt}, and Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (revision 226838) +++ gcc/doc/invoke.texi (working copy) @@ -940,7 +940,8 @@ See RS/6000 and PowerPC Options. -mquad-memory-atomic -mno-quad-memory-atomic @gol -mcompat-align-parm -mno-compat-align-parm @gol -mupper-regs-df -mno-upper-regs-df -mupper-regs-sf -mno-upper-regs-sf @gol --mupper-regs -mno-upper-regs} +-mupper-regs -mno-upper-regs @gol +-mfloat128-software -mfloat128-none} @emph{RX Options} @gccoptlist{-m64bit-doubles -m32bit-doubles -fpu -nofpu@gol @@ -19410,6 +19411,20 @@ floating point register set, depending o If the @option{-mno-upper-regs} option is used, it turns off both @option{-mupper-regs-sf} and @option{-mupper-regs-df} options. +@item -mfloat128-software +@opindex mfloat128-software +Enable the @var{__float128} keyword for IEEE 128-bit floating point +and use software emulation for IEEE 128-bit floating point. +@option{-mfloat128-software} option is enabled by default with either +of the the @option{-mcpu=power7} or @option{-mcpu=power8} options. + +The VSX instruction set must be enabled to use the +@option{-mfloat128-software} option. + +@item -mfloat128-none +@opindex mfloat128-none +Disable the use of the @var{__float128} keyword. + @item -mfloat-gprs=@var{yes/single/double/no} @itemx -mfloat-gprs @opindex mfloat-gprs Index: gcc/testsuite/gcc.target/powerpc/float128-call.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/float128-call.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/float128-call.c (revision 0) @@ -0,0 +1,27 @@ +/* { dg-do compile { target { powerpc*-*-linux* } } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */ +/* { dg-require-effective-target powerpc_vsx_ok } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power7" } } */ +/* { dg-options "-O2 -mcpu=power7 -mfloat128-software -mno-regnames" } */ + +#ifndef __FLOAT128_SOFTWARE__ +#error "-mfloat128-software is not supported." +#endif + +#ifdef __LONG_DOUBLE_IEEE128__ +#define TYPE long double +#define ONE 1.0L + +#else +#define TYPE __float128 +#define ONE 1.0Q +#endif + +/* Test to make sure vector registers are used for passing IEEE 128-bit + floating point values and returning them. Also make sure the 'q' suffix is + handled. */ +TYPE one (void) { return ONE; } +void store (TYPE a, TYPE *p) { *p = a; } + +/* { dg-final { scan-assembler "lxvd2x 34" } } */ +/* { dg-final { scan-assembler "stxvd2x 34" } } */