[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