[PATCH], PowerPC IEEE 128-bit patch #6
Michael Meissner
meissner@linux.vnet.ibm.com
Fri Aug 14 16:24:00 GMT 2015
Evidently I attached the wrong file for patch #6.
2015-08-13 Michael Meissner <meissner@linux.vnet.ibm.com>
* config/rs6000/rs6000-protos.h (rs6000_expand_float128_convert):
Add declaration.
* config/rs6000/rs6000.c (rs6000_emit_le_vsx_store): Fix a
comment.
(rs6000_cannot_change_mode_class): Add support for IEEE 128-bit
floating point in VSX registers.
(rs6000_output_move_128bit): Always print out the set insn if we
can't generate an appropriate 128-bit move.
(rs6000_generate_compare): Add support for IEEE 128-bit floating
point in VSX registers comparisons.
(rs6000_expand_float128_convert): Likewise.
* config/rs6000/rs6000.md (extenddftf2): Add support for IEEE
128-bit floating point in VSX registers.
(extenddftf2_internal): Likewise.
(trunctfdf2): Likewise.
(trunctfdf2_internal2): Likewise.
(fix_trunc_helper): Likewise.
(fix_trunctfdi2"): Likewise.
(floatditf2): Likewise.
(floatuns<mode>tf2): Likewise.
(extend<FLOAT128_SFDFTF:mode><IFKF:mode>2): Likewise.
(trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2): Likewise.
(fix_trunc<IFKF:mode><SDI:mode>2): Likewise.
(fixuns_trunc<IFKF:mode><SDI:mode>2): Likewise.
(float<SDI:mode><IFKF:mode>2): Likewise.
(floatuns<SDI:mode><IFKF:mode>2): Likewise.
--
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meissner@linux.vnet.ibm.com, phone: +1 (978) 899-4797
-------------- next part --------------
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h (revision 226838)
+++ gcc/config/rs6000/rs6000-protos.h (working copy)
@@ -54,6 +54,7 @@ extern const char *output_vec_const_move
extern const char *rs6000_output_move_128bit (rtx *);
extern bool rs6000_move_128bit_ok_p (rtx []);
extern bool rs6000_split_128bit_ok_p (rtx []);
+extern void rs6000_expand_float128_convert (rtx, rtx, bool);
extern void rs6000_expand_vector_init (rtx, rtx);
extern void paired_expand_vector_init (rtx, rtx);
extern void rs6000_expand_vector_set (rtx, rtx, int);
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c (revision 226838)
+++ gcc/config/rs6000/rs6000.c (working copy)
@@ -8462,7 +8462,7 @@ rs6000_emit_le_vsx_store (rtx dest, rtx
during expand. */
gcc_assert (!reload_in_progress && !lra_in_progress && !reload_completed);
- /* Use V2DImode to do swaps of types with 128-bit scalare parts (TImode,
+ /* Use V2DImode to do swaps of types with 128-bit scalar parts (TImode,
V1TImode). */
if (mode == TImode || mode == V1TImode)
{
@@ -18519,6 +18519,8 @@ rs6000_cannot_change_mode_class (machine
{
unsigned to_nregs = hard_regno_nregs[FIRST_FPR_REGNO][to];
unsigned from_nregs = hard_regno_nregs[FIRST_FPR_REGNO][from];
+ bool to_float128_vector_p = FLOAT128_VECTOR_P (to);
+ bool from_float128_vector_p = FLOAT128_VECTOR_P (from);
/* Don't allow 64-bit types to overlap with 128-bit types that take a
single register under VSX because the scalar part of the register
@@ -18527,7 +18529,10 @@ rs6000_cannot_change_mode_class (machine
IEEE floating point can't overlap, and neither can small
values. */
- if (TARGET_IEEEQUAD && (to == TFmode || from == TFmode))
+ if (to_float128_vector_p && from_float128_vector_p)
+ return false;
+
+ else if (to_float128_vector_p || from_float128_vector_p)
return true;
/* TDmode in floating-mode registers must always go into a register
@@ -18555,6 +18560,8 @@ rs6000_cannot_change_mode_class (machine
if (TARGET_E500_DOUBLE
&& ((((to) == DFmode) + ((from) == DFmode)) == 1
|| (((to) == TFmode) + ((from) == TFmode)) == 1
+ || (((to) == IFmode) + ((from) == IFmode)) == 1
+ || (((to) == KFmode) + ((from) == KFmode)) == 1
|| (((to) == DDmode) + ((from) == DDmode)) == 1
|| (((to) == TDmode) + ((from) == TDmode)) == 1
|| (((to) == DImode) + ((from) == DImode)) == 1))
@@ -18751,13 +18758,7 @@ rs6000_output_move_128bit (rtx operands[
return output_vec_const_move (operands);
}
- if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\n===== Bad 128 bit move:\n");
- debug_rtx (gen_rtx_SET (dest, src));
- }
-
- gcc_unreachable ();
+ fatal_insn ("Bad 128-bit move", gen_rtx_SET (dest, src));
}
/* Validate a 128-bit move. */
@@ -19801,6 +19802,8 @@ rs6000_generate_compare (rtx cmp, machin
break;
case TFmode:
+ case IFmode:
+ case KFmode:
cmp = (flag_finite_math_only && !flag_trapping_math)
? gen_tsttfeq_gpr (compare_result, op0, op1)
: gen_cmptfeq_gpr (compare_result, op0, op1);
@@ -19828,6 +19831,8 @@ rs6000_generate_compare (rtx cmp, machin
break;
case TFmode:
+ case IFmode:
+ case KFmode:
cmp = (flag_finite_math_only && !flag_trapping_math)
? gen_tsttfgt_gpr (compare_result, op0, op1)
: gen_cmptfgt_gpr (compare_result, op0, op1);
@@ -19855,6 +19860,8 @@ rs6000_generate_compare (rtx cmp, machin
break;
case TFmode:
+ case IFmode:
+ case KFmode:
cmp = (flag_finite_math_only && !flag_trapping_math)
? gen_tsttflt_gpr (compare_result, op0, op1)
: gen_cmptflt_gpr (compare_result, op0, op1);
@@ -19892,6 +19899,8 @@ rs6000_generate_compare (rtx cmp, machin
break;
case TFmode:
+ case IFmode:
+ case KFmode:
cmp = (flag_finite_math_only && !flag_trapping_math)
? gen_tsttfeq_gpr (compare_result2, op0, op1)
: gen_cmptfeq_gpr (compare_result2, op0, op1);
@@ -19914,14 +19923,117 @@ rs6000_generate_compare (rtx cmp, machin
emit_insn (cmp);
}
+
+ /* IEEE 128-bit support in VSX registers. The comparison function (__cmpkf2)
+ returns 0..15 that is laid out the same way as the PowerPC CR register
+ would for a normal floating point comparison. */
+ else if (FLOAT128_IEEE_P (mode))
+ {
+ rtx and_reg = gen_reg_rtx (SImode);
+ rtx dest = gen_reg_rtx (SImode);
+ rtx libfunc = optab_libfunc (cmp_optab, mode);
+ HOST_WIDE_INT mask_value = 0;
+
+ /* Values that __cmpkf2 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;
+ 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;
+ 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;
+ break;
+
+ case UNORDERED:
+ mask_value = PPC_CMP_UNORDERED;
+ code = NE;
+ break;
+
+ case ORDERED:
+ mask_value = PPC_CMP_UNORDERED;
+ code = 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);
+
+ emit_insn (gen_andsi3 (dest, and_reg, GEN_INT (mask_value)));
+ compare_result = gen_reg_rtx (CCmode);
+ comp_mode = CCmode;
+
+ emit_insn (gen_rtx_SET (compare_result,
+ gen_rtx_COMPARE (comp_mode, dest, const0_rtx)));
+ }
+
else
{
/* Generate XLC-compatible TFmode compare as PARALLEL with extra
CLOBBERs to match cmptf_internal2 pattern. */
if (comp_mode == CCFPmode && TARGET_XL_COMPAT
- && GET_MODE (op0) == TFmode
- && !TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
+ && FLOAT128_IBM_P (GET_MODE (op0))
+ && TARGET_HARD_FLOAT && TARGET_FPRS)
emit_insn (gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (10,
gen_rtx_SET (compare_result,
@@ -19954,6 +20066,7 @@ rs6000_generate_compare (rtx cmp, machin
/* Some kinds of FP comparisons need an OR operation;
under flag_finite_math_only we don't bother. */
if (FLOAT_MODE_P (mode)
+ && !FLOAT128_IEEE_P (mode)
&& !flag_finite_math_only
&& !(TARGET_HARD_FLOAT && !TARGET_FPRS)
&& (code == LE || code == GE
@@ -19993,6 +20106,68 @@ rs6000_generate_compare (rtx cmp, machin
}
+/* Expand floating point conversion to/from __float128 and __ibm128. */
+
+void
+rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
+{
+ machine_mode dest_mode = GET_MODE (dest);
+ machine_mode src_mode = GET_MODE (src);
+ convert_optab cvt = unknown_optab;
+ rtx libfunc = NULL_RTX;
+ rtx dest2;
+
+ if (dest_mode == src_mode)
+ gcc_unreachable ();
+
+ if (FLOAT128_IEEE_P (dest_mode))
+ {
+ if (src_mode == SFmode
+ || src_mode == DFmode
+ || FLOAT128_IBM_P (src_mode))
+ cvt = sext_optab;
+
+ else if (GET_MODE_CLASS (src_mode) == MODE_INT)
+ cvt = (unsigned_p) ? ufloat_optab : sfloat_optab;
+
+ else if (FLOAT128_IEEE_P (src_mode))
+ emit_move_insn (dest, gen_lowpart (dest_mode, src));
+
+ else
+ gcc_unreachable ();
+ }
+
+ else if (FLOAT128_IEEE_P (src_mode))
+ {
+ if (dest_mode == SFmode
+ || dest_mode == DFmode
+ || FLOAT128_IBM_P (dest_mode))
+ cvt = trunc_optab;
+
+ else if (GET_MODE_CLASS (dest_mode) == MODE_INT)
+ cvt = (unsigned_p) ? ufix_optab : sfix_optab;
+
+ else
+ 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);
+
+ return;
+}
+
/* Emit the RTL for an sISEL pattern. */
void
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md (revision 226871)
+++ gcc/config/rs6000/rs6000.md (working copy)
@@ -6488,12 +6488,12 @@ (define_insn_and_split "*mov<mode>_softf
(define_expand "extenddftf2"
[(set (match_operand:TF 0 "nonimmediate_operand" "")
(float_extend:TF (match_operand:DF 1 "input_operand" "")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT
- && (TARGET_FPRS || TARGET_E500_DOUBLE)
+ "TARGET_HARD_FLOAT && (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128"
{
- if (TARGET_E500_DOUBLE)
+ if (TARGET_IEEEQUAD)
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ else if (TARGET_E500_DOUBLE)
emit_insn (gen_spe_extenddftf2 (operands[0], operands[1]));
else
emit_insn (gen_extenddftf2_fprs (operands[0], operands[1]));
@@ -6542,25 +6542,34 @@ (define_insn_and_split "*extenddftf2_int
(define_expand "extendsftf2"
[(set (match_operand:TF 0 "nonimmediate_operand" "")
(float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT
+ "TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128"
{
- rtx tmp = gen_reg_rtx (DFmode);
- emit_insn (gen_extendsfdf2 (tmp, operands[1]));
- emit_insn (gen_extenddftf2 (operands[0], tmp));
+ if (TARGET_IEEEQUAD)
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ else
+ {
+ rtx tmp = gen_reg_rtx (DFmode);
+ emit_insn (gen_extendsfdf2 (tmp, operands[1]));
+ emit_insn (gen_extenddftf2 (operands[0], tmp));
+ }
DONE;
})
(define_expand "trunctfdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT
+ "TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128"
- "")
+{
+ if (TARGET_IEEEQUAD)
+ {
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+ }
+})
(define_insn_and_split "trunctfdf2_internal1"
[(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d")
@@ -6591,12 +6600,13 @@ (define_insn "trunctfdf2_internal2"
(define_expand "trunctfsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT
+ "TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128"
{
- if (TARGET_E500_DOUBLE)
+ if (TARGET_IEEEQUAD)
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ else if (TARGET_E500_DOUBLE)
emit_insn (gen_spe_trunctfsf2 (operands[0], operands[1]));
else
emit_insn (gen_trunctfsf2_fprs (operands[0], operands[1]));
@@ -6647,10 +6657,12 @@ (define_insn "fix_trunc_helper"
(define_expand "fix_trunctfsi2"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))]
- "!TARGET_IEEEQUAD && TARGET_HARD_FLOAT
+ "TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128"
{
- if (TARGET_E500_DOUBLE)
+ if (TARGET_IEEEQUAD)
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ else if (TARGET_E500_DOUBLE)
emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1]));
else
emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1]));
@@ -6698,6 +6710,42 @@ (define_insn_and_split "*fix_trunctfsi2_
DONE;
})
+(define_expand "fix_trunctfdi2"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (fix:DI (match_operand:TF 1 "gpc_reg_operand" "")))]
+ "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "fixuns_trunctf<mode>2"
+ [(set (match_operand:SDI 0 "nonimmediate_operand" "")
+ (unsigned_fix:SDI (match_operand:TF 1 "gpc_reg_operand" "")))]
+ "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], true);
+ DONE;
+})
+
+(define_expand "floatditf2"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
+ (float:TF (match_operand:DI 1 "gpc_reg_operand" "")))]
+ "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "floatuns<mode>tf2"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
+ (unsigned_float:TF (match_operand:SDI 1 "gpc_reg_operand" "")))]
+ "TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], true);
+ DONE;
+})
+
(define_expand "neg<mode>2"
[(set (match_operand:TFIFKF 0 "gpc_reg_operand" "")
(neg:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))]
@@ -6920,6 +6968,64 @@ (define_insn "*ieee_128bit_vsx_nabs<mode
[(set_attr "length" "4")
(set_attr "type" "vecsimple")])
+;; Float128 conversion functions. These expand to library function calls.
+
+(define_expand "extend<FLOAT128_SFDFTF:mode><IFKF:mode>2"
+ [(set (match_operand:IFKF 0 "nonimmediate_operand" "")
+ (float_extend:IFKF
+ (match_operand:FLOAT128_SFDFTF 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "trunc<IFKF:mode><FLOAT128_SFDFTF:mode>2"
+ [(set (match_operand:FLOAT128_SFDFTF 0 "nonimmediate_operand" "")
+ (float_truncate:FLOAT128_SFDFTF
+ (match_operand:IFKF 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "fix_trunc<IFKF:mode><SDI:mode>2"
+ [(set (match_operand:SDI 0 "nonimmediate_operand" "")
+ (fix:SDI (match_operand:IFKF 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "fixuns_trunc<IFKF:mode><SDI:mode>2"
+ [(set (match_operand:SDI 0 "nonimmediate_operand" "")
+ (unsigned_fix:SDI (match_operand:IFKF 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], true);
+ DONE;
+})
+
+(define_expand "float<SDI:mode><IFKF:mode>2"
+ [(set (match_operand:IFKF 0 "nonimmediate_operand" "")
+ (float:KF (match_operand:SDI 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+})
+
+(define_expand "floatuns<SDI:mode><IFKF:mode>2"
+ [(set (match_operand:IFKF 0 "nonimmediate_operand" "")
+ (unsigned_float:IFKF (match_operand:SDI 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128"
+{
+ rs6000_expand_float128_convert (operands[0], operands[1], true);
+ DONE;
+})
+
;; Reload helper functions used by rs6000_secondary_reload. The patterns all
;; must have 3 arguments, and scratch register constraint must be a single
More information about the Gcc-patches
mailing list