diff mbox series

[5/5,ver4] RS6000: Conversions between 128-bit integer and floating point values.

Message ID 3f87135c8d31ed5430c8d8aa25e36290002a6142.camel@us.ibm.com
State New
Headers show
Series RS6000: Add 128-bit Integer Operations | expand

Commit Message

Carl Love April 26, 2021, 4:36 p.m. UTC
Will, Segher:

This patch adds support for converting to/from 128-bit integers and
128-bit decimal floating point formats using the new P10 instructions
dcffixqq and dctfixqq.  The new instructions are only used on P10 HW,
otherwise the conversions continue to use the existing SW routines.

The files fixkfti-sw.c and fixunskfti-sw.c are renamed versions of
fixkfti.c and fixunskfti.c respectively.  The function names in the
files were updated with the rename as well as some white spaces fixes.

The patch has been tested on
    powerpc64-linux instead (Power 8 BE)
    powerpc64-linux instead (Power 9 LE)
    powerpc64-linux instead (Power 10 LE)

Please let me know if the patch is acceptable for mainline.

                   Carl Love
------------------------------------------------

gcc/ChangeLog

2021-04-26  Carl Love  <cel@us.ibm.com>
	* config/rs6000/rs6000.md (floatti<mode>2, floatunsti<mode>2,
	fix_trunc<mode>ti2, fixuns_trunc<mode>ti2): Add
	define_insn for mode IEEE 128.

gcc/testsuite/ChangeLog

2021-04-26  Carl Love  <cel@us.ibm.com>
	* gcc.target/powerpc/fp128_conversions.c: New file.
	* gcc.target/powerpc/int_128bit-runnable.c(vextsd2ppc_native_128bitq,
	vcmpuq, vcmpsq, vcmpequq, vcmpequq., vcmpgtsq, vcmpgtsq.
	vcmpgtuq, vcmpgtuq.): Update scan-assembler-times.
	(ppc_native_128bit): Remove dg-require-effective-target.

libgcc/ChangeLog
2021-04-26  Carl Love  <cel@us.ibm.com>
	* config.host: Add if test and set for
	libgcc_cv_powerpc_3_1_float128_hw.
	* libgcc/config/rs6000/fixkfti.c: Renamed to fixkfti-sw.c.
	Change calls of __fixkfti to __fixkfti_sw.
	* libgcc/config/rs6000/fixunskfti.c: Renamed to fixunskfti-sw.c.
	Change calls of __fixunskfti to __fixunskfti_sw.
	* libgcc/config/rs6000/float128-p10.c (__floattikf_hw,
	__floatuntikf_hw, __fixkfti_hw, __fixunskfti_hw): New file.
	* libgcc/config/rs6000/float128-ifunc.c (SW_OR_HW_ISA3_1): New macro.
	(__floattikf_resolve, __floatuntikf_resolve, __fixkfti_resolve,
	__fixunskfti_resolve): Add resolve functions.
	(__floattikf, __floatuntikf, __fixkfti, __fixunskfti): New functions.
	* libgcc/config/rs6000/float128-sed (floattitf, __floatuntitf,
	__fixtfti, __fixunstfti): Add editor commands to change names.
	* libgcc/config/rs6000/float128-sed-hw (__floattitf,
	__floatuntitf, __fixtfti, __fixunstfti): Add editor commands to
	change names.
	* libgcc/config/rs6000/floattikf.c: Renamed to floattikf-sw.c.
	* libgcc/config/rs6000/floatuntikf.c: Renamed to floatuntikf-sw.c.
	* libgcc/config/rs6000/quaad-float128.h (__floattikf_sw,
	__floatuntikf_sw, __fixkfti_sw, __fixunskfti_sw, __floattikf_hw,
	__floatuntikf_hw, __fixkfti_hw, __fixunskfti_hw, __floattikf,
	__floatuntikf, __fixkfti, __fixunskfti): New extern declarations.
	* libgcc/config/rs6000/t-float128 (floattikf, floatuntikf,
	fixkfti, fixunskfti): Remove file names from fp128_ppc_funcs.
	(floattikf-sw, floatuntikf-sw, fixkfti-sw, fixunskfti-sw): Add
	file names to fp128_ppc_funcs.
	* libgcc/config/rs6000/t-float128-hw(fp128_3_1_hw_funcs,
	fp128_3_1_hw_src, fp128_3_1_hw_static_obj, fp128_3_1_hw_shared_obj,
	fp128_3_1_hw_obj): Add variables for ISA 3.1 support.
	* libgcc/config/rs6000/t-float128-p10-hw: New file.
	* configure: Update script for isa 3.1 128-bit float support.
	* configure.ac: Add check for 128-bit float hardware support.
---
 gcc/config/rs6000/rs6000.c                    |   8 +-
 gcc/config/rs6000/rs6000.md                   |  36 +++
 .../gcc.target/powerpc/fp128_conversions.c    | 294 ++++++++++++++++++
 .../gcc.target/powerpc/int_128bit-runnable.c  |  13 +-
 libgcc/config.host                            |   4 +
 .../config/rs6000/{fixkfti.c => fixkfti-sw.c} |   4 +-
 .../rs6000/{fixunskfti.c => fixunskfti-sw.c}  |   4 +-
 libgcc/config/rs6000/float128-ifunc.c         |  44 ++-
 libgcc/config/rs6000/float128-p10.c           |  71 +++++
 libgcc/config/rs6000/float128-sed             |   4 +
 libgcc/config/rs6000/float128-sed-hw          |   4 +
 .../rs6000/{floattikf.c => floattikf-sw.c}    |   4 +-
 .../{floatuntikf.c => floatuntikf-sw.c}       |   4 +-
 libgcc/config/rs6000/quad-float128.h          |  17 +-
 libgcc/config/rs6000/t-float128               |  12 +-
 libgcc/config/rs6000/t-float128-hw            |  16 +
 libgcc/config/rs6000/t-float128-p10-hw        |  24 ++
 libgcc/configure                              |  37 +++
 libgcc/configure.ac                           |  25 ++
 19 files changed, 589 insertions(+), 36 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/fp128_conversions.c
 rename libgcc/config/rs6000/{fixkfti.c => fixkfti-sw.c} (96%)
 rename libgcc/config/rs6000/{fixunskfti.c => fixunskfti-sw.c} (96%)
 create mode 100644 libgcc/config/rs6000/float128-p10.c
 rename libgcc/config/rs6000/{floattikf.c => floattikf-sw.c} (96%)
 rename libgcc/config/rs6000/{floatuntikf.c => floatuntikf-sw.c} (96%)
 create mode 100644 libgcc/config/rs6000/t-float128-p10-hw

Comments

will schmidt April 27, 2021, 11:46 p.m. UTC | #1
On Mon, 2021-04-26 at 09:36 -0700, Carl Love wrote:
> Will, Segher:
> 
> This patch adds support for converting to/from 128-bit integers and
> 128-bit decimal floating point formats using the new P10 instructions
> dcffixqq and dctfixqq.  The new instructions are only used on P10 HW,
> otherwise the conversions continue to use the existing SW routines.
> 
> The files fixkfti-sw.c and fixunskfti-sw.c are renamed versions of
> fixkfti.c and fixunskfti.c respectively.  The function names in the
> files were updated with the rename as well as some white spaces fixes.
> 
> The patch has been tested on
>     powerpc64-linux instead (Power 8 BE)
>     powerpc64-linux instead (Power 9 LE)
>     powerpc64-linux instead (Power 10 LE)
> 
> Please let me know if the patch is acceptable for mainline.
> 
>                    Carl Love
> ------------------------------------------------
> 
> gcc/ChangeLog
> 
> 2021-04-26  Carl Love  <cel@us.ibm.com>
> 	* config/rs6000/rs6000.md (floatti<mode>2, floatunsti<mode>2,
> 	fix_trunc<mode>ti2, fixuns_trunc<mode>ti2): Add
> 	define_insn for mode IEEE 128.
> 
> gcc/testsuite/ChangeLog
> 
> 2021-04-26  Carl Love  <cel@us.ibm.com>
> 	* gcc.target/powerpc/fp128_conversions.c: New file.
> 	* gcc.target/powerpc/int_128bit-runnable.c(vextsd2ppc_native_128bitq,

^ vextsd2ppc_native_128bitq ?   

> 	vcmpuq, vcmpsq, vcmpequq, vcmpequq., vcmpgtsq, vcmpgtsq.
> 	vcmpgtuq, vcmpgtuq.): Update scan-assembler-times.

> 	(ppc_native_128bit): Remove dg-require-effective-target.
> 
> libgcc/ChangeLog
> 2021-04-26  Carl Love  <cel@us.ibm.com>
> 	* config.host: Add if test and set for
> 	libgcc_cv_powerpc_3_1_float128_hw.
> 	* libgcc/config/rs6000/fixkfti.c: Renamed to fixkfti-sw.c.
> 	Change calls of __fixkfti to __fixkfti_sw.
> 	* libgcc/config/rs6000/fixunskfti.c: Renamed to fixunskfti-sw.c.
> 	Change calls of __fixunskfti to __fixunskfti_sw.
> 	* libgcc/config/rs6000/float128-p10.c (__floattikf_hw,
> 	__floatuntikf_hw, __fixkfti_hw, __fixunskfti_hw): New file.
> 	* libgcc/config/rs6000/float128-ifunc.c (SW_OR_HW_ISA3_1): New macro.
> 	(__floattikf_resolve, __floatuntikf_resolve, __fixkfti_resolve,
> 	__fixunskfti_resolve): Add resolve functions.
> 	(__floattikf, __floatuntikf, __fixkfti, __fixunskfti): New functions.
> 	* libgcc/config/rs6000/float128-sed (floattitf, __floatuntitf,
> 	__fixtfti, __fixunstfti): Add editor commands to change names.
> 	* libgcc/config/rs6000/float128-sed-hw (__floattitf,
> 	__floatuntitf, __fixtfti, __fixunstfti): Add editor commands to
> 	change names.
> 	* libgcc/config/rs6000/floattikf.c: Renamed to floattikf-sw.c.
> 	* libgcc/config/rs6000/floatuntikf.c: Renamed to floatuntikf-sw.c.
> 	* libgcc/config/rs6000/quaad-float128.h (__floattikf_sw,
> 	__floatuntikf_sw, __fixkfti_sw, __fixunskfti_sw, __floattikf_hw,
> 	__floatuntikf_hw, __fixkfti_hw, __fixunskfti_hw, __floattikf,
> 	__floatuntikf, __fixkfti, __fixunskfti): New extern declarations.
> 	* libgcc/config/rs6000/t-float128 (floattikf, floatuntikf,
> 	fixkfti, fixunskfti): Remove file names from fp128_ppc_funcs.
> 	(floattikf-sw, floatuntikf-sw, fixkfti-sw, fixunskfti-sw): Add
> 	file names to fp128_ppc_funcs.
> 	* libgcc/config/rs6000/t-float128-hw(fp128_3_1_hw_funcs,
> 	fp128_3_1_hw_src, fp128_3_1_hw_static_obj, fp128_3_1_hw_shared_obj,
> 	fp128_3_1_hw_obj): Add variables for ISA 3.1 support.
> 	* libgcc/config/rs6000/t-float128-p10-hw: New file.
> 	* configure: Update script for isa 3.1 128-bit float support.
> 	* configure.ac: Add check for 128-bit float hardware support.


Ok.

Only skimmed, nothing else jumped out at me from below.

thanks
-Will
Segher Boessenkool June 7, 2021, 6:49 p.m. UTC | #2
On Mon, Apr 26, 2021 at 09:36:33AM -0700, Carl Love wrote:
> This patch adds support for converting to/from 128-bit integers and
> 128-bit decimal floating point formats using the new P10 instructions
> dcffixqq and dctfixqq.  The new instructions are only used on P10 HW,
> otherwise the conversions continue to use the existing SW routines.
> 
> The files fixkfti-sw.c and fixunskfti-sw.c are renamed versions of
> fixkfti.c and fixunskfti.c respectively.  The function names in the
> files were updated with the rename as well as some white spaces fixes.

> --- a/gcc/config/rs6000/rs6000.md
> +++ b/gcc/config/rs6000/rs6000.md
> @@ -6421,6 +6421,42 @@
>     xscvsxddp %x0,%x1"
>    [(set_attr "type" "fp")])
>  
> +(define_insn "floatti<mode>2"
> +  [(set (match_operand:IEEE128 0 "vsx_register_operand" "=v")
> +       (float:IEEE128 (match_operand:TI 1 "vsx_register_operand" "v")))]

Broken indent?  It should be indented by 8 spaces, thus, a tab.  (More of
this further on, please fix all).


It isn't clear to me why you need the separate *_sw and *_hw names, or
if it is just to make it clearer, or maybe something else?  Some words
here would have helped :-)


Okay for trunk.  Thanks!


Segher
diff mbox series

Patch

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 531a9c87243..c7a28044f68 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -11022,10 +11022,10 @@  init_float128_ieee (machine_mode mode)
 
       if (TARGET_POWERPC64)
 	{
-	  set_conv_libfunc (sfix_optab, TImode, mode, "__fixkfti");
-	  set_conv_libfunc (ufix_optab, TImode, mode, "__fixunskfti");
-	  set_conv_libfunc (sfloat_optab, mode, TImode, "__floattikf");
-	  set_conv_libfunc (ufloat_optab, mode, TImode, "__floatuntikf");
+	  set_conv_libfunc (sfix_optab, TImode, mode, "__fixkfti_sw");
+	  set_conv_libfunc (ufix_optab, TImode, mode, "__fixunskfti_sw");
+	  set_conv_libfunc (sfloat_optab, mode, TImode, "__floattikf_sw");
+	  set_conv_libfunc (ufloat_optab, mode, TImode, "__floatuntikf_sw");
 	}
     }
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c8cdc42533c..674c4432661 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -6421,6 +6421,42 @@ 
    xscvsxddp %x0,%x1"
   [(set_attr "type" "fp")])
 
+(define_insn "floatti<mode>2"
+  [(set (match_operand:IEEE128 0 "vsx_register_operand" "=v")
+       (float:IEEE128 (match_operand:TI 1 "vsx_register_operand" "v")))]
+  "TARGET_POWER10"
+{
+  return  "xscvsqqp %0,%1";
+}
+  [(set_attr "type" "fp")])
+
+(define_insn "floatunsti<mode>2"
+  [(set (match_operand:IEEE128 0 "vsx_register_operand" "=v")
+       (unsigned_float:IEEE128 (match_operand:TI 1 "vsx_register_operand" "v")))]
+  "TARGET_POWER10"
+{
+  return  "xscvuqqp %0,%1";
+}
+  [(set_attr "type" "fp")])
+
+(define_insn "fix_trunc<mode>ti2"
+  [(set (match_operand:TI 0 "vsx_register_operand" "=v")
+       (fix:TI (match_operand:IEEE128 1 "vsx_register_operand" "v")))]
+  "TARGET_POWER10"
+{
+  return  "xscvqpsqz %0,%1";
+}
+  [(set_attr "type" "fp")])
+
+(define_insn "fixuns_trunc<mode>ti2"
+  [(set (match_operand:TI 0 "vsx_register_operand" "=v")
+       (unsigned_fix:TI (match_operand:IEEE128 1 "vsx_register_operand" "v")))]
+  "TARGET_POWER10"
+{
+  return  "xscvqpuqz %0,%1";
+}
+  [(set_attr "type" "fp")])
+
 ; Allow the combiner to merge source memory operands to the conversion so that
 ; the optimizer/register allocator doesn't try to load the value too early in a
 ; GPR and then use store/load to move it to a FPR and suffer from a store-load
diff --git a/gcc/testsuite/gcc.target/powerpc/fp128_conversions.c b/gcc/testsuite/gcc.target/powerpc/fp128_conversions.c
new file mode 100644
index 00000000000..c20282fa0e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fp128_conversions.c
@@ -0,0 +1,294 @@ 
+/* { dg-do run } */
+/* { dg-require-effective-target power10_hw } */
+/* { dg-options "-mdejagnu-cpu=power10 -save-temps" } */
+
+/* Check that the expected 128-bit instructions are generated if the processor
+   supports the 128-bit integer instructions. */
+/* { dg-final { scan-assembler-times {\mxscvsqqp\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mxscvuqqp\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mxscvqpsqz\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mxscvqpuqz\M} 1 } } */
+
+#include <stdio.h>
+#include <math.h>
+#include <fenv.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#define DEBUG 0
+
+void
+abort (void);
+
+float
+conv_i_2_fp( long long int a)
+{
+  return (float) a;
+}
+
+double
+conv_i_2_fpd( long long int a)
+{
+  return (double) a;
+}
+
+double
+conv_ui_2_fpd( unsigned long long int a)
+{
+  return (double) a;
+}
+
+__float128
+conv_i128_2_fp128 (__int128_t a)
+{
+  // default, gen inst KF mode
+  // -mabi=ibmlongdouble, gen inst floattiieee KF mode
+  // -mabi=ieeelongdouble gen inst floattiieee TF mode
+  return (__float128) a;
+}
+
+__float128
+conv_ui128_2_fp128 (__uint128_t a)
+{
+  // default, gen inst KF mode
+  // -mabi=ibmlongdouble, gen inst floattiieee KF mode
+  // -mabi=ieeelongdouble gen inst floattiieee TF mode
+  return (__float128) a;
+}
+
+__int128_t
+conv_fp128_2_i128 (__float128 a)
+{
+  // default, gen inst KF mode
+  // -mabi=ibmlongdouble, gen inst floattiieee KF mode
+  // -mabi=ieeelongdouble gen inst floattiieee TF mode
+  return (__int128_t) a;
+}
+
+__uint128_t
+conv_fp128_2_ui128 (__float128 a)
+{
+  // default, gen inst KF mode
+  // -mabi=ibmlongdouble, gen inst floattiieee KF mode
+  // -mabi=ieeelongdouble gen inst floattiieee TF mode
+  return (__uint128_t) a;
+}
+
+long double
+conv_i128_2_ld (__int128_t a)
+{
+  // default, gen call __floattitf
+  // -mabi=ibmlongdouble, gen call __floattitf
+  // -mabi=ieeelongdouble gen inst floattiieee TF mode
+  return (long double) a;
+}
+
+__ibm128
+conv_i128_2_ibm128 (__int128_t a)
+{
+  // default, gen call __floattitf
+  // -mabi=ibmlongdouble, gen call __floattitf
+  // -mabi=ieeelongdouble, message uses IBM long double, no binary output
+  return (__ibm128) a;
+}
+
+int
+main()
+{
+	float a, expected_result_float;
+	double b, expected_result_double;
+	long long int c, expected_result_llint;
+	unsigned long long int u;
+	__int128_t d;
+	__uint128_t u128;
+	unsigned long long expected_result_uint128[2] ;
+	__float128 e;
+	long double ld;     // another 128-bit float version
+
+	union conv_t {
+		float a;
+		double b;
+		long long int c;
+		long long int128[2] ;
+		unsigned long long uint128[2] ;
+		unsigned long long int u;
+		__int128_t d;
+		__uint128_t u128;
+		__float128 e;
+		long double ld;     // another 128-bit float version
+	} conv, conv_result;
+
+	c = 20;
+	expected_result_llint = 20.00000;
+	a = conv_i_2_fp (c);
+
+	if (a != expected_result_llint) {
+#if DEBUG
+		printf("ERROR: conv_i_2_fp(%lld) = %10.5f\n", c, a);
+		printf("\n does not match expected_result = %10.5f\n\n",
+				 expected_result_llint);
+#else
+		abort();
+#endif
+	}
+
+	c = 20;
+	expected_result_double = 20.00000;
+	b = conv_i_2_fpd (c);
+
+	if (b != expected_result_double) {
+#if DEBUG
+		printf("ERROR: conv_i_2_fpd(%lld) = %10.5f\n", d, b);
+		printf("\n does not match expected_result = %10.5f\n\n",
+				 expected_result_double);
+ #else
+		abort();
+#endif
+	}
+
+	u = 20;
+	expected_result_double = 20.00000;
+	b = conv_ui_2_fpd (u);
+
+	if (b != expected_result_double) {
+#if DEBUG
+		printf("ERROR: conv_ui_2_fpd(%llu) = %10.5f\n", u, b);
+		printf("\n does not match expected_result = %10.5f\n\n",
+				 expected_result_double);
+ #else
+		abort();
+#endif
+	}
+
+  d = -3210;
+  d = (d * 10000000000) + 9876543210;
+  conv_result.e = conv_i128_2_fp128 (d);
+  expected_result_uint128[1] = 0xc02bd2f9068d1160;
+  expected_result_uint128[0] = 0x0;
+  
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_i128_2_fp128(-32109876543210) = (result in hex) 0x%llx %llx\n",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  d = 123;
+  d = (d * 10000000000) + 1234567890;
+  conv_result.ld = conv_i128_2_fp128 (d);
+  expected_result_uint128[1] = 0x0;
+  expected_result_uint128[0] = 0x4271eab4c8ed2000;
+
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_i128_2_fp128(1231234567890) = (result in hex) 0x%llx %llx\n",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  u128 = 8760;
+  u128 = (u128 * 10000000000) + 1234567890;
+  conv_result.e = conv_ui128_2_fp128 (u128);
+  expected_result_uint128[1] = 0x402d3eb101df8b48;
+  expected_result_uint128[0] = 0x0;
+
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_ui128_2_fp128(87601234567890) = (result in hex) 0x%llx %llx\n",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  u128 = 3210;
+  u128 = (u128 * 10000000000) + 9876543210;
+  expected_result_uint128[1] = 0x402bd3429c8feea0;
+  expected_result_uint128[0] = 0x0;
+  conv_result.e = conv_ui128_2_fp128 (u128);
+
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_ui128_2_fp128(32109876543210) = (result in hex) 0x%llx %llx\n",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  conv.e = 12345.6789;
+  expected_result_uint128[1] = 0x1407374883526960;
+  expected_result_uint128[0] = 0x3039;
+
+  conv_result.d = conv_fp128_2_i128 (conv.e);
+
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_fp128_2_i128(0x%llx %llx) =  ",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("0x%llx %llx\n", conv_result.uint128[1], conv_result.uint128[0]);
+
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  conv.e = -6789.12345;
+  expected_result_uint128[1] = 0x0;
+  expected_result_uint128[0] = 0xffffffffffffe57b;
+  conv_result.d = conv_fp128_2_i128 (conv.e);
+ 
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_fp128_2_i128(0x%llx %llx) = ",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("0x%llx %llx\n", conv_result.uint128[1], conv_result.uint128[0]);
+
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  conv.e = 6789.12345;
+  expected_result_uint128[1] = 0x0;
+  expected_result_uint128[0] = 0x1a85;
+  conv_result.d = conv_fp128_2_ui128 (conv.e);
+ 
+  if ((conv_result.uint128[1] != expected_result_uint128[1])
+		&& (conv_result.uint128[0] != expected_result_uint128[0])) {
+#if DEBUG
+	  printf("ERROR: conv_fp128_2_ui128(0x%llx %llx) = ",
+				conv.uint128[1], conv.uint128[0]);
+	  printf("0x%llx %llx\n", conv_result.uint128[1], conv_result.uint128[0]);
+	  
+	  printf("\n does not match expected_result = (result in hex) 0x%llx %llx\n\n",
+				expected_result_uint128[1], expected_result_uint128[0]);
+ #else
+	  abort();
+#endif
+	}
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/int_128bit-runnable.c b/gcc/testsuite/gcc.target/powerpc/int_128bit-runnable.c
index 9f7dbc6cc75..94dbd2b6230 100644
--- a/gcc/testsuite/gcc.target/powerpc/int_128bit-runnable.c
+++ b/gcc/testsuite/gcc.target/powerpc/int_128bit-runnable.c
@@ -4,21 +4,16 @@ 
 
 /* Check that the expected 128-bit instructions are generated if the processor
    supports the 128-bit integer instructions. */
+/* { dg-final { scan-assembler-times {\mvextsd2q\M} 4 } } */
 /* { dg-final { scan-assembler-times {\mvslq\M} 2 } } */
 /* { dg-final { scan-assembler-times {\mvsrq\M} 2 } } */
 /* { dg-final { scan-assembler-times {\mvsraq\M} 2 } } */
 /* { dg-final { scan-assembler-times {\mvrlq\M} 2 } } */
 /* { dg-final { scan-assembler-times {\mvrlqnm\M} 2 } } */
 /* { dg-final { scan-assembler-times {\mvrlqmi\M} 2 } } */
-/* { dg-final { scan-assembler-times {\mvcmpuq\M} 0 } } */
-/* { dg-final { scan-assembler-times {\mvcmpsq\M} 0 } } */
-/* { dg-final { scan-assembler-times {\mvcmpequq\M} 0 } } */
-/* { dg-final { scan-assembler-times {\mvcmpequq.\M} 16 } } */
-/* { dg-final { scan-assembler-times {\mvcmpgtsq\M} 0 } } */
-/* { dg-final { scan-assembler-times {\mvcmpgtsq.\M} 16 } } */
-/* { dg-final { scan-assembler-times {\mvcmpgtuq\M} 0 } } */
-/* { dg-final { scan-assembler-times {\mvcmpgtuq.\M} 16 } } */
-/* { dg-final { scan-assembler-times {\mvmuleud\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mvcmpequq\M} 16 } } */
+/* { dg-final { scan-assembler-times {\mvcmpgtsq\M} 16 } } */
+/* { dg-final { scan-assembler-times {\mvcmpgtuq\M} 16 } } */
 /* { dg-final { scan-assembler-times {\mvmuloud\M} 1 } } */
 /* { dg-final { scan-assembler-times {\mvmulesd\M} 1 } } */
 /* { dg-final { scan-assembler-times {\mvmulosd\M} 1 } } */
diff --git a/libgcc/config.host b/libgcc/config.host
index f808b61be70..50f00062232 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -1224,6 +1224,10 @@  powerpc*-*-linux*)
 		tmake_file="${tmake_file} rs6000/t-float128-hw"
 	fi
 
+	if test $libgcc_cv_powerpc_3_1_float128_hw = yes; then
+		tmake_file="${tmake_file} rs6000/t-float128-p10-hw"
+	fi
+
 	extra_parts="$extra_parts ecrti.o ecrtn.o ncrti.o ncrtn.o"
 	md_unwind_header=rs6000/linux-unwind.h
 	;;
diff --git a/libgcc/config/rs6000/fixkfti.c b/libgcc/config/rs6000/fixkfti-sw.c
similarity index 96%
rename from libgcc/config/rs6000/fixkfti.c
rename to libgcc/config/rs6000/fixkfti-sw.c
index 0d965bc6253..cc000fca0f8 100644
--- a/libgcc/config/rs6000/fixkfti.c
+++ b/libgcc/config/rs6000/fixkfti-sw.c
@@ -5,7 +5,7 @@ 
    This file is part of the GNU C Library.
    Contributed by Steven Munroe (munroesj@linux.vnet.ibm.com)
    Code is based on the main soft-fp library written by:
-   	   Uros Bizjak (ubizjak@gmail.com).
+	   Uros Bizjak (ubizjak@gmail.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -35,7 +35,7 @@ 
 #include "quad-float128.h"
 
 TItype
-__fixkfti (TFtype a)
+__fixkfti_sw (TFtype a)
 {
   FP_DECL_EX;
   FP_DECL_Q (A);
diff --git a/libgcc/config/rs6000/fixunskfti.c b/libgcc/config/rs6000/fixunskfti-sw.c
similarity index 96%
rename from libgcc/config/rs6000/fixunskfti.c
rename to libgcc/config/rs6000/fixunskfti-sw.c
index f285b4e3fbd..7a04d1a489a 100644
--- a/libgcc/config/rs6000/fixunskfti.c
+++ b/libgcc/config/rs6000/fixunskfti-sw.c
@@ -5,7 +5,7 @@ 
    This file is part of the GNU C Library.
    Contributed by Steven Munroe (munroesj@linux.vnet.ibm.com)
    Code is based on the main soft-fp library written by:
-   	   Uros Bizjak (ubizjak@gmail.com).
+	   Uros Bizjak (ubizjak@gmail.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -35,7 +35,7 @@ 
 #include "quad-float128.h"
 
 UTItype
-__fixunskfti (TFtype a)
+__fixunskfti_sw (TFtype a)
 {
   FP_DECL_EX;
   FP_DECL_Q (A);
diff --git a/libgcc/config/rs6000/float128-ifunc.c b/libgcc/config/rs6000/float128-ifunc.c
index 85380471c5e..57545dd7edb 100644
--- a/libgcc/config/rs6000/float128-ifunc.c
+++ b/libgcc/config/rs6000/float128-ifunc.c
@@ -46,14 +46,9 @@ 
 #endif
 
 #define SW_OR_HW(SW, HW) (__builtin_cpu_supports ("ieee128") ? HW : SW)
+#define SW_OR_HW_ISA3_1(SW, HW) (__builtin_cpu_supports ("arch_3_1") ? HW : SW)
 
 /* Resolvers.  */
-
-/* We do not provide ifunc resolvers for __fixkfti, __fixunskfti, __floattikf,
-   and __floatuntikf.  There is no ISA 3.0 instruction that converts between
-   128-bit integer types and 128-bit IEEE floating point, or vice versa.  So
-   use the emulator functions for these conversions.  */
-
 static __typeof__ (__addkf3_sw) *
 __addkf3_resolve (void)
 {
@@ -102,6 +97,18 @@  __floatdikf_resolve (void)
   return SW_OR_HW (__floatdikf_sw, __floatdikf_hw);
 }
 
+static __typeof__ (__floattikf_sw) *
+__floattikf_resolve (void)
+{
+  return SW_OR_HW_ISA3_1 (__floattikf_sw, __floattikf_hw);
+}
+
+static __typeof__ (__floatuntikf_sw) *
+__floatuntikf_resolve (void)
+{
+  return SW_OR_HW_ISA3_1 (__floatuntikf_sw, __floatuntikf_hw);
+}
+
 static __typeof__ (__floatunsikf_sw) *
 __floatunsikf_resolve (void)
 {
@@ -114,6 +121,19 @@  __floatundikf_resolve (void)
   return SW_OR_HW (__floatundikf_sw, __floatundikf_hw);
 }
 
+
+static __typeof__ (__fixkfti_sw) *
+__fixkfti_resolve (void)
+{
+  return SW_OR_HW_ISA3_1 (__fixkfti_sw, __fixkfti_hw);
+}
+
+static __typeof__ (__fixunskfti_sw) *
+__fixunskfti_resolve (void)
+{
+  return SW_OR_HW_ISA3_1 (__fixunskfti_sw, __fixunskfti_hw);
+}
+
 static __typeof__ (__fixkfsi_sw) *
 __fixkfsi_resolve (void)
 {
@@ -303,6 +323,18 @@  TFtype __floatsikf (SItype_ppc)
 TFtype __floatdikf (DItype_ppc)
   __attribute__ ((__ifunc__ ("__floatdikf_resolve")));
 
+TFtype __floattikf (TItype_ppc)
+  __attribute__ ((__ifunc__ ("__floattikf_resolve")));
+
+TFtype __floatuntikf (UTItype_ppc)
+  __attribute__ ((__ifunc__ ("__floatuntikf_resolve")));
+
+TItype_ppc __fixkfti (TFtype)
+  __attribute__ ((__ifunc__ ("__fixkfti_resolve")));
+
+UTItype_ppc __fixunskfti (TFtype)
+  __attribute__ ((__ifunc__ ("__fixunskfti_resolve")));
+
 TFtype __floatunsikf (USItype_ppc)
   __attribute__ ((__ifunc__ ("__floatunsikf_resolve")));
 
diff --git a/libgcc/config/rs6000/float128-p10.c b/libgcc/config/rs6000/float128-p10.c
new file mode 100644
index 00000000000..7f5d317631a
--- /dev/null
+++ b/libgcc/config/rs6000/float128-p10.c
@@ -0,0 +1,71 @@ 
+/* Automatic switching between software and hardware IEEE 128-bit
+   ISA 3.1 floating-point emulation for PowerPC.
+
+   Copyright (C) 2016-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Carl Love (cel@us.ibm.com)
+   Code is based on the main soft-fp library written by:
+	Richard Henderson (rth@cygnus.com) and
+	Jakub Jelinek (jj@ultra.linux.cz).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file into
+   combinations with other programs, and to distribute those
+   combinations without any restriction coming from the use of this
+   file.  (The Lesser General Public License restrictions do apply in
+   other respects; for example, they cover modification of the file,
+   and distribution when not linked into a combine executable.)
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Note, the hardware conversion instructions for 128-bit integers are
+   supported for ISA 3.1 and later.  Only compile this file with -mcpu=power10
+   or newer support.  */
+
+#include <soft-fp.h>
+#include <quad-float128.h>
+
+#ifndef __FLOAT128_HARDWARE__
+#error "This module must be compiled with IEEE 128-bit hardware support"
+#endif
+
+#ifndef _ARCH_PWR10
+#error "This module must be compiled for Power 10 support"
+#endif
+
+TFtype
+__floattikf_hw (TItype_ppc a)
+{
+  return (TFtype) a;
+}
+
+TFtype
+__floatuntikf_hw (UTItype_ppc a)
+{
+  return (TFtype) a;
+}
+
+TItype_ppc
+__fixkfti_hw (TFtype a)
+{
+  return (TItype_ppc) a;
+}
+
+UTItype_ppc
+__fixunskfti_hw (TFtype a)
+{
+  return (UTItype_ppc) a;
+}
diff --git a/libgcc/config/rs6000/float128-sed b/libgcc/config/rs6000/float128-sed
index d9a089ff9ba..c0fcddb1959 100644
--- a/libgcc/config/rs6000/float128-sed
+++ b/libgcc/config/rs6000/float128-sed
@@ -8,6 +8,10 @@  s/__fixtfsi/__fixkfsi/g
 s/__fixunstfdi/__fixunskfdi/g
 s/__fixunstfsi/__fixunskfsi/g
 s/__floatditf/__floatdikf/g
+s/__floattitf/__floattikf/g
+s/__floatuntitf/__floatuntikf/g
+s/__fixtfti/__fixkfti/g
+s/__fixunstfti/__fixunskfti/g
 s/__floatsitf/__floatsikf/g
 s/__floatunditf/__floatundikf/g
 s/__floatunsitf/__floatunsikf/g
diff --git a/libgcc/config/rs6000/float128-sed-hw b/libgcc/config/rs6000/float128-sed-hw
index acf36b0c17d..3d2bf556da1 100644
--- a/libgcc/config/rs6000/float128-sed-hw
+++ b/libgcc/config/rs6000/float128-sed-hw
@@ -8,6 +8,10 @@  s/__fixtfsi/__fixkfsi_sw/g
 s/__fixunstfdi/__fixunskfdi_sw/g
 s/__fixunstfsi/__fixunskfsi_sw/g
 s/__floatditf/__floatdikf_sw/g
+s/__floattitf/__floattikf_sw/g
+s/__floatuntitf/__floatuntikf_sw/g
+s/__fixtfti/__fixkfti_sw/g
+s/__fixunstfti/__fixunskfti_sw/g
 s/__floatsitf/__floatsikf_sw/g
 s/__floatunditf/__floatundikf_sw/g
 s/__floatunsitf/__floatunsikf_sw/g
diff --git a/libgcc/config/rs6000/floattikf.c b/libgcc/config/rs6000/floattikf-sw.c
similarity index 96%
rename from libgcc/config/rs6000/floattikf.c
rename to libgcc/config/rs6000/floattikf-sw.c
index cc5c7ca0fd0..4e1786cd229 100644
--- a/libgcc/config/rs6000/floattikf.c
+++ b/libgcc/config/rs6000/floattikf-sw.c
@@ -5,7 +5,7 @@ 
    This file is part of the GNU C Library.
    Contributed by Steven Munroe (munroesj@linux.vnet.ibm.com)
    Code is based on the main soft-fp library written by:
-   	   Uros Bizjak (ubizjak@gmail.com).
+	   Uros Bizjak (ubizjak@gmail.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -35,7 +35,7 @@ 
 #include "quad-float128.h"
 
 TFtype
-__floattikf (TItype i)
+__floattikf_sw (TItype i)
 {
   FP_DECL_EX;
   FP_DECL_Q (A);
diff --git a/libgcc/config/rs6000/floatuntikf.c b/libgcc/config/rs6000/floatuntikf-sw.c
similarity index 96%
rename from libgcc/config/rs6000/floatuntikf.c
rename to libgcc/config/rs6000/floatuntikf-sw.c
index 96f2d3bdcb8..c4b814ddd68 100644
--- a/libgcc/config/rs6000/floatuntikf.c
+++ b/libgcc/config/rs6000/floatuntikf-sw.c
@@ -5,7 +5,7 @@ 
    This file is part of the GNU C Library.
    Contributed by Steven Munroe (munroesj@linux.vnet.ibm.com)
    Code is based on the main soft-fp library written by:
-   	   Uros Bizjak (ubizjak@gmail.com).
+	   Uros Bizjak (ubizjak@gmail.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -35,7 +35,7 @@ 
 #include "quad-float128.h"
 
 TFtype
-__floatuntikf (UTItype i)
+__floatuntikf_sw (UTItype i)
 {
   FP_DECL_EX;
   FP_DECL_Q (A);
diff --git a/libgcc/config/rs6000/quad-float128.h b/libgcc/config/rs6000/quad-float128.h
index 5beb1531d2b..c4d775b4ad3 100644
--- a/libgcc/config/rs6000/quad-float128.h
+++ b/libgcc/config/rs6000/quad-float128.h
@@ -88,19 +88,18 @@  extern USItype_ppc __fixunskfsi_sw (TFtype);
 extern UDItype_ppc __fixunskfdi_sw (TFtype);
 extern TFtype __floatsikf_sw (SItype_ppc);
 extern TFtype __floatdikf_sw (DItype_ppc);
+extern TFtype __floattikf_sw (TItype_ppc);
 extern TFtype __floatunsikf_sw (USItype_ppc);
 extern TFtype __floatundikf_sw (UDItype_ppc);
+extern TFtype __floatuntikf_sw (UTItype_ppc);
+extern TItype_ppc __fixkfti_sw (TFtype);
+extern UTItype_ppc __fixunskfti_sw (TFtype);
 extern IBM128_TYPE __extendkftf2_sw (TFtype);
 extern TFtype __trunctfkf2_sw (IBM128_TYPE);
 extern TCtype __mulkc3_sw (TFtype, TFtype, TFtype, TFtype);
 extern TCtype __divkc3_sw (TFtype, TFtype, TFtype, TFtype);
 
 #ifdef _ARCH_PPC64
-/* We do not provide ifunc resolvers for __fixkfti, __fixunskfti, __floattikf,
-   and __floatuntikf.  There is no ISA 3.0 instruction that converts between
-   128-bit integer types and 128-bit IEEE floating point, or vice versa.  So
-   use the emulator functions for these conversions.  */
-
 extern TItype_ppc __fixkfti (TFtype);
 extern UTItype_ppc __fixunskfti (TFtype);
 extern TFtype __floattikf (TItype_ppc);
@@ -131,8 +130,12 @@  extern USItype_ppc __fixunskfsi_hw (TFtype);
 extern UDItype_ppc __fixunskfdi_hw (TFtype);
 extern TFtype __floatsikf_hw (SItype_ppc);
 extern TFtype __floatdikf_hw (DItype_ppc);
+extern TFtype __floattikf_hw (TItype_ppc);
 extern TFtype __floatunsikf_hw (USItype_ppc);
 extern TFtype __floatundikf_hw (UDItype_ppc);
+extern TFtype __floatuntikf_hw (UTItype_ppc);
+extern TItype_ppc __fixkfti_hw (TFtype);
+extern UTItype_ppc __fixunskfti_hw (TFtype);
 extern IBM128_TYPE __extendkftf2_hw (TFtype);
 extern TFtype __trunctfkf2_hw (IBM128_TYPE);
 extern TCtype __mulkc3_hw (TFtype, TFtype, TFtype, TFtype);
@@ -163,8 +166,12 @@  extern USItype_ppc __fixunskfsi (TFtype);
 extern UDItype_ppc __fixunskfdi (TFtype);
 extern TFtype __floatsikf (SItype_ppc);
 extern TFtype __floatdikf (DItype_ppc);
+extern TFtype __floattikf (TItype_ppc);
 extern TFtype __floatunsikf (USItype_ppc);
 extern TFtype __floatundikf (UDItype_ppc);
+extern TFtype __floatuntikf (UTItype_ppc);
+extern TItype_ppc __fixkfti (TFtype);
+extern UTItype_ppc __fixunskfti (TFtype);
 extern IBM128_TYPE __extendkftf2 (TFtype);
 extern TFtype __trunctfkf2 (IBM128_TYPE);
 
diff --git a/libgcc/config/rs6000/t-float128 b/libgcc/config/rs6000/t-float128
index d745f0d82e1..b09b5664af0 100644
--- a/libgcc/config/rs6000/t-float128
+++ b/libgcc/config/rs6000/t-float128
@@ -31,7 +31,8 @@  ibm128_dec_funcs	= _tf_to_sd _tf_to_dd _tf_to_td \
 			  _sd_to_tf _dd_to_tf _td_to_tf
 
 # New functions for software emulation
-fp128_ppc_funcs		= floattikf floatuntikf fixkfti fixunskfti \
+fp128_ppc_funcs		= floattikf-sw floatuntikf-sw \
+			  fixkfti-sw fixunskfti-sw \
 			  extendkftf2-sw trunctfkf2-sw \
 			  sfp-exceptions _mulkc3 _divkc3 _powikf2
 
@@ -47,13 +48,16 @@  fp128_ppc_obj		= $(fp128_ppc_static_obj) $(fp128_ppc_shared_obj)
 
 # All functions
 fp128_funcs		= $(fp128_softfp_funcs) $(fp128_ppc_funcs) \
-			  $(fp128_hw_funcs) $(fp128_ifunc_funcs)
+			  $(fp128_hw_funcs) $(fp128_ifunc_funcs) \
+			  $(fp128_3_1_hw_funcs)
 
 fp128_src		= $(fp128_softfp_src) $(fp128_ppc_src) \
-			  $(fp128_hw_src) $(fp128_ifunc_src)
+			  $(fp128_hw_src) $(fp128_ifunc_src) \
+			  $(fp128_3_1_hw_src)
 
 fp128_obj		= $(fp128_softfp_obj) $(fp128_ppc_obj) \
-			  $(fp128_hw_obj) $(fp128_ifunc_obj)
+			  $(fp128_hw_obj) $(fp128_ifunc_obj) \
+			  $(fp128_3_1_hw_obj)
 
 fp128_sed		= $(srcdir)/config/rs6000/float128-sed$(fp128_sed_hw)
 fp128_dep		= $(fp128_sed) $(srcdir)/config/rs6000/t-float128
diff --git a/libgcc/config/rs6000/t-float128-hw b/libgcc/config/rs6000/t-float128-hw
index d64ca4dd694..c0827366cc4 100644
--- a/libgcc/config/rs6000/t-float128-hw
+++ b/libgcc/config/rs6000/t-float128-hw
@@ -13,6 +13,13 @@  fp128_hw_static_obj	= $(addsuffix $(objext),$(fp128_hw_funcs))
 fp128_hw_shared_obj	= $(addsuffix _s$(objext),$(fp128_hw_funcs))
 fp128_hw_obj		= $(fp128_hw_static_obj) $(fp128_hw_shared_obj)
 
+# New functions for ISA 3.1 hardware support
+fp128_3_1_hw_funcs	= float128-p10
+fp128_3_1_hw_src	= $(srcdir)/config/rs6000/float128-p10.c
+fp128_3_1_hw_static_obj	= $(addsuffix $(objext),$(fp128_3_1_hw_funcs))
+fp128_3_1_hw_shared_obj	= $(addsuffix _s$(objext),$(fp128_3_1_hw_funcs))
+fp128_3_1_hw_obj	= $(fp128_3_1_hw_static_obj) $(fp128_3_1_hw_shared_obj)
+
 fp128_ifunc_funcs	= float128-ifunc
 fp128_ifunc_src		= $(srcdir)/config/rs6000/float128-ifunc.c
 fp128_ifunc_static_obj	= float128-ifunc$(objext)
@@ -30,9 +37,18 @@  FP128_CFLAGS_HW		 = -Wno-type-limits -mvsx -mfloat128 \
 			   -I$(srcdir)/config/rs6000 \
 			   $(FLOAT128_HW_INSNS)
 
+FP128_3_1_CFLAGS_HW	 = -Wno-type-limits -mvsx -mcpu=power10 \
+			   -mfloat128-hardware -mno-gnu-attribute \
+			   -I$(srcdir)/soft-fp \
+			   -I$(srcdir)/config/rs6000 \
+			   $(FLOAT128_HW_INSNS)
+
 $(fp128_hw_obj)		 : INTERNAL_CFLAGS += $(FP128_CFLAGS_HW)
 $(fp128_hw_obj)		 : $(srcdir)/config/rs6000/t-float128-hw
 
+$(fp128_3_1_hw_obj)	 : INTERNAL_CFLAGS += $(FP128_3_1_CFLAGS_HW)
+$(fp128_3_1_hw_obj)	 : $(srcdir)/config/rs6000/t-float128-p10-hw
+
 $(fp128_ifunc_obj)	 : INTERNAL_CFLAGS += $(FP128_CFLAGS_SW)
 $(fp128_ifunc_obj)	 : $(srcdir)/config/rs6000/t-float128-hw
 
diff --git a/libgcc/config/rs6000/t-float128-p10-hw b/libgcc/config/rs6000/t-float128-p10-hw
new file mode 100644
index 00000000000..de36227c3d1
--- /dev/null
+++ b/libgcc/config/rs6000/t-float128-p10-hw
@@ -0,0 +1,24 @@ 
+# Support for adding __float128 hardware support to the powerpc.
+# Tell the float128 functions that the ISA 3.1 hardware support can
+# be compiled it to be selected via IFUNC functions.
+
+FLOAT128_HW_INSNS	= -DFLOAT128_HW_INSNS
+
+# New functions for hardware support
+
+fp128_3_1_hw_funcs	= float128-p10
+fp128_3_1_hw_src	= $(srcdir)/config/rs6000/float128-p10.c
+fp128_3_1_hw_static_obj	= $(addsuffix $(objext),$(fp128_3_1_hw_funcs))
+fp128_3_1_hw_shared_obj	= $(addsuffix _s$(objext),$(fp128_3_1_hw_funcs))
+fp128_3_1_hw_obj	= $(fp128_3_1_hw_static_obj) $(fp128_3_1_hw_shared_obj)
+
+# Build the hardware support functions with appropriate hardware support
+FP128_3_1_CFLAGS_HW	 = -Wno-type-limits -mvsx -mfloat128 \
+			   -mpower10 \
+			   -mfloat128-hardware -mno-gnu-attribute \
+			   -I$(srcdir)/soft-fp \
+			   -I$(srcdir)/config/rs6000 \
+			   $(FLOAT128_HW_INSNS)
+
+$(fp128_3_1_hw_obj)		 : INTERNAL_CFLAGS += $(FP128_3_1_CFLAGS_HW)
+$(fp128_3_1_hw_obj)		 : $(srcdir)/config/rs6000/t-float128-p10-hw
diff --git a/libgcc/configure b/libgcc/configure
index dd3afb2c957..ce05e0dd48b 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -5263,6 +5263,43 @@  fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_powerpc_float128_hw" >&5
 $as_echo "$libgcc_cv_powerpc_float128_hw" >&6; }
   CFLAGS="$saved_CFLAGS"
+
+  saved_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -mpower10 -mfloat128-hardware"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PowerPC ISA 3.1 to build hardware __float128 libraries" >&5
+$as_echo_n "checking for PowerPC ISA 3.1 to build hardware __float128 libraries... " >&6; }
+if ${libgcc_cv_powerpc_float128_hw+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/auxv.h>
+     #ifndef AT_PLATFORM
+     #error "AT_PLATFORM is not defined"
+     #endif
+     #ifndef __BUILTIN_CPU_SUPPORTS__
+     #error "__builtin_cpu_supports is not available"
+     #endif
+     vector unsigned char add (vector unsigned char a, vector unsigned char b)
+     {
+       vector unsigned char ret;
+       __asm__ ("xscvsqqp %0,%1,%2" : "=v" (ret) : "v" (a), "v" (b));
+       return ret;
+     }
+     void *add_resolver (void) { return (void *) add; }
+     __float128 add_ifunc (__float128, __float128)
+	__attribute__ ((__ifunc__ ("add_resolver")));
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_powerpc_3_1_float128_hw=yes
+else
+  libgcc_cv_powerpc_3_1_float128_hw=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_powerpc_float128_hw" >&5
+  $as_echo "$libgcc_cv_powerpc_float128_hw" >&6; }
+  CFLAGS="$saved_CFLAGS"
 esac
 
 # Collect host-machine-specific information.
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 10ffb046415..bc315dec7e4 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -458,6 +458,31 @@  powerpc*-*-linux*)
     [libgcc_cv_powerpc_float128_hw=yes],
     [libgcc_cv_powerpc_float128_hw=no])])
   CFLAGS="$saved_CFLAGS"
+
+  saved_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -mpower10 -mfloat128-hardware"
+  AC_CACHE_CHECK([for PowerPC ISA 3.1 to build hardware __float128 libraries],
+		 [libgcc_cv_powerpc_float128_hw],
+		 [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([#include <sys/auxv.h>
+     #ifndef AT_PLATFORM
+     #error "AT_PLATFORM is not defined"
+     #endif
+     #ifndef __BUILTIN_CPU_SUPPORTS__
+     #error "__builtin_cpu_supports is not available"
+     #endif
+     vector unsigned char add (vector unsigned char a, vector unsigned char b)
+     {
+       vector unsigned char ret;
+       __asm__ ("xscvsqqp %0,%1,%2" : "=v" (ret) : "v" (a), "v" (b));
+       return ret;
+     }
+     void *add_resolver (void) { return (void *) add; }
+     __float128 add_ifunc (__float128, __float128)
+	__attribute__ ((__ifunc__ ("add_resolver")));])],
+    [libgcc_cv_powerpc_3_1_float128_hw=yes],
+    [libgcc_cv_powerpc_3_1_float128_hw=no])])
+  CFLAGS="$saved_CFLAGS"
 esac
 
 # Collect host-machine-specific information.