+2015-12-29 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit
+ comparison functions in cmp_optab and ucmp_optab.
+ (rs6000_generate_compare): Rewrite IEEE 128-bit floating point
+ software emulation comparisons to only use __eqkf2, __gekf2,
+ __lekf2, and __unordkf2 functions.
+ (rs6000_invalid_binary_op): Add support for -mfloat128-convert.
+
+ * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
+ __FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is
+ available.
+
+ * config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch
+ to allow IBM extended double and IEEE 128-bit floating point to be
+ converted with default conversions.
+
+ * config/rs6000/rs6000.md (extendkftf2): Add converters between
+ KFmode and TFmode if -mabi=ieeelongdouble.
+ (trunctfkf2): Likewise.
+ (ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and
+ 64-bit insns.
+ (ieee128_mfvsrd_64bit): Likewise.
+ (ieee128_mfvsrd_32bit): Likewise.
+ (ieee128_mtvsrd): Likewise.
+ (ieee128_mtvsrd_64bit): Likewise.
+ (ieee128_mtvsrd_32bit): Likewise.
+
+ * doc/extend.texi (Floating Types): Document that complex
+ __float128 does not work currently.
+
+ * doc/invoke.texi (RS/6000 and PowerPC Options): Document that
+ -mfloat128 is only supported on PowerPC 64-bit Linux systems.
+
2015-12-28 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* config/rs6000/rs6000.c (rs6000_emit_le_vsx_move): Verify that
builtin_define ("__RSQRTEF__");
if (TARGET_FLOAT128)
builtin_define ("__FLOAT128__");
+ if (TARGET_FLOAT128_HW)
+ builtin_define ("__FLOAT128_HARDWARE__");
if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM)
{
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, "__cmpokf2"); /* fcmpo */
- set_optab_libfunc (ucmp_optab, mode, "__cmpukf2"); /* fcmpu */
set_conv_libfunc (sext_optab, mode, SFmode, "__extendsfkf2");
set_conv_libfunc (sext_optab, mode, DFmode, "__extenddfkf2");
rtx op0 = XEXP (cmp, 0);
rtx op1 = XEXP (cmp, 1);
- if (FLOAT_MODE_P (mode))
+ if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
+ comp_mode = CCmode;
+ else if (FLOAT_MODE_P (mode))
comp_mode = CCFPmode;
else if (code == GTU || code == LTU
|| code == GEU || code == LEU)
emit_insn (cmp);
}
- /* IEEE 128-bit support in VSX registers. If we do not have IEEE 128-bit
- hardware, the comparison functions (__cmpokf2 and __cmpukf2) returns 0..15
- that is laid out the same way as the PowerPC CR register would for a
- normal floating point comparison from the fcmpo and fcmpu
- instructions. */
- else if (!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (mode))
+ /* IEEE 128-bit support in VSX registers when we do not have hardware
+ support. */
+ else if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
{
- rtx and_reg = gen_reg_rtx (SImode);
+ rtx libfunc = NULL_RTX;
+ bool uneq_or_ltgt = false;
rtx dest = gen_reg_rtx (SImode);
- rtx libfunc = optab_libfunc (ucmp_optab, mode);
- HOST_WIDE_INT mask_value = 0;
-
- /* Values that __cmpokf2/__cmpukf2 returns. */
-#define PPC_CMP_UNORDERED 0x1 /* isnan (a) || isnan (b). */
-#define PPC_CMP_EQUAL 0x2 /* a == b. */
-#define PPC_CMP_GREATER_THEN 0x4 /* a > b. */
-#define PPC_CMP_LESS_THEN 0x8 /* a < b. */
switch (code)
{
case EQ:
- mask_value = PPC_CMP_EQUAL;
- code = NE;
- break;
-
case NE:
- mask_value = PPC_CMP_EQUAL;
- code = EQ;
+ libfunc = optab_libfunc (eq_optab, mode);
break;
case GT:
- mask_value = PPC_CMP_GREATER_THEN;
- code = NE;
- break;
-
case GE:
- mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
- code = NE;
+ libfunc = optab_libfunc (ge_optab, mode);
break;
case LT:
- mask_value = PPC_CMP_LESS_THEN;
- code = NE;
- break;
-
case LE:
- mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
- code = NE;
- break;
-
- case UNLE:
- mask_value = PPC_CMP_GREATER_THEN;
- code = EQ;
+ libfunc = optab_libfunc (le_optab, mode);
break;
- case UNLT:
- mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
- code = EQ;
+ case UNORDERED:
+ case ORDERED:
+ libfunc = optab_libfunc (unord_optab, mode);
+ code = (code == UNORDERED) ? NE : EQ;
break;
case UNGE:
- mask_value = PPC_CMP_LESS_THEN;
- code = EQ;
+ case UNGT:
+ libfunc = optab_libfunc (le_optab, mode);
+ code = (code == UNGE) ? GE : GT;
break;
- case UNGT:
- mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
- code = EQ;
+ case UNLE:
+ case UNLT:
+ libfunc = optab_libfunc (ge_optab, mode);
+ code = (code == UNLE) ? LE : LT;
break;
case UNEQ:
- mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
- code = NE;
-
case LTGT:
- mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
- code = EQ;
- break;
-
- case UNORDERED:
- mask_value = PPC_CMP_UNORDERED;
- code = NE;
- break;
-
- case ORDERED:
- mask_value = PPC_CMP_UNORDERED;
- code = EQ;
+ libfunc = optab_libfunc (le_optab, mode);
+ uneq_or_ltgt = true;
+ code = (code = UNEQ) ? NE : EQ;
break;
default:
gcc_unreachable ();
}
- gcc_assert (mask_value != 0);
- and_reg = emit_library_call_value (libfunc, and_reg, LCT_CONST, SImode, 2,
- op0, mode, op1, mode);
+ gcc_assert (libfunc);
+ dest = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+ SImode, 2, op0, mode, op1, mode);
- emit_insn (gen_andsi3 (dest, and_reg, GEN_INT (mask_value)));
- compare_result = gen_reg_rtx (CCmode);
- comp_mode = CCmode;
+ /* If this is UNEQ or LTGT, we call __lekf2, which returns -1 for less
+ than, 0 for equal, +1 for greater, and +2 for nan. We add 1, to give
+ a value of 0..3, and then do and AND immediate of 1 to isolate whether
+ it is 0/Nan (i.e. bottom bit is 0), or less than/greater than
+ (i.e. bottom bit is 1). */
+ if (uneq_or_ltgt)
+ {
+ rtx add_result = gen_reg_rtx (SImode);
+ rtx and_result = gen_reg_rtx (SImode);
+ emit_insn (gen_addsi3 (add_result, dest, GEN_INT (1)));
+ emit_insn (gen_andsi3 (and_result, add_result, GEN_INT (1)));
+ dest = and_result;
+ }
emit_insn (gen_rtx_SET (compare_result,
gen_rtx_COMPARE (comp_mode, dest, const0_rtx)));
mode2 = GET_MODE_INNER (mode2);
/* Don't allow IEEE 754R 128-bit binary floating point and IBM extended
- double to intermix. */
+ double to intermix unless -mfloat128-convert. */
if (mode1 == mode2)
return NULL;
- if ((mode1 == KFmode && mode2 == IFmode)
- || (mode1 == IFmode && mode2 == KFmode))
- return N_("__float128 and __ibm128 cannot be used in the same expression");
+ if (!TARGET_FLOAT128_CVT)
+ {
+ if ((mode1 == KFmode && mode2 == IFmode)
+ || (mode1 == IFmode && mode2 == KFmode))
+ return N_("__float128 and __ibm128 cannot be used in the same "
+ "expression");
- if (TARGET_IEEEQUAD
- && ((mode1 == IFmode && mode2 == TFmode)
- || (mode1 == TFmode && mode2 == IFmode)))
- return N_("__ibm128 and long double cannot be used in the same expression");
+ if (TARGET_IEEEQUAD
+ && ((mode1 == IFmode && mode2 == TFmode)
+ || (mode1 == TFmode && mode2 == IFmode)))
+ return N_("__ibm128 and long double cannot be used in the same "
+ "expression");
- if (!TARGET_IEEEQUAD
- && ((mode1 == KFmode && mode2 == TFmode)
- || (mode1 == TFmode && mode2 == KFmode)))
- return N_("__float128 and long double cannot be used in the same "
- "expression");
+ if (!TARGET_IEEEQUAD
+ && ((mode1 == KFmode && mode2 == TFmode)
+ || (mode1 == TFmode && mode2 == KFmode)))
+ return N_("__float128 and long double cannot be used in the same "
+ "expression");
+ }
return NULL;
}
"xscvdpqp %0,%1"
[(set_attr "type" "vecfloat")])
+;; Conversion between KFmode and TFmode if TFmode is ieee 128-bit floating
+;; point is a simple copy.
+(define_insn_and_split "extendkftf2"
+ [(set (match_operand:TF 0 "vsx_register_operand" "=wa,?wa")
+ (float_extend:TF (match_operand:KF 1 "vsx_register_operand" "0,wa")))]
+ "TARGET_FLOAT128 && TARGET_IEEEQUAD"
+ "@
+ #
+ xxlor %x0,%x1,%x1"
+ "&& reload_completed && REGNO (operands[0]) == REGNO (operands[1])"
+ [(const_int 0)]
+{
+ emit_note (NOTE_INSN_DELETED);
+ DONE;
+}
+ [(set_attr "type" "*,vecsimple")
+ (set_attr "length" "0,4")])
+
+(define_insn_and_split "trunctfkf2"
+ [(set (match_operand:KF 0 "vsx_register_operand" "=wa,?wa")
+ (float_extend:KF (match_operand:TF 1 "vsx_register_operand" "0,wa")))]
+ "TARGET_FLOAT128 && TARGET_IEEEQUAD"
+ "@
+ #
+ xxlor %x0,%x1,%x1"
+ "&& reload_completed && REGNO (operands[0]) == REGNO (operands[1])"
+ [(const_int 0)]
+{
+ emit_note (NOTE_INSN_DELETED);
+ DONE;
+}
+ [(set_attr "type" "*,vecsimple")
+ (set_attr "length" "0,4")])
+
(define_insn "trunc<mode>df2_hw"
[(set (match_operand:DF 0 "altivec_register_operand" "=v")
(float_truncate:DF
"xscv<su>dqp %0,%1"
[(set_attr "type" "vecfloat")])
-(define_insn "*ieee128_mfvsrd"
+(define_insn "*ieee128_mfvsrd_64bit"
[(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi")
(unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")]
UNSPEC_IEEE128_MOVE))]
xxlor %x0,%x1,%x1"
[(set_attr "type" "mftgpr,vecsimple,fpstore")])
+
+(define_insn "*ieee128_mfvsrd_32bit"
+ [(set (match_operand:DI 0 "reg_or_indexed_operand" "=Z,wi")
+ (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
+ UNSPEC_IEEE128_MOVE))]
+ "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
+ "@
+ stxsdx %x1,%y0
+ xxlor %x0,%x1,%x1"
+ [(set_attr "type" "vecsimple,fpstore")])
+
(define_insn "*ieee128_mfvsrwz"
[(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z")
(unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
[(set_attr "type" "mffgpr,fpload,mffgpr,fpload")])
-(define_insn "*ieee128_mtvsrd"
+(define_insn "*ieee128_mtvsrd_64bit"
[(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v")
(unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")]
UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW"
+ "TARGET_FLOAT128_HW && TARGET_POWERPC64"
"@
mtvsrd %x0,%1
lxsdx %x0,%y1
xxlor %x0,%x1,%x1"
[(set_attr "type" "mffgpr,fpload,vecsimple")])
+(define_insn "*ieee128_mtvsrd_32bit"
+ [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v")
+ (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "Z,wi")]
+ UNSPEC_IEEE128_MOVE))]
+ "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
+ "@
+ lxsdx %x0,%y1
+ xxlor %x0,%x1,%x1"
+ [(set_attr "type" "fpload,vecsimple")])
+
;; IEEE 128-bit instructions with round to odd semantics
(define_insn "*trunc<mode>df2_odd"
[(set (match_operand:DF 0 "vsx_register_operand" "=v")
mfloat128-hardware
Target Report Mask(FLOAT128_HW) Var(rs6000_isa_flags)
Enable/disable using IEEE 128-bit floating point instructions.
+
+mfloat128-convert
+Target Undocumented Mask(FLOAT128_CVT) Var(rs6000_isa_flags)
+Enable/disable default conversions between __float128 & long double.
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}:
+On PowerPC 64-bit Linux systems there are currently problems in using
+the complex @code{__float128} type. When these problems are fixed,
+you would use:
@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.
-The @code{__float128} type is supported on PowerPC systems by default
-if the vector scalar instruction set (VSX) is enabled.
+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.
+The @code{__float128} type is supported on PowerPC 64-bit Linux
+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
The VSX instruction set (@option{-mvsx}, @option{-mcpu=power7}, or
@option{-mcpu=power8}) must be enabled to use the @option{-mfloat128}
-option.
+option. The @code{-mfloat128} option only works on PowerPC 64-bit
+Linux systems.
@item -mfloat128-hardware
@itemx -mno-float128-hardware