https://gcc.gnu.org/g:f85d222359d056353677bc2fc4a8ca9d2f1a4f5e

commit f85d222359d056353677bc2fc4a8ca9d2f1a4f5e
Author: Michael Meissner <[email protected]>
Date:   Thu Jun 18 23:20:14 2026 -0400

    [PATCH] Add paddis support.
    
    This patch adds support for the paddis instruction that might be added to a
    future PowerPC processor.
    
    2026-06-18  Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/constraints.md (eU): New constraint.
            (eV): Likewise.
            * config/rs6000/predicates.md (paddis_operand): New predicate.
            (paddis_paddi_operand): Likewise.
            (add_cint_operand): Add paddis support.
            (add_operand): Likewise.
            * config/rs6000/rs6000.cc (num_insns_constant_gpr): Likewise.
            (print_operand): Add %B<n> for paddis support.
            * config/rs6000/rs6000.h (TARGET_PADDIS): New macro.
            (SIGNED_INTEGER_64BIT_P): Likewise.
            * config/rs6000/rs6000.md (isa attribute): Add paddis support.
            (enabled attribute); Likewise.
            (add<mode>3): Likewise.
            (adddi3 splitter): New splitter for paddis.
            (movdi_internal64): Add paddis support.
            (movdi splitter): New splitter for paddis.
            * doc/md.texi (PowerPC constraints): Add eU and eV documentation.
    
    gcc/testsuite/
    
            * gcc.target/powerpc/prefixed-addis.c: New test.
    
    2026-06-18  Michael Meissner  <[email protected]>
    
    gcc/
    
            * config/rs6000/predicates.md (paddis_paddi_operand): Only handle
            postive values.  Simplify test for addis/rldicl.
            (add_cint_operand): Do not allow paddis+paddi operands here.
            (reg_or_add_cint_operand): Add paddis/paddi support here.
            * config/rs6000/rs6000.md (add<mode>3, define_expand): Use 
op0/op1/op2
            instead of operands[0]/operands[1]/operands[2].  If the add could 
be done via
            paddis + paddi/addi, split it here.
            (*add<mode>3, define_insn): Remove paddis+paddi support.
            (add<mode>3 splitter for paddis+paddi): Delete.
            (spliter to load constant int with paddis+paddi): Simplify code.
    ---
     gcc/config/rs6000/predicates.md | 16 +++---
     gcc/config/rs6000/rs6000.md     | 99 ++++++++++++++++-----------------
     2 files changed, 57 insertions(+), 58 deletions(-)
    
    diff --git a/gcc/config/rs6000/predicates.md 
b/gcc/config/rs6000/predicates.md
    index 4800cc7fe5a..841619570c1 100644
    --- a/gcc/config/rs6000/predicates.md
    +++ b/gcc/config/rs6000/predicates.md
    @@ -433,13 +433,16 @@ (define_predicate "paddis_paddi_operand"
       if (!SIGNED_INTEGER_64BIT_P (value))
         return false;
    
    +  /* Don't worry about negative values at the moment.  */
    +  if (value < 0)
    +    return false;
    +
       /* If paddi alone can handle the number, don't return true.  */
       if (SIGNED_INTEGER_34BIT_P (value))
         return false;
    
       /* If we can do the add or generate the constant via addis/rldicl, fail. 
 */
    -  if (num_insns_constant (op, mode) == 2
    -      && rs6000_is_valid_and_mask (op, mode))
    +  if (rs6000_is_valid_and_mask (op, mode))
         return false;
    
       /* Only return true if we need both paddi and paddis.  */
    @@ -647,14 +650,14 @@ (define_predicate "add_cint_operand"
                               + (mode == SImode ? 0x80000000 : 0x80008000))
                            < (unsigned HOST_WIDE_INT) 0x100000000ll")
                (match_operand 0 "cint34_operand")
    -           (match_operand 0 "paddis_operand")
    -           (match_operand 0 "paddis_paddi_operand"))))
    +           (match_operand 0 "paddis_operand"))))
    
     ;; Return 1 if op is a constant integer valid for addition
     ;; or non-special register.
     (define_predicate "reg_or_add_cint_operand"
       (if_then_else (match_code "const_int")
    -    (match_operand 0 "add_cint_operand")
    +    (ior (match_operand 0 "add_cint_operand")
    +        (match_operand 0 "paddis_paddi_operand"))
         (match_operand 0 "gpc_reg_operand")))
    
     ;; Return 1 if op is a constant integer valid for subtraction
    @@ -1207,8 +1210,7 @@ (define_predicate "add_operand"
         (match_test "satisfies_constraint_I (op)
                     || satisfies_constraint_L (op)
                     || satisfies_constraint_eI (op)
    -                || satisfies_constraint_eU (op)
    -                || satisfies_constraint_eV (op)")
    +                || satisfies_constraint_eU (op)")
         (match_operand 0 "gpc_reg_operand")))
    
     ;; Return 1 if the operand is either a non-special register, or 0, or -1.
    diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
    index edfeca2040d..f1688ce409b 100644
    --- a/gcc/config/rs6000/rs6000.md
    +++ b/gcc/config/rs6000/rs6000.md
    @@ -1914,14 +1914,18 @@ (define_expand "add<mode>3"
                      (match_operand:SDI 2 "reg_or_add_cint_operand")))]
       ""
     {
    +  rtx op0 = operands[0];
    +  rtx op1 = operands[1];
    +  rtx op2 = operands[2];
    +
       if (<MODE>mode == DImode && !TARGET_POWERPC64)
         {
    -      rtx lo0 = gen_lowpart (SImode, operands[0]);
    -      rtx lo1 = gen_lowpart (SImode, operands[1]);
    -      rtx lo2 = gen_lowpart (SImode, operands[2]);
    -      rtx hi0 = gen_highpart (SImode, operands[0]);
    -      rtx hi1 = gen_highpart (SImode, operands[1]);
    -      rtx hi2 = gen_highpart_mode (SImode, DImode, operands[2]);
    +      rtx lo0 = gen_lowpart (SImode, op0);
    +      rtx lo1 = gen_lowpart (SImode, op1);
    +      rtx lo2 = gen_lowpart (SImode, op2);
    +      rtx hi0 = gen_highpart (SImode, op0);
    +      rtx hi1 = gen_highpart (SImode, op1);
    +      rtx hi2 = gen_highpart_mode (SImode, DImode, op2);
    
           if (!reg_or_short_operand (lo2, SImode))
            lo2 = force_reg (SImode, lo2);
    @@ -1933,24 +1937,40 @@ (define_expand "add<mode>3"
           DONE;
         }
    
    -  if (CONST_INT_P (operands[2]) && !add_operand (operands[2], <MODE>mode))
    +  if (CONST_INT_P (op2) && !add_operand (op2, <MODE>mode))
         {
    -      rtx tmp = ((!can_create_pseudo_p ()
    -                 || rtx_equal_p (operands[0], operands[1]))
    -                ? operands[0] : gen_reg_rtx (<MODE>mode));
    +      rtx tmp = ((!can_create_pseudo_p () || rtx_equal_p (op0, op1))
    +                ? op0
    +                : gen_reg_rtx (<MODE>mode));
    
           /* Adding a constant to r0 is not a valid insn, so use a different
             strategy in that case.  */
    -      if (reg_or_subregno (operands[1]) == 0 || reg_or_subregno (tmp) == 0)
    +      if (reg_or_subregno (op1) == 0 || reg_or_subregno (tmp) == 0)
            {
    -         if (operands[0] == operands[1])
    +         if (op0 == op1)
                FAIL;
    -         rs6000_emit_move (operands[0], operands[2], <MODE>mode);
    -         emit_insn (gen_add<mode>3 (operands[0], operands[1], 
operands[0]));
    +         rs6000_emit_move (op0, op2, <MODE>mode);
    +         emit_insn (gen_add<mode>3 (op0, op1, op0));
    +         DONE;
    +       }
    +
    +      HOST_WIDE_INT val = INTVAL (op2);
    +
    +      /* If we have paddis, split the add into paddis and either addi or
    +        paddi.  However, if we can generate addis and rldicl, do that
    +        instead of doing paddis/paddi.  Emit the paddis first, just
    +        in case this is a memory operation and we could fold the offset
    +        into the memory ooperation.  */
    +
    +      if (TARGET_PADDIS && paddis_paddi_operand (op2, <MODE>mode))
    +       {
    +         const HOST_WIDE_INT mask = HOST_WIDE_INT_C(0xffffffff);
    +
    +         emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (val & ~mask)));
    +         emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (val & mask)));
              DONE;
            }
    
    -      HOST_WIDE_INT val = INTVAL (operands[2]);
           HOST_WIDE_INT low = sext_hwi (val, 16);
           HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode);
    
    @@ -1960,52 +1980,28 @@ (define_expand "add<mode>3"
           /* The ordering here is important for the prolog expander.
             When space is allocated from the stack, adding 'low' first may
             produce a temporary deallocation (which would be bad).  */
    -      emit_insn (gen_add<mode>3 (tmp, operands[1], GEN_INT (rest)));
    -      emit_insn (gen_add<mode>3 (operands[0], tmp, GEN_INT (low)));
    +      emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (rest)));
    +      emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (low)));
           DONE;
         }
     })
    
     (define_insn "*add<mode>3"
    -  [(set (match_operand:GPR 0 "gpc_reg_operand"           "=r,r,r, r, r, b")
    -       (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b, b, b, b")
    -                 (match_operand:GPR 2 "add_operand"      
"r,I,L,eI,eU,eV")))]
    +  [(set (match_operand:GPR 0 "gpc_reg_operand"           "=r,r,r, r, r")
    +       (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b, b, b")
    +                 (match_operand:GPR 2 "add_operand"      "r,I,L,eI,eU")))]
       ""
       "@
        add %0,%1,%2
        addi %0,%1,%2
        addis %0,%1,%v2
        addi %0,%1,%2
    -   paddis %0,%1,%B2
    -   #"
    +   paddis %0,%1,%B2"
       [(set_attr "type" "add")
    -   (set_attr "isa" "*,*,*,p10,paddis,paddis")
    -   (set_attr "length" "*,*,*,*,12,24")
    -   (set_attr "prefixed" "*,*,*,*,yes,yes")
    -   (set_attr "maybe_prefixed" "*,*,*,*,no,no")])
    -
    -;; We can't split r0 + large_number due to encoding issues, so use base
    -;; registers only.
    -
    -(define_split
    -  [(set (match_operand:DI 0 "base_reg_operand")
    -       (plus:DI (match_operand:DI 1 "base_reg_operand")
    -                (match_operand:DI 2 "paddis_paddi_operand")))]
    -  "TARGET_PADDIS"
    -  [(set (match_dup 3)
    -       (plus:DI (match_dup 1)
    -                (match_dup 4)))
    -   (set (match_dup 0)
    -       (plus:DI (match_dup 3)
    -                (match_dup 5)))]
    -{
    -  HOST_WIDE_INT value = INTVAL (operands[2]);
    -  operands[3] = (can_create_pseudo_p ()
    -                ? gen_reg_rtx (DImode)
    -                : operands[0]);
    -  operands[4] = GEN_INT (value & ~HOST_WIDE_INT_C (0xffffffff));
    -  operands[5] = GEN_INT (value & HOST_WIDE_INT_C (0xffffffff));
    -})
    +   (set_attr "isa" "*,*,*,p10,paddis")
    +   (set_attr "length" "*,*,*,*,12")
    +   (set_attr "prefixed" "*,*,*,*,yes")
    +   (set_attr "maybe_prefixed" "*,*,*,*,no")])
    
     (define_insn "*addsi3_high"
       [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
    @@ -10169,11 +10165,12 @@ (define_split
                     (match_dup 4)))]
     {
       HOST_WIDE_INT value = INTVAL (operands[1]);
    +  const HOST_WIDE_INT mask = HOST_WIDE_INT_C (0xffffffff);
       operands[2] = (can_create_pseudo_p ()
                     ? gen_reg_rtx (DImode)
                     : operands[0]);
    -  operands[3] = GEN_INT (value & ~HOST_WIDE_INT_C (0xffffffff));
    -  operands[4] = GEN_INT (value & HOST_WIDE_INT_C (0xffffffff));
    +  operands[3] = GEN_INT (value & ~mask);
    +  operands[4] = GEN_INT (value & mask);
     })
    
     ;; Split a load of a large constant into the appropriate five-instruction
    --
    2.54.0

Diff:
---
 gcc/config/rs6000/predicates.md | 16 ++++---
 gcc/config/rs6000/rs6000.cc     | 12 ++---
 gcc/config/rs6000/rs6000.md     | 99 ++++++++++++++++++++---------------------
 3 files changed, 63 insertions(+), 64 deletions(-)

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 4800cc7fe5ab..841619570c11 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -433,13 +433,16 @@
   if (!SIGNED_INTEGER_64BIT_P (value))
     return false;
 
+  /* Don't worry about negative values at the moment.  */
+  if (value < 0)
+    return false;
+
   /* If paddi alone can handle the number, don't return true.  */
   if (SIGNED_INTEGER_34BIT_P (value))
     return false;
 
   /* If we can do the add or generate the constant via addis/rldicl, fail.  */
-  if (num_insns_constant (op, mode) == 2
-      && rs6000_is_valid_and_mask (op, mode))
+  if (rs6000_is_valid_and_mask (op, mode))
     return false;
 
   /* Only return true if we need both paddi and paddis.  */
@@ -647,14 +650,14 @@
                           + (mode == SImode ? 0x80000000 : 0x80008000))
                        < (unsigned HOST_WIDE_INT) 0x100000000ll")
            (match_operand 0 "cint34_operand")
-           (match_operand 0 "paddis_operand")
-           (match_operand 0 "paddis_paddi_operand"))))
+           (match_operand 0 "paddis_operand"))))
 
 ;; Return 1 if op is a constant integer valid for addition
 ;; or non-special register.
 (define_predicate "reg_or_add_cint_operand"
   (if_then_else (match_code "const_int")
-    (match_operand 0 "add_cint_operand")
+    (ior (match_operand 0 "add_cint_operand")
+        (match_operand 0 "paddis_paddi_operand"))
     (match_operand 0 "gpc_reg_operand")))
 
 ;; Return 1 if op is a constant integer valid for subtraction
@@ -1207,8 +1210,7 @@
     (match_test "satisfies_constraint_I (op)
                 || satisfies_constraint_L (op)
                 || satisfies_constraint_eI (op)
-                || satisfies_constraint_eU (op)
-                || satisfies_constraint_eV (op)")
+                || satisfies_constraint_eU (op)")
     (match_operand 0 "gpc_reg_operand")))
 
 ;; Return 1 if the operand is either a non-special register, or 0, or -1.
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 32cd1de3055b..0e7848315139 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -6245,17 +6245,17 @@ num_insns_constant_gpr (HOST_WIDE_INT value)
     return 1;
 
   /* PADDIS support.  */
-  else if (TARGET_PADDIS && SIGNED_INTEGER_64BIT_P (value))
+  else if (TARGET_PADDIS)
     {
-      if ((value & HOST_WIDE_INT_C(0xffffffff)) == 0)
+      rtx num = GEN_INT (value);
+      if (paddis_operand (num, VOIDmode))
        return 1;       /* paddis alone.  */
 
-      /* Don't do paddi + paddis if we can do addis and rldicl.  */
-      if (!rs6000_is_valid_and_mask (GEN_INT (value), DImode))
-       return 2;       /* paddi + paddis.  */
+      if (paddis_paddi_operand (num, VOIDmode))
+       return 2;       /* paddis + paddi/addi.  */
     }
 
-  else if (TARGET_POWERPC64)
+  if (TARGET_POWERPC64)
     {
       int num_insns = 0;
       rs6000_emit_set_long_const (nullptr, value, &num_insns);
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index edfeca2040d7..f1688ce409be 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -1914,14 +1914,18 @@
                  (match_operand:SDI 2 "reg_or_add_cint_operand")))]
   ""
 {
+  rtx op0 = operands[0];
+  rtx op1 = operands[1];
+  rtx op2 = operands[2];
+
   if (<MODE>mode == DImode && !TARGET_POWERPC64)
     {
-      rtx lo0 = gen_lowpart (SImode, operands[0]);
-      rtx lo1 = gen_lowpart (SImode, operands[1]);
-      rtx lo2 = gen_lowpart (SImode, operands[2]);
-      rtx hi0 = gen_highpart (SImode, operands[0]);
-      rtx hi1 = gen_highpart (SImode, operands[1]);
-      rtx hi2 = gen_highpart_mode (SImode, DImode, operands[2]);
+      rtx lo0 = gen_lowpart (SImode, op0);
+      rtx lo1 = gen_lowpart (SImode, op1);
+      rtx lo2 = gen_lowpart (SImode, op2);
+      rtx hi0 = gen_highpart (SImode, op0);
+      rtx hi1 = gen_highpart (SImode, op1);
+      rtx hi2 = gen_highpart_mode (SImode, DImode, op2);
 
       if (!reg_or_short_operand (lo2, SImode))
        lo2 = force_reg (SImode, lo2);
@@ -1933,24 +1937,40 @@
       DONE;
     }
 
-  if (CONST_INT_P (operands[2]) && !add_operand (operands[2], <MODE>mode))
+  if (CONST_INT_P (op2) && !add_operand (op2, <MODE>mode))
     {
-      rtx tmp = ((!can_create_pseudo_p ()
-                 || rtx_equal_p (operands[0], operands[1]))
-                ? operands[0] : gen_reg_rtx (<MODE>mode));
+      rtx tmp = ((!can_create_pseudo_p () || rtx_equal_p (op0, op1))
+                ? op0
+                : gen_reg_rtx (<MODE>mode));
 
       /* Adding a constant to r0 is not a valid insn, so use a different
         strategy in that case.  */
-      if (reg_or_subregno (operands[1]) == 0 || reg_or_subregno (tmp) == 0)
+      if (reg_or_subregno (op1) == 0 || reg_or_subregno (tmp) == 0)
        {
-         if (operands[0] == operands[1])
+         if (op0 == op1)
            FAIL;
-         rs6000_emit_move (operands[0], operands[2], <MODE>mode);
-         emit_insn (gen_add<mode>3 (operands[0], operands[1], operands[0]));
+         rs6000_emit_move (op0, op2, <MODE>mode);
+         emit_insn (gen_add<mode>3 (op0, op1, op0));
+         DONE;
+       }
+
+      HOST_WIDE_INT val = INTVAL (op2);
+
+      /* If we have paddis, split the add into paddis and either addi or
+        paddi.  However, if we can generate addis and rldicl, do that
+        instead of doing paddis/paddi.  Emit the paddis first, just
+        in case this is a memory operation and we could fold the offset
+        into the memory ooperation.  */
+
+      if (TARGET_PADDIS && paddis_paddi_operand (op2, <MODE>mode))
+       {
+         const HOST_WIDE_INT mask = HOST_WIDE_INT_C(0xffffffff);
+
+         emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (val & ~mask)));
+         emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (val & mask)));
          DONE;
        }
 
-      HOST_WIDE_INT val = INTVAL (operands[2]);
       HOST_WIDE_INT low = sext_hwi (val, 16);
       HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode);
 
@@ -1960,52 +1980,28 @@
       /* The ordering here is important for the prolog expander.
         When space is allocated from the stack, adding 'low' first may
         produce a temporary deallocation (which would be bad).  */
-      emit_insn (gen_add<mode>3 (tmp, operands[1], GEN_INT (rest)));
-      emit_insn (gen_add<mode>3 (operands[0], tmp, GEN_INT (low)));
+      emit_insn (gen_add<mode>3 (tmp, op1, GEN_INT (rest)));
+      emit_insn (gen_add<mode>3 (op0, tmp, GEN_INT (low)));
       DONE;
     }
 })
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "gpc_reg_operand"           "=r,r,r, r, r, b")
-       (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b, b, b, b")
-                 (match_operand:GPR 2 "add_operand"      "r,I,L,eI,eU,eV")))]
+  [(set (match_operand:GPR 0 "gpc_reg_operand"           "=r,r,r, r, r")
+       (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b, b, b")
+                 (match_operand:GPR 2 "add_operand"      "r,I,L,eI,eU")))]
   ""
   "@
    add %0,%1,%2
    addi %0,%1,%2
    addis %0,%1,%v2
    addi %0,%1,%2
-   paddis %0,%1,%B2
-   #"
+   paddis %0,%1,%B2"
   [(set_attr "type" "add")
-   (set_attr "isa" "*,*,*,p10,paddis,paddis")
-   (set_attr "length" "*,*,*,*,12,24")
-   (set_attr "prefixed" "*,*,*,*,yes,yes")
-   (set_attr "maybe_prefixed" "*,*,*,*,no,no")])
-
-;; We can't split r0 + large_number due to encoding issues, so use base
-;; registers only.
-
-(define_split
-  [(set (match_operand:DI 0 "base_reg_operand")
-       (plus:DI (match_operand:DI 1 "base_reg_operand")
-                (match_operand:DI 2 "paddis_paddi_operand")))]
-  "TARGET_PADDIS"
-  [(set (match_dup 3)
-       (plus:DI (match_dup 1)
-                (match_dup 4)))
-   (set (match_dup 0)
-       (plus:DI (match_dup 3)
-                (match_dup 5)))]
-{
-  HOST_WIDE_INT value = INTVAL (operands[2]);
-  operands[3] = (can_create_pseudo_p ()
-                ? gen_reg_rtx (DImode)
-                : operands[0]);
-  operands[4] = GEN_INT (value & ~HOST_WIDE_INT_C (0xffffffff));
-  operands[5] = GEN_INT (value & HOST_WIDE_INT_C (0xffffffff));
-})
+   (set_attr "isa" "*,*,*,p10,paddis")
+   (set_attr "length" "*,*,*,*,12")
+   (set_attr "prefixed" "*,*,*,*,yes")
+   (set_attr "maybe_prefixed" "*,*,*,*,no")])
 
 (define_insn "*addsi3_high"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=b")
@@ -10169,11 +10165,12 @@
                 (match_dup 4)))]
 {
   HOST_WIDE_INT value = INTVAL (operands[1]);
+  const HOST_WIDE_INT mask = HOST_WIDE_INT_C (0xffffffff);
   operands[2] = (can_create_pseudo_p ()
                 ? gen_reg_rtx (DImode)
                 : operands[0]);
-  operands[3] = GEN_INT (value & ~HOST_WIDE_INT_C (0xffffffff));
-  operands[4] = GEN_INT (value & HOST_WIDE_INT_C (0xffffffff));
+  operands[3] = GEN_INT (value & ~mask);
+  operands[4] = GEN_INT (value & mask);
 })
 
 ;; Split a load of a large constant into the appropriate five-instruction

Reply via email to