[gcc(refs/users/meissner/heads/work256-dmf)] Add paddis support.

Michael Meissner via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:016c9aa134c8efdf2c4e9291e0b080a84c9e0abc

commit 016c9aa134c8efdf2c4e9291e0b080a84c9e0abc
Author: Michael Meissner <[email protected]>
Date:   Fri Aug 7 15:50:17 2026 -0400

    Add paddis support.
    
    This patch adds support for the paddis instruction that might be added to a
    future PowerPC processor.
    
    I have committed all of the patches in my backlog (dense math registers, other
    -mcpu=future instructions, random bug fixes, support for _Float16 and
    __bfloat16, and optimizations for vector logical operations on power10/power11)
    into the IBM vendor branch:
    
            vendors/ibm/gcc-17-future
    
    2026-08-03  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.
            (reg_or_add_cint_operand): Add support for adds that can be done with
            paddis and paddi/addi.
            (add_operand): Add support for adds that can be done with paddis, but
            not paddis + paddi/addi..
            * config/rs6000/rs6000.cc (num_insns_constant_gpr): Add support for adds
            that can be done with paddis and also paddis combined with paddi/addi.
            (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 (add<mode>3 define_expand): Add paddis
            support.
            (*add<mode>3 define_insn): Likewise.
            (movdi_internal64): Likewise.
            (movdi splitter): New splitter for paddis + paddi/addi.
            * doc/md.texi (PowerPC constraints): Add eU and eV documentation.
    
    gcc/testsuite/
    
            * gcc.target/powerpc/prefixed-addis.c: New test.

Diff:
---
 gcc/config/rs6000/constraints.md                  |  10 ++
 gcc/config/rs6000/predicates.md                   |  79 ++++++++++++-
 gcc/config/rs6000/rs6000-string.cc                |   1 +
 gcc/config/rs6000/rs6000.cc                       |  21 +++-
 gcc/config/rs6000/rs6000.h                        |  12 ++
 gcc/config/rs6000/rs6000.md                       | 129 +++++++++++++++++-----
 gcc/config/rs6000/vsx.md                          | 122 ++++++++++++++++----
 gcc/doc/md.texi                                   |   6 +
 gcc/testsuite/gcc.target/powerpc/lxvrl.c          |  32 ++++++
 gcc/testsuite/gcc.target/powerpc/prefixed-addis.c |  24 ++++
 10 files changed, 379 insertions(+), 57 deletions(-)

diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md
index 4b2e703f0497..7a21815675a3 100644
--- a/gcc/config/rs6000/constraints.md
+++ b/gcc/config/rs6000/constraints.md
@@ -223,6 +223,16 @@
   "An IEEE 128-bit constant that can be loaded into VSX registers."
   (match_operand 0 "easy_vector_constant_ieee128"))
 
+(define_constraint "eU"
+  "@internal integer constant that can be loaded with paddis"
+  (and (match_code "const_int")
+       (match_operand 0 "paddis_operand")))
+
+(define_constraint "eV"
+  "@A signed integer constant that paddis and paddi instructions generate."
+  (and (match_code "const_int")
+       (match_operand 0 "paddis_paddi_operand")))
+
 ;; Floating-point constraints.  These two are defined so that insn
 ;; length attributes can be calculated exactly.
 
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index a6ec04f5922d..b7a0b25921c2 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -376,6 +376,68 @@
   return SIGNED_INTEGER_34BIT_P (INTVAL (op));
 })
 
+;; Return 1 if op is a 64-bit constant that uses the paddis instruction
+(define_predicate "paddis_operand"
+  (match_code "const_int")
+{
+  if (!TARGET_PADDIS)
+    return false;
+
+  if (mode != VOIDmode && mode != DImode)
+    return false;
+
+  HOST_WIDE_INT value = INTVAL (op);
+
+  if (!SIGNED_INTEGER_64BIT_P (value))
+    return false;
+
+  /* If paddi alone can handle the number, don't return true.  */
+  if (SIGNED_INTEGER_34BIT_P (value))
+    return false;
+
+  /* If the bottom 32-bits are non-zero, paddis alone can't handle it.  */
+  if ((value & HOST_WIDE_INT_C(0xffffffff)) != 0)
+    return false;
+
+  return true;
+})
+
+;; Return 1 if op is a 64-bit constant that can be created with a
+;; combination of paddi and paddis.  Don't generate paddi and paddis if
+;; we can do it via addis and rldicl.
+(define_predicate "paddis_paddi_operand"
+  (match_code "const_int")
+{
+  if (!TARGET_PADDIS)
+    return false;
+
+  if (mode != VOIDmode && mode != DImode)
+    return false;
+
+  HOST_WIDE_INT value = INTVAL (op);
+
+  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 (rs6000_is_valid_and_mask (op, mode))
+    return false;
+
+  /* Only return true if we need both paddi and paddis.  */
+  if ((value & HOST_WIDE_INT_C(0xffffffff)) == 0)
+    return false;
+
+  return true;
+})
+
 ;; Return 1 if op is a register that is not special.
 ;; Disallow (SUBREG:SF (REG:SI)) and (SUBREG:SI (REG:SF)) on VSX systems where
 ;; you need to be careful in moving a SFmode to SImode and vice versa due to
@@ -569,18 +631,22 @@
   (ior (match_operand 0 "zero_constant")
        (match_operand 0 "gpc_reg_operand")))
 
-;; Return 1 if op is a constant integer valid for addition with addis, addi.
+;; Return 1 if op is a constant integer valid for addition with addis,
+;; addi, paddi, or paddis.
 (define_predicate "add_cint_operand"
   (and (match_code "const_int")
-       (match_test "((unsigned HOST_WIDE_INT) INTVAL (op)
-		       + (mode == SImode ? 0x80000000 : 0x80008000))
-		    < (unsigned HOST_WIDE_INT) 0x100000000ll")))
+       (ior (match_test "((unsigned HOST_WIDE_INT) INTVAL (op)
+			   + (mode == SImode ? 0x80000000 : 0x80008000))
+		    	< (unsigned HOST_WIDE_INT) 0x100000000ll")
+	    (match_operand 0 "cint34_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
@@ -1123,7 +1189,8 @@
   (if_then_else (match_code "const_int")
     (match_test "satisfies_constraint_I (op)
 		 || satisfies_constraint_L (op)
-		 || satisfies_constraint_eI (op)")
+		 || satisfies_constraint_eI (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-string.cc b/gcc/config/rs6000/rs6000-string.cc
index 062ff1e2465e..0c14ba4cc3ea 100644
--- a/gcc/config/rs6000/rs6000-string.cc
+++ b/gcc/config/rs6000/rs6000-string.cc
@@ -2786,6 +2786,7 @@ expand_block_move (rtx operands[], bool might_overlap)
 
       if (TARGET_MMA && TARGET_BLOCK_OPS_UNALIGNED_VSX
 	  && TARGET_BLOCK_OPS_VECTOR_PAIR
+	  && TARGET_POWERPC64
 	  && bytes >= 32
 	  && (align >= 256 || !STRICT_ALIGNMENT))
 	{
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 995559889130..792bb6f5bfaa 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -6146,7 +6146,18 @@ num_insns_constant_gpr (HOST_WIDE_INT value)
   else if (TARGET_PREFIXED && SIGNED_INTEGER_34BIT_P (value))
     return 1;
 
-  else if (TARGET_POWERPC64)
+  /* PADDIS support.  */
+  else if (TARGET_PADDIS)
+    {
+      rtx num = GEN_INT (value);
+      if (paddis_operand (num, VOIDmode))
+	return 1;	/* paddis alone.  */
+
+      if (paddis_paddi_operand (num, VOIDmode))
+	return 2;	/* paddis + paddi/addi.  */
+    }
+
+  if (TARGET_POWERPC64)
     {
       int num_insns = 0;
       rs6000_emit_set_long_const (nullptr, value, &num_insns);
@@ -14277,6 +14288,14 @@ print_operand (FILE *file, rtx x, int code)
 	fprintf (file, "%d", (REGNO (x) - FIRST_FPR_REGNO) / 4);
       return;
 
+    case 'B':
+      /* Upper 32-bits of a constant.  */
+      if (!CONST_INT_P (x))
+	output_operand_lossage ("Not a constant.");
+
+      fprintf (file, "%" HOST_LONG_FORMAT "d", INTVAL (x) >> 32);
+      return;
+
     case 'D':
       /* Like 'J' but get to the GT bit only.  */
       if (!REG_P (x) || !CR_REGNO_P (REGNO (x)))
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 4c268b8bb9b3..b4ec566e5933 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -568,6 +568,11 @@ extern int rs6000_vector_align[];
 /* Whether we have XVRLW support.  */
 #define TARGET_XVRLW			TARGET_FUTURE
 
+/* Whether we have PADDIS support.  */
+#define TARGET_PADDIS			(TARGET_FUTURE			\
+					 && TARGET_PREFIXED		\
+					 && TARGET_POWERPC64)
+
 /* Whether the various reciprocal divide/square root estimate instructions
    exist, and whether we should automatically generate code for the instruction
    by default.  */
@@ -2489,6 +2494,13 @@ typedef struct GTY(()) machine_function
 #define SIGNED_INTEGER_16BIT_P(VALUE)	SIGNED_INTEGER_NBIT_P (VALUE, 16)
 #define SIGNED_INTEGER_34BIT_P(VALUE)	SIGNED_INTEGER_NBIT_P (VALUE, 34)
 
+#if HOST_BITS_PER_WIDE_INT > 64
+#define SIGNED_INTEGER_64BIT_P(VALUE)	SIGNED_INTEGER_NBIT_P (VALUE, 64)
+
+#else
+#define SIGNED_INTEGER_64BIT_P(VALUE)	1
+#endif
+
 /* Like SIGNED_INTEGER_16BIT_P and SIGNED_INTEGER_34BIT_P, but with an extra
    argument that gives a length to validate a range of addresses, to allow for
    splitting insns into several insns, each of which has an offsettable
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 6c435c08b4e0..39792d0c0625 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -435,6 +435,7 @@
      (and (eq_attr "isa" "dmf")
 	  (match_test "TARGET_DMF"))
      (const_int 1)
+
     ] (const_int 0)))
 
 ;; If this instruction is microcoded on the CELL processor
@@ -1873,14 +1874,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);
@@ -1892,24 +1897,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);
 
@@ -1919,24 +1940,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")
-	(plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b,b")
-		  (match_operand:GPR 2 "add_operand" "r,I,L,eI")))]
+  [(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"
+   addi %0,%1,%2
+   paddis %0,%1,%B2"
   [(set_attr "type" "add")
-   (set_attr "isa" "*,*,*,p10")])
+   (set_attr "isa" "*,*,*,p10,future")
+   (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")
@@ -9959,7 +9984,7 @@
   DONE;
 })
 
-;;	   GPR store   GPR load    GPR move
+;;	   GPR store   GPR load    GPR move    GPR paddis   GPR paddis+paddi
 ;;	   GPR li      GPR lis     GPR pli     GPR #
 ;;	   FPR store   FPR load    FPR move
 ;;	   AVX store   AVX store   AVX load    AVX load    VSX move
@@ -9969,7 +9994,7 @@
 ;;	   VSX->GPR    GPR->VSX
 (define_insn "*movdi_internal64"
   [(set (match_operand:DI 0 "nonimmediate_operand"
-	  "=YZ,        r,          r,
+	  "=YZ,        r,          r,          r,          b,
 	   r,          r,          r,          r,
 	   m,          ^d,         ^d,
 	   wY,         Z,          $v,         $v,         ^wa,
@@ -9978,7 +10003,7 @@
 	   r,          *h,         *h,
 	   ?r,         ?wa")
 	(match_operand:DI 1 "input_operand"
-	  "r,          YZ,         r,
+	  "r,          YZ,         r,          eU,         eV,
 	   I,          L,          eI,         nF,
 	   ^d,         m,          ^d,
 	   ^v,         $v,         wY,         Z,          ^wa,
@@ -9993,6 +10018,8 @@
    std%U0%X0 %1,%0
    ld%U1%X1 %0,%1
    mr %0,%1
+   paddis %0,0,%B1
+   #
    li %0,%1
    lis %0,%v1
    li %0,%1
@@ -10018,7 +10045,7 @@
    mfvsrd %0,%x1
    mtvsrd %x0,%1"
   [(set_attr "type"
-	  "store,      load,       *,
+	  "store,      load,       *,          *,          *,
 	   *,          *,          *,          *,
 	   fpstore,    fpload,     fpsimple,
 	   fpstore,    fpstore,    fpload,     fpload,     veclogical,
@@ -10028,7 +10055,7 @@
 	   mfvsr,      mtvsr")
    (set_attr "size" "64")
    (set_attr "length"
-	  "*,          *,          *,
+	  "*,          *,          *,          12,         24,
 	   *,          *,          *,          20,
 	   *,          *,          *,
 	   *,          *,          *,          *,          *,
@@ -10037,14 +10064,32 @@
 	   *,          *,          *,
 	   *,          *")
    (set_attr "isa"
-	  "*,          *,          *,
+	  "*,          *,          *,          future,     future,
 	   *,          *,          p10,        *,
 	   *,          *,          *,
 	   p9v,        p7v,        p9v,        p7v,        *,
 	   p9v,        p9v,        p7v,        *,          *,
 	   p7v,        p7v,
 	   *,          *,          *,
-	   p8v,        p8v")])
+	   p8v,        p8v")
+   (set_attr "prefixed"
+	  "*,          *,          *,          yes,        yes,
+	   *,          *,          *,          *,
+	   *,          *,          *,
+	   *,          *,          *,          *,          *,
+	   *,          *,          *,          *,          *,
+	   *,          *,
+	   *,          *,          *,
+	   *,          *")
+   (set_attr "maybe_prefixed"
+	  "*,          *,          *,          no,         no,
+	   *,          *,          *,          *,
+	   *,          *,          *,
+	   *,          *,          *,          *,          *,
+	   *,          *,          *,          *,          *,
+	   *,          *,
+	   *,          *,          *,
+	   *,          *")])
 
 ; Some DImode loads are best done as a load of -1 followed by a mask
 ; instruction.
@@ -10062,6 +10107,32 @@
 		(match_dup 1)))]
   "")
 
+;; Split a constant that can be generated by a paddis and paddi into 2
+;; instructions.  We can't split setting r0 since that would generate:
+;;	paddis r0,0,upper
+;;	paddi  r0,r0,lower
+;;
+;; which gives the wrong value.
+
+(define_split
+  [(set (match_operand:DI 0 "base_reg_operand")
+	(match_operand:DI 1 "paddis_paddi_operand"))]
+  "TARGET_PADDIS"
+  [(set (match_dup 2)
+	(match_dup 3))
+   (set (match_dup 0)
+	(plus:DI (match_dup 2)
+		 (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 & ~mask);
+  operands[4] = GEN_INT (value & mask);
+})
+
 ;; Split a load of a large constant into the appropriate five-instruction
 ;; sequence.  Handle anything in a constant number of insns.
 ;; When non-easy constants can go in the TOC, this should use
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index 58318f5bb5e2..599b44fd6243 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -5761,20 +5761,32 @@
   DONE;
 })
 
-;; Load VSX Vector with Length
+;; Load VSX Vector with Length.  If we have lxvrl, we don't have to do an
+;; explicit shift left into a pseudo.
 (define_expand "lxvl"
-  [(set (match_dup 3)
-        (ashift:DI (match_operand:DI 2 "register_operand")
-                   (const_int 56)))
-   (set (match_operand:V16QI 0 "vsx_register_operand")
-	(unspec:V16QI
-	 [(match_operand:DI 1 "gpc_reg_operand")
-          (mem:V16QI (match_dup 1))
-	  (match_dup 3)]
-	 UNSPEC_LXVL))]
+  [(use (match_operand:V16QI 0 "vsx_register_operand"))
+   (use (match_operand:DI 1 "gpc_reg_operand"))
+   (use (match_operand:DI 2 "gpc_reg_operand"))]
   "TARGET_P9_VECTOR && TARGET_64BIT"
 {
-  operands[3] = gen_reg_rtx (DImode);
+  rtx shift_len = gen_rtx_ASHIFT (DImode, operands[2], GEN_INT (56));
+  rtx len;
+
+  if (TARGET_FUTURE)
+    len = shift_len;
+  else
+    {
+      len = gen_reg_rtx (DImode);
+      emit_insn (gen_rtx_SET (len, shift_len));
+    }
+
+  rtx dest = operands[0];
+  rtx addr = operands[1];
+  rtx mem = gen_rtx_MEM (V16QImode, addr);
+  rtvec rv = gen_rtvec (3, addr, mem, len);
+  rtx lxvl = gen_rtx_UNSPEC (V16QImode, rv, UNSPEC_LXVL);
+  emit_insn (gen_rtx_SET (dest, lxvl));
+  DONE;
 })
 
 (define_insn "*lxvl"
@@ -5798,6 +5810,34 @@
   "lxvll %x0,%1,%2"
   [(set_attr "type" "vecload")])
 
+;; For lxvrl and lxvrll, use the combiner to eliminate the shift.  The
+;; define_expand for lxvl will already incorporate the shift in generating the
+;; insn.  The lxvll buitl-in function required the user to have already done
+;; the shift.  Defining lxvrll this way, will optimize cases where the user has
+;; done the shift immediately before the built-in.
+(define_insn "*lxvrl"
+  [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa")
+	(unspec:V16QI
+	 [(match_operand:DI 1 "gpc_reg_operand" "b")
+	  (mem:V16QI (match_dup 1))
+	  (ashift:DI (match_operand:DI 2 "register_operand" "r")
+		     (const_int 56))]
+	 UNSPEC_LXVL))]
+  "TARGET_FUTURE && TARGET_64BIT"
+  "lxvrl %x0,%1,%2"
+  [(set_attr "type" "vecload")])
+
+(define_insn "*lxvrll"
+  [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa")
+	(unspec:V16QI [(match_operand:DI 1 "gpc_reg_operand" "b")
+                       (mem:V16QI (match_dup 1))
+		       (ashift:DI (match_operand:DI 2 "register_operand" "r")
+				  (const_int 56))]
+		      UNSPEC_LXVLL))]
+  "TARGET_FUTURE"
+  "lxvrll %x0,%1,%2"
+  [(set_attr "type" "vecload")])
+
 ;; Expand for builtin xl_len_r
 (define_expand "xl_len_r"
   [(match_operand:V16QI 0 "vsx_register_operand")
@@ -5829,18 +5869,29 @@
 
 ;; Store VSX Vector with Length
 (define_expand "stxvl"
-  [(set (match_dup 3)
-	(ashift:DI (match_operand:DI 2 "register_operand")
-		   (const_int 56)))
-   (set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand"))
-	(unspec:V16QI
-	 [(match_operand:V16QI 0 "vsx_register_operand")
-	  (mem:V16QI (match_dup 1))
-	  (match_dup 3)]
-	 UNSPEC_STXVL))]
+  [(use (match_operand:V16QI 0 "vsx_register_operand"))
+   (use (match_operand:DI 1 "gpc_reg_operand"))
+   (use (match_operand:DI 2 "gpc_reg_operand"))]
   "TARGET_P9_VECTOR && TARGET_64BIT"
 {
-  operands[3] = gen_reg_rtx (DImode);
+  rtx shift_len = gen_rtx_ASHIFT (DImode, operands[2], GEN_INT (56));
+  rtx len;
+
+  if (TARGET_FUTURE)
+    len = shift_len;
+  else
+    {
+      len = gen_reg_rtx (DImode);
+      emit_insn (gen_rtx_SET (len, shift_len));
+    }
+
+  rtx src = operands[0];
+  rtx addr = operands[1];
+  rtx mem = gen_rtx_MEM (V16QImode, addr);
+  rtvec rv = gen_rtvec (3, src, mem, len);
+  rtx stxvl = gen_rtx_UNSPEC (V16QImode, rv, UNSPEC_STXVL);
+  emit_insn (gen_rtx_SET (mem, stxvl));
+  DONE;
 })
 
 ;; Define optab for vector access with length vectorization exploitation.
@@ -5885,6 +5936,35 @@
   "stxvl %x0,%1,%2"
   [(set_attr "type" "vecstore")])
 
+;; For stxvrl and stxvrll, use the combiner to eliminate the shift.  The
+;; define_expand for stxvl will already incorporate the shift in generating the
+;; insn.  The stxvll buitl-in function required the user to have already done
+;; the shift.  Defining stxvrll this way, will optimize cases where the user
+;; has done the shift immediately before the built-in.
+
+(define_insn "*stxvrl"
+  [(set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand" "b"))
+	(unspec:V16QI
+	 [(match_operand:V16QI 0 "vsx_register_operand" "wa")
+	  (mem:V16QI (match_dup 1))
+	  (ashift:DI (match_operand:DI 2 "register_operand" "r")
+		     (const_int 56))]
+	 UNSPEC_STXVL))]
+  "TARGET_FUTURE && TARGET_64BIT"
+  "stxvrl %x0,%1,%2"
+  [(set_attr "type" "vecstore")])
+
+(define_insn "*stxvrll"
+  [(set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand" "b"))
+	(unspec:V16QI [(match_operand:V16QI 0 "vsx_register_operand" "wa")
+		       (mem:V16QI (match_dup 1))
+		       (ashift:DI (match_operand:DI 2 "register_operand" "r")
+				  (const_int 56))]
+	              UNSPEC_STXVLL))]
+  "TARGET_FUTURE"
+  "stxvrll %x0,%1,%2"
+  [(set_attr "type" "vecstore")])
+
 ;; Expand for builtin xst_len_r
 (define_expand "xst_len_r"
   [(match_operand:V16QI 0 "vsx_register_operand" "=wa")
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index c0026c173182..368c409b3ac7 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -3367,6 +3367,12 @@ loaded to a VSX register with one prefixed instruction.
 An IEEE 128-bit constant that can be loaded into a VSX register with
 the @code{lxvkq} instruction.
 
+@item eU
+A signed integer constant that can be used with the paddis instruction.
+
+@item eV
+A signed integer constant that paddis and paddi instructions generate.
+
 @ifset INTERNALS
 @item G
 A floating point constant that can be loaded into a register with one
diff --git a/gcc/testsuite/gcc.target/powerpc/lxvrl.c b/gcc/testsuite/gcc.target/powerpc/lxvrl.c
new file mode 100644
index 000000000000..71854c50c911
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/lxvrl.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_future_ok } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+
+/* Test whether the lxvrl and stxvrl instructions are generated for
+   -mcpu=future on memory copy operations.  */
+
+#ifndef VSIZE
+#define VSIZE 2
+#endif
+
+#ifndef LSIZE
+#define LSIZE 5
+#endif
+
+struct foo {
+  vector unsigned char vc[VSIZE];
+  unsigned char leftover[LSIZE];
+};
+
+void memcpy_ptr (struct foo *p, struct foo *q)
+{
+  __builtin_memcpy ((void *) p,		/* lxvrl and stxvrl.  */
+		    (void *) q,
+		    (sizeof (vector unsigned char) * VSIZE) + LSIZE);
+}
+
+/* { dg-final { scan-assembler     {\mlxvrl\M}  } } */
+/* { dg-final { scan-assembler     {\mstxvrl\M} } } */
+/* { dg-final { scan-assembler-not {\mlxvl\M}   } } */
+/* { dg-final { scan-assembler-not {\mstxvl\M}  } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/prefixed-addis.c b/gcc/testsuite/gcc.target/powerpc/prefixed-addis.c
new file mode 100644
index 000000000000..d08e3675f94c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/prefixed-addis.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_future_ok } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-options "-mdejagnu-cpu=future -O2" } */
+
+/* Test whether the xvrl (vector word rotate left using VSX registers insead of
+   Altivec registers is generated.  */
+
+#include <stddef.h>
+
+size_t
+prefix_addis_addi (size_t x)
+{
+  return x + 0x123456789ABCDEUL;	/* paddis + paddi.  */
+}
+
+size_t
+prefix_addis (size_t x)
+{
+  return x + 0x12345600000000UL;	/* paddis.  */
+}
+
+/* { dg-final { scan-assembler-times {\mpaddis\M} 2  } } */
+/* { dg-final { scan-assembler-times {\mpaddi\M}  1  } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.