Hi All,

The following patch has been bootstrapped and regtested on powerpc64le-linux.

PTImode is used to generate even/odd register pairs for 128-bit values. When
PTImode is specified via a type attribute, compilation fails because no
internal type exists to represent this mode.

Introduce signed and unsigned PTImode internal builtin types to handle PTImode.
These __pti_internal types are not documented, as they are not intended for
direct user use.

2026-02-19  Jeevitha Palanisamy  <[email protected]>

gcc/
        PR target/106895
        * config/rs6000/rs6000.h (enum rs6000_builtin_type_index): Add
        RS6000_BTI_INTPTI and RS6000_BTI_UINTPTI.
        (intPTI_type_internal_node, uintPTI_type_internal_node): New
        PTImode type macros.
        * config/rs6000/rs6000-builtin.cc (rs6000_init_builtins): Register
        signed and unsigned PTImode internal builtin types.
        * config/rs6000/sync.md (trunctipti2): New splitter.
        (extendptiti2): Likewise.
        (zero_extendptiti2): Likewise.

gcc/testsuite/
        PR target/106895
        * gcc.target/powerpc/pr106895.c: New test.

diff --git a/gcc/config/rs6000/rs6000-builtin.cc 
b/gcc/config/rs6000/rs6000-builtin.cc
index 45c88fe063b..6663e23f9ac 100644
--- a/gcc/config/rs6000/rs6000-builtin.cc
+++ b/gcc/config/rs6000/rs6000-builtin.cc
@@ -756,6 +756,19 @@ rs6000_init_builtins (void)
   else
     ieee128_float_type_node = NULL_TREE;
 
+  /* PTImode to get even/odd register pairs.  */
+  intPTI_type_internal_node = make_signed_type (GET_MODE_BITSIZE (PTImode));
+  SET_TYPE_MODE (intPTI_type_internal_node, PTImode);
+  t = build_qualified_type (intPTI_type_internal_node, TYPE_QUAL_CONST);
+  lang_hooks.types.register_builtin_type (intPTI_type_internal_node,
+                                         "__pti_internal");
+
+  uintPTI_type_internal_node = make_unsigned_type (GET_MODE_BITSIZE (PTImode));
+  SET_TYPE_MODE (uintPTI_type_internal_node, PTImode);
+  t = build_qualified_type (uintPTI_type_internal_node, TYPE_QUAL_CONST);
+  lang_hooks.types.register_builtin_type (uintPTI_type_internal_node,
+                                         "__upti_internal");
+
   /* Vector pair and vector quad support.  */
   vector_pair_type_node = make_node (OPAQUE_TYPE);
   SET_TYPE_MODE (vector_pair_type_node, OOmode);
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 2b90694cef1..d85f71aa65d 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -2285,6 +2285,8 @@ enum rs6000_builtin_type_index
   RS6000_BTI_ptr_vector_quad,
   RS6000_BTI_ptr_long_long,
   RS6000_BTI_ptr_long_long_unsigned,
+  RS6000_BTI_INTPTI,
+  RS6000_BTI_UINTPTI,
   RS6000_BTI_MAX
 };
 
@@ -2329,6 +2331,8 @@ enum rs6000_builtin_type_index
 #define uintDI_type_internal_node       
(rs6000_builtin_types[RS6000_BTI_UINTDI])
 #define intTI_type_internal_node        
(rs6000_builtin_types[RS6000_BTI_INTTI])
 #define uintTI_type_internal_node       
(rs6000_builtin_types[RS6000_BTI_UINTTI])
+#define intPTI_type_internal_node       
(rs6000_builtin_types[RS6000_BTI_INTPTI])
+#define uintPTI_type_internal_node      
(rs6000_builtin_types[RS6000_BTI_UINTPTI])
 #define float_type_internal_node        
(rs6000_builtin_types[RS6000_BTI_float])
 #define double_type_internal_node       
(rs6000_builtin_types[RS6000_BTI_double])
 #define long_double_type_internal_node  
(rs6000_builtin_types[RS6000_BTI_long_double])
diff --git a/gcc/config/rs6000/sync.md b/gcc/config/rs6000/sync.md
index a4e8344ef11..c31339e7b2e 100644
--- a/gcc/config/rs6000/sync.md
+++ b/gcc/config/rs6000/sync.md
@@ -198,6 +198,54 @@
   DONE;
 })
 
+;; PTI and TI are both 128-bit modes; the following conversions are
+;; register-class changes only, no actual truncation, sign or zero
+;; extension occurs.
+(define_insn_and_split "trunctipti2"
+  [(set (match_operand:PTI 0 "register_operand" "=r")
+        (truncate:PTI (match_operand:TI 1 "register_operand" "r")))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+{
+  operands[2] = gen_lowpart (DImode, operands[0]);
+  operands[3] = gen_highpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_highpart (DImode, operands[1]);
+})
+
+(define_insn_and_split "extendptiti2"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+        (sign_extend:TI (match_operand:PTI 1 "register_operand" "r")))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+{
+  operands[2] = gen_lowpart (DImode, operands[0]);
+  operands[3] = gen_highpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_highpart (DImode, operands[1]);
+})
+
+(define_insn_and_split "zero_extendptiti2"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+        (zero_extend:TI (match_operand:PTI 1 "register_operand" "r")))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+{
+  operands[2] = gen_lowpart (DImode, operands[0]);
+  operands[3] = gen_highpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_highpart (DImode, operands[1]);
+})
+
 ;; If TARGET_PREFIXED, always use pstq rather than stq.
 (define_insn "store_quadpti"
   [(set (match_operand:PTI 0 "quad_memory_operand" "=wQ")
diff --git a/gcc/testsuite/gcc.target/powerpc/pr106895.c 
b/gcc/testsuite/gcc.target/powerpc/pr106895.c
new file mode 100644
index 00000000000..d38d58f5d42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr106895.c
@@ -0,0 +1,17 @@
+/* PR target/106895 */
+/* { dg-do assemble } */
+/* { dg-require-effective-target int128 } */
+/* { dg-options "-O2 -save-temps" } */
+
+/* Verify the following generates even/odd register pairs.  */
+
+typedef __int128 pti __attribute__((mode(PTI)));
+
+void
+set128 (pti val, pti *mem)
+{
+  asm ("stq %1,%0" : "=m" (*mem) : "r" (val));
+}
+
+/* { dg-final { scan-assembler {\mstq\M} } } */
+

Reply via email to