rs6000.c (init_float128_ieee): Remove IEEE 128-bit comparison functions in cmp_optab and ucmp_optab.

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.

From-SVN: r231996
This commit is contained in:
Michael Meissner 2015-12-29 17:15:14 +00:00 committed by Michael Meissner
parent 1c64553627
commit ec21a884b3
7 changed files with 174 additions and 104 deletions

View File

@ -1,3 +1,37 @@
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

View File

@ -412,6 +412,8 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfile)
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)
{

View File

@ -16501,8 +16501,6 @@ init_float128_ieee (machine_mode mode)
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");
@ -20297,7 +20295,9 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
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)
@ -20503,106 +20503,77 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
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;
break;
case UNLT:
mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
code = EQ;
break;
case UNGE:
mask_value = PPC_CMP_LESS_THEN;
code = EQ;
break;
case UNGT:
mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
code = EQ;
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;
libfunc = optab_libfunc (le_optab, mode);
break;
case UNORDERED:
mask_value = PPC_CMP_UNORDERED;
code = NE;
case ORDERED:
libfunc = optab_libfunc (unord_optab, mode);
code = (code == UNORDERED) ? NE : EQ;
break;
case ORDERED:
mask_value = PPC_CMP_UNORDERED;
code = EQ;
case UNGE:
case UNGT:
libfunc = optab_libfunc (le_optab, mode);
code = (code == UNGE) ? GE : GT;
break;
case UNLE:
case UNLT:
libfunc = optab_libfunc (ge_optab, mode);
code = (code == UNLE) ? LE : LT;
break;
case UNEQ:
case LTGT:
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)));
@ -20706,24 +20677,29 @@ rs6000_invalid_binary_op (int op ATTRIBUTE_UNUSED,
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;
}

View File

@ -13352,6 +13352,40 @@
"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
@ -13476,7 +13510,7 @@
"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))]
@ -13487,6 +13521,17 @@
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")]
@ -13512,17 +13557,27 @@
[(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")

View File

@ -632,3 +632,7 @@ Enable/disable IEEE 128-bit floating point via the __float128 keyword.
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.

View File

@ -954,22 +954,20 @@ 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}:
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

View File

@ -19690,7 +19690,8 @@ hardware instructions.
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