Index: gcc/config/rs6000/rs6000-cpus.def =================================================================== --- gcc/config/rs6000/rs6000-cpus.def (revision 227594) +++ gcc/config/rs6000/rs6000-cpus.def (working copy) @@ -80,6 +80,7 @@ | OPTION_MASK_DIRECT_MOVE \ | OPTION_MASK_DLMZB \ | OPTION_MASK_EFFICIENT_UNALIGNED_VSX \ + | OPTION_MASK_FLOAT128 \ | OPTION_MASK_FPRND \ | OPTION_MASK_HTM \ | OPTION_MASK_ISEL \ Index: gcc/config/rs6000/rs6000-c.c =================================================================== --- gcc/config/rs6000/rs6000-c.c (revision 227594) +++ gcc/config/rs6000/rs6000-c.c (working copy) @@ -410,6 +410,8 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi builtin_define ("__RSQRTE__"); if (TARGET_FRSQRTES) builtin_define ("__RSQRTEF__"); + if (TARGET_FLOAT128) + builtin_define ("__FLOAT128__"); if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM) { @@ -483,6 +485,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.opt =================================================================== --- gcc/config/rs6000/rs6000.opt (revision 227594) +++ gcc/config/rs6000/rs6000.opt (working copy) @@ -601,18 +601,6 @@ moptimize-swaps Target Undocumented Var(rs6000_optimize_swaps) Init(1) Save Analyze and remove doubleword swaps from VSX computations. -mfloat128- -Target RejectNegative Joined Enum(float128_type_t) Var(TARGET_FLOAT128) Init(FLOAT128_UNSET) Save --mfloat128-{software,none} - Specify how IEEE 128-bit floating point is used. - -Enum -Name(float128_type_t) Type(enum float128_type_t) - -EnumValue -Enum(float128_type_t) String(none) Value(FLOAT128_NONE) - -EnumValue -Enum(float128_type_t) String(software) Value(FLOAT128_SW) - -EnumValue -Enum(float128_type_t) String(sw) Value(FLOAT128_SW) +mfloat128 +Target Report Mask(FLOAT128) Var(rs6000_isa_flags) +Enable/disable IEEE 128-bit floating point via the __float128 keyword. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 227594) +++ 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. */ @@ -1786,16 +1789,6 @@ rs6000_hard_regno_mode_ok (int regno, ma && IN_RANGE (last_regno, FIRST_GPR_REGNO, LAST_GPR_REGNO) && ((regno & 1) == 0)); - /* If we don't allow 128-bit binary floating point, disallow the 128-bit - types from going in any registers. Similarly if __float128 is not - supported, don't allow __float128/__ibm128 types. */ - if (!TARGET_LONG_DOUBLE_128 - && (mode == TFmode || mode == KFmode || mode == IFmode)) - return false; - - if (!TARGET_FLOAT128 && (mode == KFmode || mode == IFmode)) - return false; - /* VSX registers that overlap the FPR registers are larger than for non-VSX implementations. Don't allow an item to be split between a FP register and an Altivec register. Allow TImode in all VSX registers if the user @@ -2069,7 +2062,6 @@ rs6000_debug_reg_global (void) const char *trace_str; const char *abi_str; const char *cmodel_str; - const char *float128_str; struct cl_target_option cl_opts; /* Modes we want tieable information on. */ @@ -2435,15 +2427,6 @@ rs6000_debug_reg_global (void) fprintf (stderr, DEBUG_FMT_S, "e500_double", (TARGET_E500_DOUBLE ? "true" : "false")); - switch (TARGET_FLOAT128) - { - case FLOAT128_NONE: float128_str = "none"; break; - case FLOAT128_SW: float128_str = "software"; break; - default: float128_str = "unknown"; break; - } - - fprintf (stderr, DEBUG_FMT_S, "float128", float128_str); - if (TARGET_LINK_STACK) fprintf (stderr, DEBUG_FMT_S, "link_stack", "true"); @@ -2526,6 +2509,7 @@ rs6000_setup_reg_addr_masks (void) && (rc == RELOAD_REG_GPR || rc == RELOAD_REG_FPR) && GET_MODE_SIZE (m2) <= 8 && !VECTOR_MODE_P (m2) + && !FLOAT128_VECTOR_P (m2) && !COMPLEX_MODE_P (m2) && !indexed_only_p && !(TARGET_E500_DOUBLE && GET_MODE_SIZE (m2) == 8)) @@ -2671,6 +2655,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) { @@ -2864,7 +2862,7 @@ rs6000_init_hard_regno_mode_ok (bool glo if (TARGET_FLOAT128) { rs6000_constraints[RS6000_CONSTRAINT_wq] = VSX_REGS; /* KFmode */ - if (rs6000_ieeequad) + if (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) rs6000_constraints[RS6000_CONSTRAINT_wp] = VSX_REGS; /* TFmode */ } @@ -2887,6 +2885,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 +2894,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_LONG_DOUBLE_128 && 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 +2953,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 +2962,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_LONG_DOUBLE_128 && 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) @@ -3709,13 +3723,6 @@ rs6000_option_override_internal (bool gl && optimize >= 3) rs6000_isa_flags |= OPTION_MASK_P8_FUSION_SIGN; - /* Set the appropriate IEEE 128-bit floating option. Do not enable float128 - support by default until the libgcc support is added. */ - if (TARGET_FLOAT128 == FLOAT128_UNSET) - TARGET_FLOAT128 = FLOAT128_NONE; - else if (TARGET_FLOAT128 == FLOAT128_SW && !TARGET_VSX) - error ("-mfloat128-software requires VSX support"); - /* Set -mallow-movmisalign to explicitly on if we have full ISA 2.07 support. If we only have ISA 2.06 support, and the user did not specify the switch, leave it set to -1 so the movmisalign patterns are enabled, @@ -3755,6 +3762,15 @@ rs6000_option_override_internal (bool gl } } + /* __float128 requires VSX support. */ + if (TARGET_FLOAT128 && !TARGET_VSX) + { + if ((rs6000_isa_flags_explicit & OPTION_MASK_FLOAT128) != 0) + error ("-mfloat128 requires VSX support"); + + rs6000_isa_flags &= ~OPTION_MASK_FLOAT128; + } + if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET) rs6000_print_isa_options (stderr, 0, "after defaults", rs6000_isa_flags); @@ -3835,7 +3851,8 @@ rs6000_option_override_internal (bool gl unless the altivec ABI was set. This is set by default for 64-bit, but not for 32-bit. */ if (main_target_opt != NULL && !main_target_opt->x_rs6000_altivec_abi) - rs6000_isa_flags &= ~((OPTION_MASK_VSX | OPTION_MASK_ALTIVEC) + rs6000_isa_flags &= ~((OPTION_MASK_VSX | OPTION_MASK_ALTIVEC + | OPTION_MASK_FLOAT128) & ~rs6000_isa_flags_explicit); /* Enable Altivec ABI for AIX -maltivec. */ @@ -8444,8 +8461,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 @@ -9424,6 +9447,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) @@ -10586,9 +10610,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); @@ -10819,11 +10845,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. */ @@ -14408,8 +14437,6 @@ rs6000_init_builtins (void) tree tdecl; tree ftype; machine_mode mode; - machine_mode ieee128_mode; - machine_mode ibm128_mode; if (TARGET_DEBUG_BUILTIN) fprintf (stderr, "rs6000_init_builtins%s%s%s%s\n", @@ -14482,26 +14509,24 @@ rs6000_init_builtins (void) TFmode will be either IEEE 128-bit floating point or the IBM double-double format that uses a pair of doubles, depending on the switches and defaults. */ - if (TARGET_IEEEQUAD) - { - ieee128_mode = TFmode; - ibm128_mode = IFmode; - } - else + if (TARGET_FLOAT128) { - ieee128_mode = KFmode; - ibm128_mode = TFmode; - } + ibm128_float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (ibm128_float_type_node) = 128; + layout_type (ibm128_float_type_node); + SET_TYPE_MODE (ibm128_float_type_node, IFmode); + + ieee128_float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (ieee128_float_type_node) = 128; + layout_type (ieee128_float_type_node); + SET_TYPE_MODE (ieee128_float_type_node, KFmode); - ieee128_float_type_node = make_node (REAL_TYPE); - TYPE_PRECISION (ieee128_float_type_node) = 128; - layout_type (ieee128_float_type_node); - SET_TYPE_MODE (ieee128_float_type_node, ieee128_mode); + lang_hooks.types.register_builtin_type (ieee128_float_type_node, + "__float128"); - ibm128_float_type_node = make_node (REAL_TYPE); - TYPE_PRECISION (ibm128_float_type_node) = 128; - layout_type (ibm128_float_type_node); - SET_TYPE_MODE (ibm128_float_type_node, ibm128_mode); + 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. */ @@ -16007,75 +16032,155 @@ 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_ for the names, so + continue to use that if we can't pass IEEE 128-bit in a VSX vector register. + + 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"); + } + } + } - 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"); + 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, 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) +{ + /* __float128 support. */ + if (TARGET_FLOAT128) + { + init_float128_ibm (IFmode); + init_float128_ieee (KFmode); + } - 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"); + /* AIX/Darwin/64-bit Linux quad floating point routines. */ + if (TARGET_LONG_DOUBLE_128) + { + if (!TARGET_IEEEQUAD) + init_float128_ibm (TFmode); + + /* IEEE 128-bit including 32-bit SVR4 quad floating point routines. */ + else + init_float128_ieee (TFmode); } } @@ -20141,7 +20246,7 @@ rs6000_generate_compare (rtx cmp, machin return gen_rtx_fmt_ee (code, VOIDmode, compare_result, const0_rtx); } - + /* Expand floating point conversion to/from __float128 and __ibm128. */ void @@ -20150,60 +20255,105 @@ rs6000_expand_float128_convert (rtx dest machine_mode dest_mode = GET_MODE (dest); machine_mode src_mode = GET_MODE (src); convert_optab cvt = unknown_optab; + bool do_move = false; rtx libfunc = NULL_RTX; rtx dest2; if (dest_mode == src_mode) gcc_unreachable (); + /* Convert to IEEE 128-bit floating point. */ if (FLOAT128_IEEE_P (dest_mode)) { - if (src_mode == SFmode - || src_mode == DFmode - || FLOAT128_IBM_P (src_mode)) - cvt = sext_optab; + switch (src_mode) + { + case DFmode: + cvt = sext_optab; + break; - else if (GET_MODE_CLASS (src_mode) == MODE_INT) - cvt = (unsigned_p) ? ufloat_optab : sfloat_optab; + case SFmode: + cvt = sext_optab; + break; - else if (FLOAT128_IEEE_P (src_mode)) - emit_move_insn (dest, gen_lowpart (dest_mode, src)); + case KFmode: + case IFmode: + case TFmode: + if (FLOAT128_IBM_P (src_mode)) + cvt = sext_optab; + else + do_move = true; + break; - else - gcc_unreachable (); + case SImode: + case DImode: + cvt = (unsigned_p) ? ufloat_optab : sfloat_optab; + break; + + default: + gcc_unreachable (); + } } + /* Convert from IEEE 128-bit floating point. */ else if (FLOAT128_IEEE_P (src_mode)) { - if (dest_mode == SFmode - || dest_mode == DFmode - || FLOAT128_IBM_P (dest_mode)) - cvt = trunc_optab; + switch (dest_mode) + { + case DFmode: + cvt = trunc_optab; + break; - else if (GET_MODE_CLASS (dest_mode) == MODE_INT) - cvt = (unsigned_p) ? ufix_optab : sfix_optab; + case SFmode: + cvt = trunc_optab; + break; - else - gcc_unreachable (); + case KFmode: + case IFmode: + case TFmode: + if (FLOAT128_IBM_P (dest_mode)) + cvt = trunc_optab; + else + do_move = true; + break; + + case SImode: + case DImode: + cvt = (unsigned_p) ? ufix_optab : sfix_optab; + break; + + default: + gcc_unreachable (); + } } else gcc_unreachable (); - gcc_assert (cvt != unknown_optab); - libfunc = convert_optab_libfunc (cvt, dest_mode, src_mode); - gcc_assert (libfunc != NULL_RTX); - - dest2 = emit_library_call_value (libfunc, dest, LCT_CONST, dest_mode, 1, src, - src_mode); - - gcc_assert (dest != NULL_RTX); - if (!rtx_equal_p (dest, dest2)) - emit_move_insn (dest, dest2); + /* Handle conversion between TFmode/KFmode. */ + if (do_move) + emit_move_insn (dest, gen_lowpart (dest_mode, src)); + + /* Call an external function to do the conversion. */ + else if (cvt != unknown_optab) + { + libfunc = convert_optab_libfunc (cvt, dest_mode, src_mode); + gcc_assert (libfunc != NULL_RTX); + + dest2 = emit_library_call_value (libfunc, dest, LCT_CONST, dest_mode, 1, src, + src_mode); + + gcc_assert (dest2 != NULL_RTX); + if (!rtx_equal_p (dest, dest2)) + emit_move_insn (dest, dest2); + } + + else + gcc_unreachable (); return; } + /* Emit the RTL for an sISEL pattern. */ void @@ -29800,6 +29950,21 @@ 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". Use + "g" for IBM extended double, no matter whether it is long double (using + -mabi=ibmlongdouble) or the distinct __ibm128 type. */ + if (TARGET_FLOAT128) + { + if (type == ieee128_float_type_node) + return "U10__float128"; + + if (type == ibm128_float_type_node) + return "g"; + + if (type == long_double_type_node && TARGET_LONG_DOUBLE_128) + return (TARGET_IEEEQUAD) ? "U10__float128" : "g"; + } + /* 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 @@ -33023,8 +33188,8 @@ rs6000_scalar_mode_supported_p (machine_ if (DECIMAL_FLOAT_MODE_P (mode)) return default_decimal_float_supported_p (); - else if (mode == KFmode) - return TARGET_FLOAT128; + else if (TARGET_FLOAT128 && (mode == KFmode || mode == IFmode)) + return true; else return default_scalar_mode_supported_p (mode); } @@ -33050,6 +33215,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) + { + if (suffix == 'q' || suffix == 'Q') + return (TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128) ? 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) @@ -33135,6 +33320,7 @@ static struct rs6000_opt_mask const rs60 { "dlmzb", OPTION_MASK_DLMZB, false, true }, { "efficient-unaligned-vsx", OPTION_MASK_EFFICIENT_UNALIGNED_VSX, false, true }, + { "float128", OPTION_MASK_FLOAT128, false, true }, { "fprnd", OPTION_MASK_FPRND, false, true }, { "hard-dfp", OPTION_MASK_DFP, false, true }, { "htm", OPTION_MASK_HTM, false, true }, @@ -33213,7 +33399,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[] = @@ -35431,7 +35617,7 @@ chain_contains_only_swaps (swap_web_entr for (; link; link = link->next) { - if (!VECTOR_MODE_P (GET_MODE (DF_REF_REG (link->ref)))) + if (!ALTIVEC_OR_VSX_VECTOR_MODE (GET_MODE (DF_REF_REG (link->ref)))) continue; if (DF_REF_IS_ARTIFICIAL (link->ref)) @@ -35530,7 +35716,7 @@ mark_swaps_for_removal (swap_web_entry * { /* Ignore uses for addressability. */ machine_mode mode = GET_MODE (DF_REF_REG (use)); - if (!VECTOR_MODE_P (mode)) + if (!ALTIVEC_OR_VSX_VECTOR_MODE (mode)) continue; struct df_link *link = DF_REF_CHAIN (use); @@ -35939,10 +36125,11 @@ rs6000_analyze_swaps (function *fun) mode = V4SImode; } - if (VECTOR_MODE_P (mode) || mode == TImode) + if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode) { insn_entry[uid].is_relevant = 1; - if (mode == TImode || mode == V1TImode) + if (mode == TImode || mode == V1TImode + || FLOAT128_VECTOR_P (mode)) insn_entry[uid].is_128_int = 1; if (DF_REF_INSN_INFO (mention)) insn_entry[uid].contains_subreg @@ -35963,13 +36150,14 @@ rs6000_analyze_swaps (function *fun) isn't sufficient to ensure we union the call into the web with the parameter setup code. */ if (mode == DImode && GET_CODE (insn) == SET - && VECTOR_MODE_P (GET_MODE (SET_DEST (insn)))) + && ALTIVEC_OR_VSX_VECTOR_MODE (GET_MODE (SET_DEST (insn)))) mode = GET_MODE (SET_DEST (insn)); - if (VECTOR_MODE_P (mode) || mode == TImode) + if (ALTIVEC_OR_VSX_VECTOR_MODE (mode) || mode == TImode) { insn_entry[uid].is_relevant = 1; - if (mode == TImode || mode == V1TImode) + if (mode == TImode || mode == V1TImode + || FLOAT128_VECTOR_P (mode)) insn_entry[uid].is_128_int = 1; if (DF_REF_INSN_INFO (mention)) insn_entry[uid].contains_subreg Index: gcc/config/rs6000/rs6000.h =================================================================== --- gcc/config/rs6000/rs6000.h (revision 227594) +++ 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/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 227594) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -6956,7 +6956,7 @@ (define_insn "*ieee_128bit_vsx_nabs2" - [(set (match_operand:IFKF 0 "nonimmediate_operand" "") + [(set (match_operand:IFKF 0 "gpc_reg_operand" "") (float_extend:IFKF (match_operand:FLOAT128_SFDFTF 1 "gpc_reg_operand" "")))] "TARGET_FLOAT128" @@ -6966,7 +6966,7 @@ (define_expand "extend2" - [(set (match_operand:FLOAT128_SFDFTF 0 "nonimmediate_operand" "") + [(set (match_operand:FLOAT128_SFDFTF 0 "gpc_reg_operand" "") (float_truncate:FLOAT128_SFDFTF (match_operand:IFKF 1 "gpc_reg_operand" "")))] "TARGET_FLOAT128" Index: gcc/config/rs6000/rs6000-opts.h =================================================================== --- gcc/config/rs6000/rs6000-opts.h (revision 227594) +++ gcc/config/rs6000/rs6000-opts.h (working copy) @@ -80,14 +80,6 @@ enum fpu_type_t }; -/* Float128 support. */ -enum float128_type_t -{ - FLOAT128_UNSET = -1, /* Initial value. */ - FLOAT128_NONE, /* No __float128 support. */ - FLOAT128_SW /* software __float128 support. */ -}; - /* Types of costly dependences. */ enum rs6000_dependence_cost { Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (revision 227594) +++ 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 @@ -13326,6 +13347,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 227594) +++ 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 -mno-float128} @emph{RX Options} @gccoptlist{-m64bit-doubles -m32bit-doubles -fpu -nofpu@gol @@ -19338,6 +19339,17 @@ 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 +@itemx -mno-float128 +@opindex mfloat128 +@opindex mno-float128 +Enable/disable the @var{__float128} keyword for IEEE 128-bit floating point +and use software emulation for IEEE 128-bit floating point. + +The VSX instruction set (@option{-mvsx}, @option{-mcpu=power7}, or +@option{-mcpu=power8}) must be enabled to use the @option{-mfloat128} +option. + @item -mfloat-gprs=@var{yes/single/double/no} @itemx -mfloat-gprs @opindex mfloat-gprs