predicates.md (quad_memory_operand): Move most of the code into quad_address_p and...
authorMichael Meissner <meissner@linux.vnet.ibm.com>
Wed, 11 May 2016 18:38:10 +0000 (18:38 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Wed, 11 May 2016 18:38:10 +0000 (18:38 +0000)
[gcc]
2016-05-11  Michael Meissner  <meissner@linux.vnet.ibm.com>

* config/rs6000/predicates.md (quad_memory_operand): Move most of
the code into quad_address_p and call it to share code with
vsx_quad_dform_memory_operand.
(vsx_quad_dform_memory_operand): New predicate for ISA 3.0 vector
d-form support.
* config/rs6000/rs6000.opt (-mlra): Switch to being an option mask
bit instead of being a separate word.  Split -mpower9-dform into
two switches, -mpower9-dform-scalar and -mpower9-dform-vector.
* config/rs6000/rs6000.c (RELOAD_REG_QUAD_OFFSET): New addr_mask
for the register class supporting 128-bit quad word memory
offsets.
(mode_supports_vsx_dform_quad): Helper function to return if the
register class uses quad word memory offsets.
(rs6000_debug_addr_mask): Add support for quad word memory
offsets.
(rs6000_debug_reg_global): Always print if we are using LRA or
not.
(rs6000_setup_reg_addr_masks): If ISA 3.0 vector d-form
instructions are enabled, set up the appropriate addr_masks for
128-bit types.
(rs6000_init_hard_regno_mode_ok): wb constraint is now based on
-mpower9-dform-scalar, instead of -mpower9-dform.
(rs6000_option_override_internal): Split -mpower9-dform into two
switches, -mpower9-dform-scalar and -mpower9-dform-vector.  The
-mpower9-dform switch sets or clears both.  If we are not using
the LRA register allocator, do not enable -mpower9-dform-vector by
default.  If we are using LRA, enable -mpower9-dform-vector and
-mvsx-timode if it is appropriate.  Issue a warning if either
-mpower9-dform-vector or -mvsx-timode are explicitly used without
enabling LRA.
(quad_address_offset_p): New helper function to return if the
offset is legal for quad word memory instructions.
(quad_address_p): New function to determin if GPR or vector
register quad word memory addresses are legal.
(mem_operand_gpr): Validate quad word address offsets.
(reg_offset_addressing_ok_p): Add support for ISA 3.0 vector
d-form (register + offset) instructions.
(offsettable_ok_by_alignment): Likewise.
(rs6000_legitimate_offset_address_p): Likewise.
(legitimate_lo_sum_address_p): Likewise.
(rs6000_legitimize_address): Likewise.
(rs6000_legitimize_reload_address): Add more debug statements for
-mdebug=addr.
(rs6000_legitimate_address_p): Add support for ISA 3.0 vector
d-form instructions.
(rs6000_secondary_reload_memory): Add support for ISA 3.0 vector
d-form instructions.  Distinguish different cases in debug
output. (rs6000_secondary_reload_inner): Add support for ISA 3.0 vector
d-form instructions.
(rs6000_preferred_reload_class): Likewise.
(rs6000_output_move_128bit): Add support for ISA 3.0 d-form
instructions.  If ISA 3.0 is available, generate lxvx/stxvx instead
of the ISA 2.06 indexed memory instructions.
(rs6000_emit_prologue): If we have ISA 3.0 d-form instructions,
use them to save/restore the saved vector registers instead of
using Altivec instructions.
(rs6000_emit_epilogue): Likewise.
(rs6000_lra_p): Use TARGET_LRA instead of the old option word.
(rs6000_opt_masks): Split -mpower9-dform into
-mpower9-dform-scalar and -mpower9-dform-vector.
(rs6000_print_options_internal): Print -mno-<switch> if <switch>
was not selected.
* config/rs6000/vsx.md (p9_vecload_<mode>): Delete hack to emit
ISA 3.0 vector indexed memory instructions, and fold the code into
the normal mov<mode> patterns.
(p9_vecstore_<mode>): Likewise.
(vsx_mov<mode>): Add support for ISA 3.0 vector d-form
instructions.
(vsx_movti_64bit): Likewise.
(vsx_movti_32bit): Likewise.
* config/rs6000/constraints.md (wO constraint): New constraint for
ISA 3.0 vector d-form support.
* config/rs6000/rs6000-cpus.def (ISA_3_0_MASKS_SERVER): Use
-mpower9-dform-scalar instead of -mpower9-dform.  Add note not to
include -mpower9-dform-vector until we switch over to LRA.
(POWERPC_MASKS): Add -mlra. Split -mpower9-dform into two.
switches, -mpower9-dform-scalar and -mpower9-dform-vector.
* config/rs6000/rs6000-protos.h (quad_address_p): Add declaration.
* doc/invoke.texi (RS/6000 and PowerPC Options): Add documentation
for -mpower9-dform and -mlra.
* doc/md.texi (wO constraint): Document wO constraint.

[gcc/testsuite]
2016-05-11  Michael Meissner  <meissner@linux.vnet.ibm.com>

* gcc.target/powerpc/dform-3.c: New test for ISA 3.0 vector d-form
support.
* gcc.target/powerpc/dform-1.c: Add -mlra option to silence
warning when using -mvsx-timode.
* gcc.target/powerpc/p8vector-int128-1.c: Likewise.
* gcc.target/powerpc/dform-2.c: Likewise.
* gcc.target/powerpc/pr68805.c: Likewise.

From-SVN: r236133

16 files changed:
gcc/ChangeLog
gcc/config/rs6000/constraints.md
gcc/config/rs6000/predicates.md
gcc/config/rs6000/rs6000-cpus.def
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.opt
gcc/config/rs6000/vsx.md
gcc/doc/invoke.texi
gcc/doc/md.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/dform-1.c
gcc/testsuite/gcc.target/powerpc/dform-2.c
gcc/testsuite/gcc.target/powerpc/dform-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/p8vector-int128-1.c
gcc/testsuite/gcc.target/powerpc/pr68805.c

index be9cf29f9fd02ab3944d08aafe1c5e6f9f545a4a..88f92359955e81248170e29ce8b66028c17dde2f 100644 (file)
@@ -1,3 +1,87 @@
+2016-05-11  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * config/rs6000/predicates.md (quad_memory_operand): Move most of
+       the code into quad_address_p and call it to share code with
+       vsx_quad_dform_memory_operand.
+       (vsx_quad_dform_memory_operand): New predicate for ISA 3.0 vector
+       d-form support.
+       * config/rs6000/rs6000.opt (-mlra): Switch to being an option mask
+       bit instead of being a separate word.  Split -mpower9-dform into
+       two switches, -mpower9-dform-scalar and -mpower9-dform-vector.
+       * config/rs6000/rs6000.c (RELOAD_REG_QUAD_OFFSET): New addr_mask
+       for the register class supporting 128-bit quad word memory
+       offsets.
+       (mode_supports_vsx_dform_quad): Helper function to return if the
+       register class uses quad word memory offsets.
+       (rs6000_debug_addr_mask): Add support for quad word memory
+       offsets.
+       (rs6000_debug_reg_global): Always print if we are using LRA or
+       not.
+       (rs6000_setup_reg_addr_masks): If ISA 3.0 vector d-form
+       instructions are enabled, set up the appropriate addr_masks for
+       128-bit types.
+       (rs6000_init_hard_regno_mode_ok): wb constraint is now based on
+       -mpower9-dform-scalar, instead of -mpower9-dform.
+       (rs6000_option_override_internal): Split -mpower9-dform into two
+       switches, -mpower9-dform-scalar and -mpower9-dform-vector.  The
+       -mpower9-dform switch sets or clears both.  If we are not using
+       the LRA register allocator, do not enable -mpower9-dform-vector by
+       default.  If we are using LRA, enable -mpower9-dform-vector and
+       -mvsx-timode if it is appropriate.  Issue a warning if either
+       -mpower9-dform-vector or -mvsx-timode are explicitly used without
+       enabling LRA.
+       (quad_address_offset_p): New helper function to return if the
+       offset is legal for quad word memory instructions.
+       (quad_address_p): New function to determin if GPR or vector
+       register quad word memory addresses are legal.
+       (mem_operand_gpr): Validate quad word address offsets.
+       (reg_offset_addressing_ok_p): Add support for ISA 3.0 vector
+       d-form (register + offset) instructions.
+       (offsettable_ok_by_alignment): Likewise.
+       (rs6000_legitimate_offset_address_p): Likewise.
+       (legitimate_lo_sum_address_p): Likewise.
+       (rs6000_legitimize_address): Likewise.
+       (rs6000_legitimize_reload_address): Add more debug statements for
+       -mdebug=addr.
+       (rs6000_legitimate_address_p): Add support for ISA 3.0 vector
+       d-form instructions.
+       (rs6000_secondary_reload_memory): Add support for ISA 3.0 vector
+       d-form instructions.  Distinguish different cases in debug
+       output. (rs6000_secondary_reload_inner): Add support for ISA 3.0 vector
+       d-form instructions.
+       (rs6000_preferred_reload_class): Likewise.
+       (rs6000_output_move_128bit): Add support for ISA 3.0 d-form
+       instructions.  If ISA 3.0 is available, generate lxvx/stxvx instead
+       of the ISA 2.06 indexed memory instructions.
+       (rs6000_emit_prologue): If we have ISA 3.0 d-form instructions,
+       use them to save/restore the saved vector registers instead of
+       using Altivec instructions.
+       (rs6000_emit_epilogue): Likewise.
+       (rs6000_lra_p): Use TARGET_LRA instead of the old option word.
+       (rs6000_opt_masks): Split -mpower9-dform into
+       -mpower9-dform-scalar and -mpower9-dform-vector.
+       (rs6000_print_options_internal): Print -mno-<switch> if <switch>
+       was not selected.
+       * config/rs6000/vsx.md (p9_vecload_<mode>): Delete hack to emit
+       ISA 3.0 vector indexed memory instructions, and fold the code into
+       the normal mov<mode> patterns.
+       (p9_vecstore_<mode>): Likewise.
+       (vsx_mov<mode>): Add support for ISA 3.0 vector d-form
+       instructions.
+       (vsx_movti_64bit): Likewise.
+       (vsx_movti_32bit): Likewise.
+       * config/rs6000/constraints.md (wO constraint): New constraint for
+       ISA 3.0 vector d-form support.
+       * config/rs6000/rs6000-cpus.def (ISA_3_0_MASKS_SERVER): Use
+       -mpower9-dform-scalar instead of -mpower9-dform.  Add note not to
+       include -mpower9-dform-vector until we switch over to LRA.
+       (POWERPC_MASKS): Add -mlra. Split -mpower9-dform into two. 
+       switches, -mpower9-dform-scalar and -mpower9-dform-vector.
+       * config/rs6000/rs6000-protos.h (quad_address_p): Add declaration.
+       * doc/invoke.texi (RS/6000 and PowerPC Options): Add documentation
+       for -mpower9-dform and -mlra.
+       * doc/md.texi (wO constraint): Document wO constraint.
+
 2016-05-11  Alexander Monakov  <amonakov@ispras.ru>
 
        * genattr.c (main): Change 'rtx' to 'rtx_insn *' in prototypes of
index ea15764e513c929fa41c809864be70fbb406d18e..a3abe6ab80a762a5c73aaff21322d242be3b591b 100644 (file)
        (and (match_test "TARGET_DIRECT_MOVE_128")
            (match_test "(ival == VECTOR_ELEMENT_MFVSRLD_64BIT)"))))
 
+;; ISA 3.0 vector d-form addresses
+(define_memory_constraint "wO"
+  "Memory operand suitable for the ISA 3.0 vector d-form instructions."
+  (match_operand 0 "vsx_quad_dform_memory_operand"))
+
 ;; Lq/stq validates the address for load/store quad
 (define_memory_constraint "wQ"
   "Memory operand suitable for the load/store quad instructions"
index 3b40e3ad9538f9d92ec234b361048c946faec432..ebc924673445c13cfba3cef64c1694149dce8a2b 100644 (file)
 (define_predicate "quad_memory_operand"
   (match_code "mem")
 {
-  rtx addr, op0, op1;
-  int ret;
-
   if (!TARGET_QUAD_MEMORY && !TARGET_SYNC_TI)
-    ret = 0;
-
-  else if (!memory_operand (op, mode))
-    ret = 0;
-
-  else if (GET_MODE_SIZE (GET_MODE (op)) != 16)
-    ret = 0;
-
-  else if (MEM_ALIGN (op) < 128)
-    ret = 0;
-
-  else
-    {
-      addr = XEXP (op, 0);
-      if (int_reg_operand (addr, Pmode))
-       ret = 1;
+    return false;
 
-      else if (GET_CODE (addr) != PLUS)
-       ret = 0;
+  if (GET_MODE_SIZE (mode) != 16 || !MEM_P (op) || MEM_ALIGN (op) < 128)
+    return false;
 
-      else
-       {
-         op0 = XEXP (addr, 0);
-         op1 = XEXP (addr, 1);
-         ret = (int_reg_operand (op0, Pmode)
-                && GET_CODE (op1) == CONST_INT
-                && IN_RANGE (INTVAL (op1), -32768, 32767)
-                && (INTVAL (op1) & 15) == 0);
-       }
-    }
+  return quad_address_p (XEXP (op, 0), mode, true);
+})
 
-  if (TARGET_DEBUG_ADDR)
-    {
-      fprintf (stderr, "\nquad_memory_operand, ret = %s\n", ret ? "true" : "false");
-      debug_rtx (op);
-    }
+;; Return 1 if the operand is suitable for load/store to vector registers with
+;; d-form addressing (register+offset), which was added in ISA 3.0.
+;; Unlike quad_memory_operand, we do not have to check for alignment.
+(define_predicate "vsx_quad_dform_memory_operand"
+  (match_code "mem")
+{
+  if (!TARGET_P9_DFORM_VECTOR || !MEM_P (op) || GET_MODE_SIZE (mode) != 16)
+    return false;
 
-  return ret;
+  return quad_address_p (XEXP (op, 0), mode, false);
 })
 
 ;; Return 1 if the operand is an indexed or indirect memory operand.
index 275404a63ac2408cfb8298524e648a9486ad39c2..27239f1d3718d0c4c65ff71a67ac5a6660ae91bc 100644 (file)
                                 | OPTION_MASK_UPPER_REGS_SF)
 
 /* Add ISEL back into ISA 3.0, since it is supposed to be a win.  Do not add
-   P9_DFORM or P9_MINMAX until they are fully debugged.  */
+   P9_MINMAX until the hardware that supports it is available. Do not add
+   P9_DFORM_VECTOR until LRA is the default register allocator.  */
 #define ISA_3_0_MASKS_SERVER   (ISA_2_7_MASKS_SERVER                   \
                                 | OPTION_MASK_FLOAT128_HW              \
                                 | OPTION_MASK_ISEL                     \
                                 | OPTION_MASK_MODULO                   \
                                 | OPTION_MASK_P9_FUSION                \
-                                | OPTION_MASK_P9_DFORM                 \
+                                | OPTION_MASK_P9_DFORM_SCALAR          \
                                 | OPTION_MASK_P9_VECTOR)
 
 #define POWERPC_7400_MASK      (OPTION_MASK_PPC_GFXOPT | OPTION_MASK_ALTIVEC)
@@ -94,6 +95,7 @@
                                 | OPTION_MASK_FPRND                    \
                                 | OPTION_MASK_HTM                      \
                                 | OPTION_MASK_ISEL                     \
+                                | OPTION_MASK_LRA                      \
                                 | OPTION_MASK_MFCRF                    \
                                 | OPTION_MASK_MFPGPR                   \
                                 | OPTION_MASK_MODULO                   \
                                 | OPTION_MASK_NO_UPDATE                \
                                 | OPTION_MASK_P8_FUSION                \
                                 | OPTION_MASK_P8_VECTOR                \
-                                | OPTION_MASK_P9_DFORM                 \
+                                | OPTION_MASK_P9_DFORM_SCALAR          \
+                                | OPTION_MASK_P9_DFORM_VECTOR          \
                                 | OPTION_MASK_P9_FUSION                \
                                 | OPTION_MASK_P9_MINMAX                \
                                 | OPTION_MASK_P9_VECTOR                \
index d9a6b1f784b88a425d8b01b8a3609a213b5f5e9c..f75624f70d8ebe9bf4690d1073c25758263ea916 100644 (file)
@@ -86,6 +86,7 @@ extern int registers_ok_for_quad_peep (rtx, rtx);
 extern int mems_ok_for_quad_peep (rtx, rtx);
 extern bool gpr_or_gpr_p (rtx, rtx);
 extern bool direct_move_p (rtx, rtx);
+extern bool quad_address_p (rtx, machine_mode, bool);
 extern bool quad_load_store_p (rtx, rtx);
 extern bool fusion_gpr_load_p (rtx, rtx, rtx, rtx);
 extern void expand_fusion_gpr_load (rtx *);
index 0f70bb91126c17d8ee50e60860c539c30c9cb823..3f721c67cd58576a72b3ccfa25f196190bf4b22c 100644 (file)
@@ -452,6 +452,7 @@ typedef unsigned char addr_mask_type;
 #define RELOAD_REG_PRE_INCDEC  0x10    /* PRE_INC/PRE_DEC valid.  */
 #define RELOAD_REG_PRE_MODIFY  0x20    /* PRE_MODIFY valid.  */
 #define RELOAD_REG_AND_M16     0x40    /* AND -16 addressing.  */
+#define RELOAD_REG_QUAD_OFFSET 0x80    /* quad offset is limited.  */
 
 /* Register type masks based on the type, of valid addressing modes.  */
 struct rs6000_reg_addr {
@@ -499,6 +500,16 @@ mode_supports_vmx_dform (machine_mode mode)
   return ((reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_OFFSET) != 0);
 }
 
+/* Return true if we have D-form addressing in VSX registers.  This addressing
+   is more limited than normal d-form addressing in that the offset must be
+   aligned on a 16-byte boundary.  */
+static inline bool
+mode_supports_vsx_dform_quad (machine_mode mode)
+{
+  return ((reg_addr[mode].addr_mask[RELOAD_REG_ANY] & RELOAD_REG_QUAD_OFFSET)
+         != 0);
+}
+
 \f
 /* Target cpu costs.  */
 
@@ -2111,7 +2122,9 @@ rs6000_debug_addr_mask (addr_mask_type mask, bool keep_spaces)
   else if (keep_spaces)
     *p++ = ' ';
 
-  if ((mask & RELOAD_REG_OFFSET) != 0)
+  if ((mask & RELOAD_REG_QUAD_OFFSET) != 0)
+    *p++ = 'O';
+  else if ((mask & RELOAD_REG_OFFSET) != 0)
     *p++ = 'o';
   else if (keep_spaces)
     *p++ = ' ';
@@ -2648,8 +2661,7 @@ rs6000_debug_reg_global (void)
   if (TARGET_LINK_STACK)
     fprintf (stderr, DEBUG_FMT_S, "link_stack", "true");
 
-  if (targetm.lra_p ())
-    fprintf (stderr, DEBUG_FMT_S, "lra", "true");
+  fprintf (stderr, DEBUG_FMT_S, "lra", TARGET_LRA ? "true" : "false");
 
   if (TARGET_P8_FUSION)
     {
@@ -2784,17 +2796,31 @@ rs6000_setup_reg_addr_masks (void)
            }
 
          /* GPR and FPR registers can do REG+OFFSET addressing, except
-            possibly for SDmode.  ISA 3.0 (i.e. power9) adds D-form
-            addressing for scalars to altivec registers.  */
+            possibly for SDmode.  ISA 3.0 (i.e. power9) adds D-form addressing
+            for 64-bit scalars and 32-bit SFmode to altivec registers.  */
          if ((addr_mask != 0) && !indexed_only_p
              && msize <= 8
              && (rc == RELOAD_REG_GPR
-                 || rc == RELOAD_REG_FPR
-                 || (rc == RELOAD_REG_VMX
-                     && TARGET_P9_DFORM
-                     && (m2 == DFmode || m2 == SFmode))))
+                 || ((msize == 8 || m2 == SFmode)
+                     && (rc == RELOAD_REG_FPR
+                         || (rc == RELOAD_REG_VMX
+                             && TARGET_P9_DFORM_SCALAR)))))
            addr_mask |= RELOAD_REG_OFFSET;
 
+         /* VSX registers can do REG+OFFSET addresssing if ISA 3.0
+            instructions are enabled.  The offset for 128-bit VSX registers is
+            only 12-bits.  While GPRs can handle the full offset range, VSX
+            registers can only handle the restricted range.  */
+         else if ((addr_mask != 0) && !indexed_only_p
+                  && msize == 16 && TARGET_P9_DFORM_VECTOR
+                  && (ALTIVEC_OR_VSX_VECTOR_MODE (m2)
+                      || (m2 == TImode && TARGET_VSX_TIMODE)))
+           {
+             addr_mask |= RELOAD_REG_OFFSET;
+             if (rc == RELOAD_REG_FPR || rc == RELOAD_REG_VMX)
+               addr_mask |= RELOAD_REG_QUAD_OFFSET;
+           }
+
          /* VMX registers can do (REG & -16) and ((REG+REG) & -16)
             addressing on 128-bit types.  */
          if (rc == RELOAD_REG_VMX && msize == 16
@@ -3117,7 +3143,7 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
     }
 
   /* Support for new D-form instructions.  */
-  if (TARGET_P9_DFORM)
+  if (TARGET_P9_DFORM_SCALAR)
     rs6000_constraints[RS6000_CONSTRAINT_wb] = ALTIVEC_REGS;
 
   /* Support for ISA 3.0 (power9) vectors.  */
@@ -3990,7 +4016,8 @@ rs6000_option_override_internal (bool global_init_p)
 
   /* For the newer switches (vsx, dfp, etc.) set some of the older options,
      unless the user explicitly used the -mno-<option> to disable the code.  */
-  if (TARGET_P9_VECTOR || TARGET_MODULO || TARGET_P9_DFORM || TARGET_P9_MINMAX)
+  if (TARGET_P9_VECTOR || TARGET_MODULO || TARGET_P9_DFORM_SCALAR
+      || TARGET_P9_DFORM_VECTOR || TARGET_P9_DFORM_BOTH > 0 || TARGET_P9_MINMAX)
     rs6000_isa_flags |= (ISA_3_0_MASKS_SERVER & ~rs6000_isa_flags_explicit);
   else if (TARGET_P8_VECTOR || TARGET_DIRECT_MOVE || TARGET_CRYPTO)
     rs6000_isa_flags |= (ISA_2_7_MASKS_SERVER & ~rs6000_isa_flags_explicit);
@@ -4204,26 +4231,49 @@ rs6000_option_override_internal (bool global_init_p)
       && !(rs6000_isa_flags_explicit & OPTION_MASK_TOC_FUSION))
     rs6000_isa_flags |= OPTION_MASK_TOC_FUSION;
 
+  /* -mpower9-dform turns on both -mpower9-dform-scalar and
+      -mpower9-dform-vector. There are currently problems if
+      -mpower9-dform-vector instructions are enabled when we use the RELOAD
+      register allocator.  */
+  if (TARGET_P9_DFORM_BOTH > 0)
+    {
+      if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR)
+         && TARGET_LRA)
+       rs6000_isa_flags |= OPTION_MASK_P9_DFORM_VECTOR;
+
+      if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_SCALAR))
+       rs6000_isa_flags |= OPTION_MASK_P9_DFORM_SCALAR;
+    }
+  else if (TARGET_P9_DFORM_BOTH == 0)
+    {
+      if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR))
+       rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_VECTOR;
+
+      if (!(rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_SCALAR))
+       rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_SCALAR;
+    }
+
   /* ISA 3.0 D-form instructions require p9-vector and upper-regs.  */
-  if (TARGET_P9_DFORM && !TARGET_P9_VECTOR)
+  if ((TARGET_P9_DFORM_SCALAR || TARGET_P9_DFORM_VECTOR) && !TARGET_P9_VECTOR)
     {
       if (rs6000_isa_flags_explicit & OPTION_MASK_P9_VECTOR)
        error ("-mpower9-dform requires -mpower9-vector");
-      rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM;
+      rs6000_isa_flags &= ~(OPTION_MASK_P9_DFORM_SCALAR
+                           | OPTION_MASK_P9_DFORM_VECTOR);
     }
 
-  if (TARGET_P9_DFORM && !TARGET_UPPER_REGS_DF)
+  if (TARGET_P9_DFORM_SCALAR && !TARGET_UPPER_REGS_DF)
     {
       if (rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_DF)
        error ("-mpower9-dform requires -mupper-regs-df");
-      rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM;
+      rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_SCALAR;
     }
 
-  if (TARGET_P9_DFORM && !TARGET_UPPER_REGS_SF)
+  if (TARGET_P9_DFORM_SCALAR && !TARGET_UPPER_REGS_SF)
     {
       if (rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_SF)
        error ("-mpower9-dform requires -mupper-regs-sf");
-      rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM;
+      rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_SCALAR;
     }
 
   /* ISA 3.0 vector instructions include ISA 2.07.  */
@@ -4234,6 +4284,47 @@ rs6000_option_override_internal (bool global_init_p)
       rs6000_isa_flags &= ~OPTION_MASK_P9_VECTOR;
     }
 
+  /* There have been bugs with both -mvsx-timode and -mpower9-dform-vector that
+     don't show up with -mlra, but do show up with -mno-lra.  Given -mlra will
+     become the default once PR 69847 is fixed, turn off the options with
+     problems by default if -mno-lra was used, and warn if the user explicitly
+     asked for the option.
+
+     Enable -mpower9-dform-vector by default if LRA and other power9 options.
+     Enable -mvsx-timode by default if LRA and VSX.  */
+  if (!TARGET_LRA)
+    {
+      if (TARGET_VSX_TIMODE)
+       {
+         if ((rs6000_isa_flags_explicit & OPTION_MASK_VSX_TIMODE) != 0)
+           warning (0, "-mvsx-timode might need -mlra");
+
+         else
+           rs6000_isa_flags &= ~OPTION_MASK_VSX_TIMODE;
+       }
+
+      if (TARGET_P9_DFORM_VECTOR)
+       {
+         if ((rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR) != 0)
+           warning (0, "-mpower9-dform-vector might need -mlra");
+
+         else
+           rs6000_isa_flags &= ~OPTION_MASK_P9_DFORM_VECTOR;
+       }
+    }
+
+  else
+    {
+      if (TARGET_VSX && !TARGET_VSX_TIMODE
+         && (rs6000_isa_flags_explicit & OPTION_MASK_VSX_TIMODE) == 0)
+       rs6000_isa_flags |= OPTION_MASK_VSX_TIMODE;
+
+      if (TARGET_VSX && TARGET_P9_VECTOR && !TARGET_P9_DFORM_VECTOR
+         && TARGET_P9_DFORM_SCALAR && TARGET_P9_DFORM_BOTH < 0
+         && (rs6000_isa_flags_explicit & OPTION_MASK_P9_DFORM_VECTOR) == 0)
+       rs6000_isa_flags |= OPTION_MASK_P9_DFORM_VECTOR;
+    }
+
   /* Set -mallow-movmisalign to explicitly on if we have full ISA 2.07
      support. If we only have ISA 2.06 support, and the user did not specify
      the switch, leave it set to -1 so the movmisalign patterns are enabled,
@@ -6918,6 +7009,59 @@ direct_move_p (rtx op0, rtx op1)
   return false;
 }
 
+/* Return true if the OFFSET is valid for the quad address instructions that
+   use d-form (register + offset) addressing.  */
+
+static inline bool
+quad_address_offset_p (HOST_WIDE_INT offset)
+{
+  return (IN_RANGE (offset, -32768, 32767) && ((offset) & 0xf) == 0);
+}
+
+/* Return true if the ADDR is an acceptable address for a quad memory
+   operation of mode MODE (either LQ/STQ for general purpose registers, or
+   LXV/STXV for vector registers under ISA 3.0.  GPR_P is true if this address
+   is intended for LQ/STQ.  If it is false, the address is intended for the ISA
+   3.0 LXV/STXV instruction.  */
+
+bool
+quad_address_p (rtx addr, machine_mode mode, bool gpr_p)
+{
+  rtx op0, op1;
+
+  if (GET_MODE_SIZE (mode) != 16)
+    return false;
+
+  if (gpr_p)
+    {
+      if (!TARGET_QUAD_MEMORY && !TARGET_SYNC_TI)
+       return false;
+
+      /* LQ/STQ can handle indirect addresses.  */
+      if (base_reg_operand (addr, Pmode))
+       return true;
+    }
+
+  else
+    {
+      if (!mode_supports_vsx_dform_quad (mode))
+       return false;
+    }
+
+  if (GET_CODE (addr) != PLUS)
+    return false;
+
+  op0 = XEXP (addr, 0);
+  if (!base_reg_operand (op0, Pmode))
+    return false;
+
+  op1 = XEXP (addr, 1);
+  if (!CONST_INT_P (op1))
+    return false;
+
+  return quad_address_offset_p (INTVAL (op1));
+}
+
 /* Return true if this is a load or store quad operation.  This function does
    not handle the atomic quad memory instructions.  */
 
@@ -7010,6 +7154,10 @@ mem_operand_gpr (rtx op, machine_mode mode)
   if (TARGET_POWERPC64 && (offset & 3) != 0)
     return false;
 
+  if (mode_supports_vsx_dform_quad (mode)
+      && !quad_address_offset_p (offset))
+    return false;
+
   extra = GET_MODE_SIZE (mode) - UNITS_PER_WORD;
   if (extra < 0)
     extra = 0;
@@ -7039,13 +7187,14 @@ reg_offset_addressing_ok_p (machine_mode mode)
     case TImode:
     case TFmode:
     case KFmode:
-      /* AltiVec/VSX vector modes.  Only reg+reg addressing is valid.  While
-        TImode is not a vector mode, if we want to use the VSX registers to
-        move it around, we need to restrict ourselves to reg+reg addressing.
-        Similarly for IEEE 128-bit floating point that is passed in a single
-        vector register.  */
+      /* AltiVec/VSX vector modes.  Only reg+reg addressing was valid until the
+        ISA 3.0 vector d-form addressing mode was added.  While TImode is not
+        a vector mode, if we want to use the VSX registers to move it around,
+        we need to restrict ourselves to reg+reg addressing.  Similarly for
+        IEEE 128-bit floating point that is passed in a single vector
+        register.  */
       if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode))
-       return false;
+       return mode_supports_vsx_dform_quad (mode);
       break;
 
     case V4HImode:
@@ -7112,6 +7261,11 @@ offsettable_ok_by_alignment (rtx op, HOST_WIDE_INT offset,
   if (GET_CODE (op) != SYMBOL_REF)
     return false;
 
+  /* ISA 3.0 vector d-form addressing is restricted, don't allow
+     SYMBOL_REF.  */
+  if (mode_supports_vsx_dform_quad (mode))
+    return false;
+
   dsize = GET_MODE_SIZE (mode);
   decl = SYMBOL_REF_DECL (op);
   if (!decl)
@@ -7266,6 +7420,9 @@ rs6000_legitimate_offset_address_p (machine_mode mode, rtx x,
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
+  if (mode_supports_vsx_dform_quad (mode))
+    return (virtual_stack_registers_memory_p (x)
+           || quad_address_p (x, mode, false));
   if (!reg_offset_addressing_ok_p (mode))
     return virtual_stack_registers_memory_p (x);
   if (legitimate_constant_pool_address_p (x, mode, strict || lra_in_progress))
@@ -7404,6 +7561,9 @@ legitimate_lo_sum_address_p (machine_mode mode, rtx x, int strict)
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
+  /* quad word addresses are restricted, and we can't use LO_SUM.  */
+  if (mode_supports_vsx_dform_quad (mode))
+    return false;
   /* Restrict addressing for DI because of our SUBREG hackery.  */
   if (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
     return false;
@@ -7415,7 +7575,7 @@ legitimate_lo_sum_address_p (machine_mode mode, rtx x, int strict)
 
       if (DEFAULT_ABI == ABI_V4 && flag_pic)
        return false;
-      /* LRA don't use LEGITIMIZE_RELOAD_ADDRESS as it usually calls
+      /* LRA doesn't use LEGITIMIZE_RELOAD_ADDRESS as it usually calls
         push_reload from reload pass code.  LEGITIMIZE_RELOAD_ADDRESS
         recognizes some LO_SUM addresses as valid although this
         function says opposite.  In most cases, LRA through different
@@ -7469,7 +7629,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 {
   unsigned int extra;
 
-  if (!reg_offset_addressing_ok_p (mode))
+  if (!reg_offset_addressing_ok_p (mode)
+      || mode_supports_vsx_dform_quad (mode))
     {
       if (virtual_stack_registers_memory_p (x))
        return x;
@@ -8180,6 +8341,11 @@ rs6000_legitimize_reload_address (rtx x, machine_mode mode,
       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     {
+      if (TARGET_DEBUG_ADDR)
+       {
+         fprintf (stderr, "\nlegitimize_reload_address push_reload #1:\n");
+         debug_rtx (x);
+       }
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
@@ -8191,6 +8357,11 @@ rs6000_legitimize_reload_address (rtx x, machine_mode mode,
   if (GET_CODE (x) == LO_SUM
       && GET_CODE (XEXP (x, 0)) == HIGH)
     {
+      if (TARGET_DEBUG_ADDR)
+       {
+         fprintf (stderr, "\nlegitimize_reload_address push_reload #2:\n");
+         debug_rtx (x);
+       }
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
@@ -8223,6 +8394,11 @@ rs6000_legitimize_reload_address (rtx x, machine_mode mode,
     {
       rtx hi = gen_rtx_HIGH (Pmode, copy_rtx (x));
       x = gen_rtx_LO_SUM (Pmode, hi, x);
+      if (TARGET_DEBUG_ADDR)
+       {
+         fprintf (stderr, "\nlegitimize_reload_address push_reload #3:\n");
+         debug_rtx (x);
+       }
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
@@ -8260,6 +8436,11 @@ rs6000_legitimize_reload_address (rtx x, machine_mode mode,
                                      GEN_INT (high)),
                        GEN_INT (low));
 
+      if (TARGET_DEBUG_ADDR)
+       {
+         fprintf (stderr, "\nlegitimize_reload_address push_reload #4:\n");
+         debug_rtx (x);
+       }
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
@@ -8320,6 +8501,11 @@ rs6000_legitimize_reload_address (rtx x, machine_mode mode,
        x = gen_rtx_LO_SUM (GET_MODE (x),
              gen_rtx_HIGH (Pmode, x), x);
 
+      if (TARGET_DEBUG_ADDR)
+       {
+         fprintf (stderr, "\nlegitimize_reload_address push_reload #5:\n");
+         debug_rtx (x);
+       }
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
@@ -8353,9 +8539,16 @@ rs6000_legitimize_reload_address (rtx x, machine_mode mode,
     {
       x = create_TOC_reference (x, NULL_RTX);
       if (TARGET_CMODEL != CMODEL_SMALL)
-       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-                    BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-                    opnum, (enum reload_type) type);
+       {
+         if (TARGET_DEBUG_ADDR)
+           {
+             fprintf (stderr, "\nlegitimize_reload_address push_reload #6:\n");
+             debug_rtx (x);
+           }
+         push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                      BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+                      opnum, (enum reload_type) type);
+       }
       *win = 1;
       return x;
     }
@@ -8411,6 +8604,7 @@ static bool
 rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
 {
   bool reg_offset_p = reg_offset_addressing_ok_p (mode);
+  bool quad_offset_p = mode_supports_vsx_dform_quad (mode);
 
   /* If this is an unaligned stvx/ldvx type address, discard the outer AND.  */
   if (VECTOR_MEM_ALTIVEC_P (mode)
@@ -8430,15 +8624,26 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
     return 1;
   if (virtual_stack_registers_memory_p (x))
     return 1;
-  if (reg_offset_p && legitimate_small_data_p (mode, x))
-    return 1;
-  if (reg_offset_p
-      && legitimate_constant_pool_address_p (x, mode,
+
+  /* Handle restricted vector d-form offsets in ISA 3.0.  */
+  if (quad_offset_p)
+    {
+      if (quad_address_p (x, mode, false))
+       return 1;
+    }
+
+  else if (reg_offset_p)
+    {
+      if (legitimate_small_data_p (mode, x))
+       return 1;
+      if (legitimate_constant_pool_address_p (x, mode,
                                             reg_ok_strict || lra_in_progress))
-    return 1;
-  if (reg_offset_p && reg_addr[mode].fused_toc && GET_CODE (x) == UNSPEC
-      && XINT (x, 1) == UNSPEC_FUSION_ADDIS)
-    return 1;
+       return 1;
+      if (reg_addr[mode].fused_toc && GET_CODE (x) == UNSPEC
+         && XINT (x, 1) == UNSPEC_FUSION_ADDIS)
+       return 1;
+    }
+
   /* For TImode, if we have load/store quad and TImode in VSX registers, only
      allow register indirect addresses.  This will allow the values to go in
      either GPRs or VSX registers without reloading.  The vector types would
@@ -8477,7 +8682,8 @@ rs6000_legitimate_address_p (machine_mode mode, rtx x, bool reg_ok_strict)
              && legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict)))
       && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
     return 1;
-  if (reg_offset_p && legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
+  if (reg_offset_p && !quad_offset_p
+      && legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
     return 1;
   return 0;
 }
@@ -18423,13 +18629,23 @@ rs6000_secondary_reload_memory (rtx addr,
            }
        }
 
+      else if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0
+              && CONST_INT_P (plus_arg1))
+       {
+         if (!quad_address_offset_p (INTVAL (plus_arg1)))
+           {
+             extra_cost = 1;
+             type = "vector d-form offset";
+           }
+       }
+
       /* Make sure the register class can handle offset addresses.  */
       else if (rs6000_legitimate_offset_address_p (mode, addr, false, true))
        {
          if ((addr_mask & RELOAD_REG_OFFSET) == 0)
            {
              extra_cost = 1;
-             type = "offset";
+             type = "offset #2";
            }
        }
 
@@ -18442,7 +18658,14 @@ rs6000_secondary_reload_memory (rtx addr,
       break;
 
     case LO_SUM:
-      if (!legitimate_lo_sum_address_p (mode, addr, false))
+      /* Quad offsets are restricted and can't handle normal addresses.  */
+      if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0)
+       {
+         extra_cost = -1;
+         type = "vector d-form lo_sum";
+       }
+
+      else if (!legitimate_lo_sum_address_p (mode, addr, false))
        {
          fail_msg = "bad LO_SUM";
          extra_cost = -1;
@@ -18459,8 +18682,17 @@ rs6000_secondary_reload_memory (rtx addr,
     case CONST:
     case SYMBOL_REF:
     case LABEL_REF:
-      type = "address";
-      extra_cost = rs6000_secondary_reload_toc_costs (addr_mask);
+      if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0)
+       {
+         extra_cost = -1;
+         type = "vector d-form lo_sum #2";
+       }
+
+      else
+       {
+         type = "address";
+         extra_cost = rs6000_secondary_reload_toc_costs (addr_mask);
+       }
       break;
 
       /* TOC references look like offsetable memory.  */
@@ -18471,6 +18703,12 @@ rs6000_secondary_reload_memory (rtx addr,
          extra_cost = -1;
        }
 
+      else if ((addr_mask & RELOAD_REG_QUAD_OFFSET) != 0)
+       {
+         extra_cost = -1;
+         type = "vector d-form lo_sum #3";
+       }
+
       else if ((addr_mask & RELOAD_REG_OFFSET) == 0)
        {
          extra_cost = 1;
@@ -19101,6 +19339,16 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
            }
        }
 
+      else if (mode_supports_vsx_dform_quad (mode) && CONST_INT_P (op1))
+       {
+         if (((addr_mask & RELOAD_REG_QUAD_OFFSET) == 0)
+             || !quad_address_p (addr, mode, false))
+           {
+             emit_insn (gen_rtx_SET (scratch, addr));
+             new_addr = scratch;
+           }
+       }
+
       /* Make sure the register class can handle offset addresses.  */
       else if (rs6000_legitimate_offset_address_p (mode, addr, false, true))
        {
@@ -19131,6 +19379,13 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
            }
        }
 
+      /* Quad offsets are restricted and can't handle normal addresses.  */
+      else if (mode_supports_vsx_dform_quad (mode))
+       {
+         emit_insn (gen_rtx_SET (scratch, addr));
+         new_addr = scratch;
+       }
+
       /* Make sure the register class can handle offset addresses.  */
       else if (legitimate_lo_sum_address_p (mode, addr, false))
        {
@@ -19351,7 +19606,8 @@ rs6000_preferred_reload_class (rtx x, enum reg_class rclass)
        }
 
       /* D-form addressing can easily reload the value.  */
-      if (mode_supports_vmx_dform (mode))
+      if (mode_supports_vmx_dform (mode)
+         || mode_supports_vsx_dform_quad (mode))
        return rclass;
 
       /* If this is a scalar floating point value and we don't have D-form
@@ -19786,8 +20042,16 @@ rs6000_output_move_128bit (rtx operands[])
 
       else if (TARGET_VSX && dest_vsx_p)
        {
-         if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
+         if (mode_supports_vsx_dform_quad (mode)
+             && quad_address_p (XEXP (src, 0), mode, false))
+           return "lxv %x0,%1";
+
+         else if (TARGET_P9_VECTOR)
+           return "lxvx %x0,%y1";
+
+         else if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
            return "lxvw4x %x0,%y1";
+
          else
            return "lxvd2x %x0,%y1";
        }
@@ -19816,8 +20080,16 @@ rs6000_output_move_128bit (rtx operands[])
 
       else if (TARGET_VSX && src_vsx_p)
        {
-         if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
+         if (mode_supports_vsx_dform_quad (mode)
+             && quad_address_p (XEXP (dest, 0), mode, false))
+           return "stxv %x1,%0";
+
+         else if (TARGET_P9_VECTOR)
+           return "stxvx %x1,%y0";
+
+         else if (mode == V16QImode || mode == V8HImode || mode == V4SImode)
            return "stxvw4x %x1,%y0";
+
          else
            return "stxvd2x %x1,%y0";
        }
@@ -26236,25 +26508,37 @@ rs6000_emit_prologue (void)
        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
          {
            rtx areg, savereg, mem;
-           int offset;
+           HOST_WIDE_INT offset;
 
            offset = (info->altivec_save_offset + frame_off
                      + 16 * (i - info->first_altivec_reg_save));
 
            savereg = gen_rtx_REG (V4SImode, i);
 
-           NOT_INUSE (0);
-           areg = gen_rtx_REG (Pmode, 0);
-           emit_move_insn (areg, GEN_INT (offset));
-
-           /* AltiVec addressing mode is [reg+reg].  */
-           mem = gen_frame_mem (V4SImode,
-                                gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+           if (TARGET_P9_DFORM_VECTOR && quad_address_offset_p (offset))
+             {
+               mem = gen_frame_mem (V4SImode,
+                                    gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                                  GEN_INT (offset)));
+               insn = emit_insn (gen_rtx_SET (mem, savereg));
+               areg = NULL_RTX;
+             }
+           else
+             {
+               NOT_INUSE (0);
+               areg = gen_rtx_REG (Pmode, 0);
+               emit_move_insn (areg, GEN_INT (offset));
 
-           /* Rather than emitting a generic move, force use of the stvx
-              instruction, which we always want.  In particular we don't
-              want xxpermdi/stxvd2x for little endian.  */
-           insn = emit_insn (gen_altivec_stvx_v4si_internal (mem, savereg));
+               /* AltiVec addressing mode is [reg+reg].  */
+               mem = gen_frame_mem (V4SImode,
+                                    gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+
+               /* Rather than emitting a generic move, force use of the stvx
+                  instruction, which we always want on ISA 2.07 (power8) systems.
+                  In particular we don't want xxpermdi/stxvd2x for little
+                  endian.  */
+               insn = emit_insn (gen_altivec_stvx_v4si_internal (mem, savereg));
+             }
 
            rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
                                  areg, GEN_INT (offset));
@@ -26974,23 +27258,35 @@ rs6000_emit_epilogue (int sibcall)
          for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
            if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
              {
-               rtx addr, areg, mem, reg;
+               rtx addr, areg, mem, insn;
+               rtx reg = gen_rtx_REG (V4SImode, i);
+               HOST_WIDE_INT offset
+                 = (info->altivec_save_offset + frame_off
+                    + 16 * (i - info->first_altivec_reg_save));
 
-               areg = gen_rtx_REG (Pmode, 0);
-               emit_move_insn
-                 (areg, GEN_INT (info->altivec_save_offset
-                                 + frame_off
-                                 + 16 * (i - info->first_altivec_reg_save)));
+               if (TARGET_P9_DFORM_VECTOR && quad_address_offset_p (offset))
+                 {
+                   mem = gen_frame_mem (V4SImode,
+                                        gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                                      GEN_INT (offset)));
+                   insn = gen_rtx_SET (reg, mem);
+                 }
+               else
+                 {
+                   areg = gen_rtx_REG (Pmode, 0);
+                   emit_move_insn (areg, GEN_INT (offset));
 
-               /* AltiVec addressing mode is [reg+reg].  */
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
-               mem = gen_frame_mem (V4SImode, addr);
-
-               reg = gen_rtx_REG (V4SImode, i);
-               /* Rather than emitting a generic move, force use of the
-                  lvx instruction, which we always want.  In particular
-                  we don't want lxvd2x/xxpermdi for little endian.  */
-               (void) emit_insn (gen_altivec_lvx_v4si_internal (reg, mem));
+                   /* AltiVec addressing mode is [reg+reg].  */
+                   addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+                   mem = gen_frame_mem (V4SImode, addr);
+
+                   /* Rather than emitting a generic move, force use of the
+                      lvx instruction, which we always want.  In particular we
+                      don't want lxvd2x/xxpermdi for little endian.  */
+                   insn = gen_altivec_lvx_v4si_internal (reg, mem);
+                 }
+
+               (void) emit_insn (insn);
              }
        }
 
@@ -27177,23 +27473,35 @@ rs6000_emit_epilogue (int sibcall)
          for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
            if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
              {
-               rtx addr, areg, mem, reg;
+               rtx addr, areg, mem, insn;
+               rtx reg = gen_rtx_REG (V4SImode, i);
+               HOST_WIDE_INT offset
+                 = (info->altivec_save_offset + frame_off
+                    + 16 * (i - info->first_altivec_reg_save));
 
-               areg = gen_rtx_REG (Pmode, 0);
-               emit_move_insn
-                 (areg, GEN_INT (info->altivec_save_offset
-                                 + frame_off
-                                 + 16 * (i - info->first_altivec_reg_save)));
+               if (TARGET_P9_DFORM_VECTOR && quad_address_offset_p (offset))
+                 {
+                   mem = gen_frame_mem (V4SImode,
+                                        gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                                      GEN_INT (offset)));
+                   insn = gen_rtx_SET (reg, mem);
+                 }
+               else
+                 {
+                   areg = gen_rtx_REG (Pmode, 0);
+                   emit_move_insn (areg, GEN_INT (offset));
 
-               /* AltiVec addressing mode is [reg+reg].  */
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
-               mem = gen_frame_mem (V4SImode, addr);
-
-               reg = gen_rtx_REG (V4SImode, i);
-               /* Rather than emitting a generic move, force use of the
-                  lvx instruction, which we always want.  In particular
-                  we don't want lxvd2x/xxpermdi for little endian.  */
-               (void) emit_insn (gen_altivec_lvx_v4si_internal (reg, mem));
+                   /* AltiVec addressing mode is [reg+reg].  */
+                   addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+                   mem = gen_frame_mem (V4SImode, addr);
+
+                   /* Rather than emitting a generic move, force use of the
+                      lvx instruction, which we always want.  In particular we
+                      don't want lxvd2x/xxpermdi for little endian.  */
+                   insn = gen_altivec_lvx_v4si_internal (reg, mem);
+                 }
+
+               (void) emit_insn (insn);
              }
        }
 
@@ -34365,7 +34673,7 @@ rs6000_libcall_value (machine_mode mode)
 static bool
 rs6000_lra_p (void)
 {
-  return rs6000_lra_flag;
+  return TARGET_LRA;
 }
 
 /* Given FROM and TO register numbers, say whether this elimination is allowed.
@@ -34726,7 +35034,8 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] =
   { "power8-fusion",           OPTION_MASK_P8_FUSION,          false, true  },
   { "power8-fusion-sign",      OPTION_MASK_P8_FUSION_SIGN,     false, true  },
   { "power8-vector",           OPTION_MASK_P8_VECTOR,          false, true  },
-  { "power9-dform",            OPTION_MASK_P9_DFORM,           false, true  },
+  { "power9-dform-scalar",     OPTION_MASK_P9_DFORM_SCALAR,    false, true  },
+  { "power9-dform-vector",     OPTION_MASK_P9_DFORM_VECTOR,    false, true  },
   { "power9-fusion",           OPTION_MASK_P9_FUSION,          false, true  },
   { "power9-minmax",           OPTION_MASK_P9_MINMAX,          false, true  },
   { "power9-vector",           OPTION_MASK_P9_VECTOR,          false, true  },
@@ -35359,7 +35668,9 @@ rs6000_print_options_internal (FILE *file,
   size_t i;
   size_t start_column = 0;
   size_t cur_column;
-  size_t max_column = 76;
+  size_t max_column = 120;
+  size_t prefix_len = strlen (prefix);
+  size_t comma_len = 0;
   const char *comma = "";
 
   if (indent)
@@ -35377,27 +35688,45 @@ rs6000_print_options_internal (FILE *file,
   cur_column = start_column;
   for (i = 0; i < num_elements; i++)
     {
-      if ((flags & opts[i].mask) != 0)
+      bool invert = opts[i].invert;
+      const char *name = opts[i].name;
+      const char *no_str = "";
+      HOST_WIDE_INT mask = opts[i].mask;
+      size_t len = comma_len + prefix_len + strlen (name);
+
+      if (!invert)
        {
-         const char *no_str = rs6000_opt_masks[i].invert ? "no-" : "";
-         size_t len = (strlen (comma)
-                       + strlen (prefix)
-                       + strlen (no_str)
-                       + strlen (rs6000_opt_masks[i].name));
+         if ((flags & mask) == 0)
+           {
+             no_str = "no-";
+             len += sizeof ("no-") - 1;
+           }
 
-         cur_column += len;
-         if (cur_column > max_column)
+         flags &= ~mask;
+       }
+
+      else
+       {
+         if ((flags & mask) != 0)
            {
-             fprintf (stderr, ", \\\n%*s", (int)start_column, "");
-             cur_column = start_column + len;
-             comma = "";
+             no_str = "no-";
+             len += sizeof ("no-") - 1;
            }
 
-         fprintf (file, "%s%s%s%s", comma, prefix, no_str,
-                  rs6000_opt_masks[i].name);
-         flags &= ~ opts[i].mask;
-         comma = ", ";
+         flags |= mask;
        }
+
+      cur_column += len;
+      if (cur_column > max_column)
+       {
+         fprintf (stderr, ", \\\n%*s", (int)start_column, "");
+         cur_column = start_column + len;
+         comma = "";
+       }
+
+      fprintf (file, "%s%s%s%s", comma, prefix, no_str, name);
+      comma = ", ";
+      comma_len = sizeof (", ") - 1;
     }
 
   fputs ("\n", file);
index 9a155ce0e05a9927f913466e320da5a9374e8177..92c5396c47ee455c3e7c29d35181b2ade47315bb 100644 (file)
@@ -470,8 +470,8 @@ Target RejectNegative Joined UInteger Var(rs6000_long_double_type_size) Save
 -mlong-double-<n>      Specify size of long double (64 or 128 bits).
 
 mlra
-Target Report Var(rs6000_lra_flag) Init(0) Save
-Use LRA instead of reload.
+Target Report Mask(LRA) Var(rs6000_isa_flags)
+Enable Local Register Allocation.
 
 msched-costly-dep=
 Target RejectNegative Joined Var(rs6000_sched_costly_dep_str)
@@ -609,9 +609,17 @@ mpower9-vector
 Target Report Mask(P9_VECTOR) Var(rs6000_isa_flags)
 Use/do not use vector and scalar instructions added in ISA 3.0.
 
+mpower9-dform-scalar
+Target Undocumented Mask(P9_DFORM_SCALAR) Var(rs6000_isa_flags)
+Use/do not use scalar register+offset memory instructions added in ISA 3.0.
+
+mpower9-dform-vector
+Target Undocumented Mask(P9_DFORM_VECTOR) Var(rs6000_isa_flags)
+Use/do not use vector register+offset memory instructions added in ISA 3.0.
+
 mpower9-dform
-Target Undocumented Mask(P9_DFORM) Var(rs6000_isa_flags)
-Use/do not use vector and scalar instructions added in ISA 3.0.
+Target Report Var(TARGET_P9_DFORM_BOTH) Init(-1) Save
+Use/do not use register+offset memory instructions added in ISA 3.0.
 
 mpower9-minmax
 Target Undocumented Mask(P9_MINMAX) Var(rs6000_isa_flags)
index 1d6e4797d7ca12f22f668ba3d41b3f54cd8b4ca1..57cee7934ba48d01420535dba668e7586c8e552f 100644 (file)
    UNSPEC_VSX_XVCVDPUXDS
   ])
 
-;; VSX (P9) moves
-
-(define_insn "*p9_vecload_<mode>"
-  [(set (match_operand:VSX_M2 0 "vsx_register_operand" "=<VSa>")
-        (match_operand:VSX_M2 1 "memory_operand" "Z"))]
-  "TARGET_P9_VECTOR"
-  "lxvx %x0,%y1"
-  [(set_attr "type" "vecload")
-   (set_attr "length" "4")])
-
-(define_insn "*p9_vecstore_<mode>"
-  [(set (match_operand:VSX_M2 0 "memory_operand" "=Z")
-        (match_operand:VSX_M2 1 "vsx_register_operand" "<VSa>"))]
-  "TARGET_P9_VECTOR"
-  "stxvx %x1,%y0"
-  [(set_attr "type" "vecstore")
-   (set_attr "length" "4")])
-
 ;; VSX moves
 
 ;; The patterns for LE permuted loads and stores come before the general
   "")
 
 (define_insn "*vsx_mov<mode>"
-  [(set (match_operand:VSX_M 0 "nonimmediate_operand" "=Z,<VSr>,<VSr>,?Z,?<VSa>,?<VSa>,r,we,wQ,?&r,??Y,??r,??r,<VSr>,?<VSa>,*r,v,wZ,v")
-       (match_operand:VSX_M 1 "input_operand" "<VSr>,Z,<VSr>,<VSa>,Z,<VSa>,we,b,r,wQ,r,Y,r,j,j,j,W,v,wZ"))]
+  [(set (match_operand:VSX_M 0 "nonimmediate_operand" "=ZwO,<VSr>,<VSr>,?ZwO,?<VSa>,?<VSa>,r,we,wQ,?&r,??Y,??r,??r,<VSr>,?<VSa>,*r,v,wZ,v")
+       (match_operand:VSX_M 1 "input_operand" "<VSr>,ZwO,<VSr>,<VSa>,ZwO,<VSa>,we,b,r,wQ,r,Y,r,j,j,j,W,v,wZ"))]
   "VECTOR_MEM_VSX_P (<MODE>mode)
    && (register_operand (operands[0], <MODE>mode) 
        || register_operand (operands[1], <MODE>mode))"
 ;; use of TImode is for unions.  However for plain data movement, slightly
 ;; favor the vector loads
 (define_insn "*vsx_movti_64bit"
-  [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,wa,r,we,v,v,wZ,wQ,&r,Y,r,r,?r")
-       (match_operand:TI 1 "input_operand" "wa,Z,wa,O,we,b,W,wZ,v,r,wQ,r,Y,r,n"))]
+  [(set (match_operand:TI 0 "nonimmediate_operand" "=ZwO,wa,wa,wa,r,we,v,v,wZ,wQ,&r,Y,r,r,?r")
+       (match_operand:TI 1 "input_operand" "wa,ZwO,wa,O,we,b,W,wZ,v,r,wQ,r,Y,r,n"))]
   "TARGET_POWERPC64 && VECTOR_MEM_VSX_P (TImode)
    && (register_operand (operands[0], TImode) 
        || register_operand (operands[1], TImode))"
    (set_attr "length" "4,4,4,4,8,4,16,4,4,8,8,8,8,8,8")])
 
 (define_insn "*vsx_movti_32bit"
-  [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,wa,v, v,wZ,Q,Y,????r,????r,????r,r")
-       (match_operand:TI 1 "input_operand"        "wa, Z,wa, O,W,wZ, v,r,r,    Q,    Y,    r,n"))]
+  [(set (match_operand:TI 0 "nonimmediate_operand" "=ZwO,wa,wa,wa,v,v,wZ,Q,Y,????r,????r,????r,r")
+       (match_operand:TI 1 "input_operand"        "wa,ZwO,wa,O,W,wZ,v,r,r,Q,Y,r,n"))]
   "! TARGET_POWERPC64 && VECTOR_MEM_VSX_P (TImode)
    && (register_operand (operands[0], TImode)
        || register_operand (operands[1], TImode))"
index a54a0af77b8757478ab3738a0ed48e77474e3644..d3e25380df62bff80acbfb1e5c40e3e5f4dfeafa 100644 (file)
@@ -1006,7 +1006,8 @@ See RS/6000 and PowerPC Options.
 -mupper-regs-df -mno-upper-regs-df -mupper-regs-sf -mno-upper-regs-sf @gol
 -mupper-regs -mno-upper-regs -mmodulo -mno-modulo @gol
 -mfloat128 -mno-float128 -mfloat128-hardware -mno-float128-hardware @gol
--mpower9-fusion -mno-mpower9-fusion -mpower9-vector -mno-power9-vector}
+-mpower9-fusion -mno-mpower9-fusion -mpower9-vector -mno-power9-vector @gol
+-mpower9-dform -mno-power9-dform -mlra -mno-lra}
 
 @emph{RX Options}
 @gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
@@ -13702,7 +13703,6 @@ Enable the use of indexed loads.  This can be problematic because some
 optimizers then assume that indexed stores exist, which is not
 the case.
 
-@item -mlra
 @opindex mlra
 Enable Local Register Allocation.  This is still experimental for ARC,
 so by default the compiler uses standard reload
@@ -19928,7 +19928,7 @@ following options:
 -msimple-fpu -mstring  -mmulhw  -mdlmzb  -mmfpgpr -mvsx @gol
 -mcrypto -mdirect-move -mpower8-fusion -mpower8-vector @gol
 -mquad-memory -mquad-memory-atomic -mmodulo -mfloat128 -mfloat128-hardware @gol
--mpower9-fusion -mpower9-vector}
+-mpower9-fusion -mpower9-vector -mpower9-dform}
 
 The particular options set for any particular CPU varies between
 compiler versions, depending on what setting seems to produce optimal
@@ -20052,6 +20052,12 @@ This switch enables or disables the generation of ISEL instructions.
 This switch has been deprecated.  Use @option{-misel} and
 @option{-mno-isel} instead.
 
+@item -mlra
+@opindex mlra
+Enable Local Register Allocation.  This is still experimental for PowerPC,
+so by default the compiler uses standard reload
+(i.e. @option{-mno-lra}).
+
 @item -mspe
 @itemx -mno-spe
 @opindex mspe
@@ -20201,10 +20207,19 @@ processors.
 @opindex mpower9-vector
 @opindex mno-power9-vector
 Generate code that uses (does not use) the vector and scalar
-instructions that were added in version 2.07 of the PowerPC ISA.  Also
+instructions that were added in version 3.0 of the PowerPC ISA.  Also
 enable the use of built-in functions that allow more direct access to
 the vector instructions.
 
+@item -mpower9-dform
+@itemx -mno-power9-dform
+@opindex mpower9-dform
+@opindex mno-power9-dform
+Enable (disable) scalar d-form (register + offset) memory instructions
+to load/store traditional Altivec registers. If the @var{LRA} register
+allocator is enabled, also enable (disable) vector d-form memory
+instructions.
+
 @item -mfloat-gprs=@var{yes/single/double/no}
 @itemx -mfloat-gprs
 @opindex mfloat-gprs
index afaecef4e54f70d348175bda31c0797f6a21ada3..f2360c8dfb62c24650e5b9f68238430f4ae75989 100644 (file)
@@ -3224,6 +3224,9 @@ Memory operand suitable for TOC fusion memory references.
 Int constant that is the element number that the MFVSRLD instruction
 targets.
 
+@item wO
+A memory operand suitable for the ISA 3.0 vector d-form instructions.
+
 @item wQ
 A memory address that will work with the @code{lq} and @code{stq}
 instructions.
index 93c8706aca6df53a0f347a9c59239053b1bd5770..77b1856371c038baa9cd29efa47b59f23c8435fb 100644 (file)
@@ -1,3 +1,13 @@
+2016-05-11  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * gcc.target/powerpc/dform-3.c: New test for ISA 3.0 vector d-form
+       support.
+       * gcc.target/powerpc/dform-1.c: Add -mlra option to silence
+       warning when using -mvsx-timode.
+       * gcc.target/powerpc/p8vector-int128-1.c: Likewise.
+       * gcc.target/powerpc/dform-2.c: Likewise.
+       * gcc.target/powerpc/pr68805.c: Likewise.
+
 2016-05-11  Marek Polacek  <polacek@redhat.com>
 
        PR c++/71024
index 37a30d1c92f68ecca65e85adda190af5d53787a0..12623f20262cf402f33051de5d110933aa39cbd2 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
 /* { dg-require-effective-target powerpc_p9vector_ok } */
 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
-/* { dg-options "-mcpu=power9 -mpower9-dform -O2" } */
+/* { dg-options "-mcpu=power9 -mpower9-dform -O2 -mlra" } */
 
 #ifndef TYPE
 #define TYPE double
index b4c4199c0b3d6bcddd1c0322e768882c8472e688..86d65b5b1fdcec7581dae973d12b67e4c9976b9f 100644 (file)
@@ -1,7 +1,7 @@
 /* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
 /* { dg-require-effective-target powerpc_p9vector_ok } */
 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
-/* { dg-options "-mcpu=power9 -mpower9-dform -O2" } */
+/* { dg-options "-mcpu=power9 -mpower9-dform -O2 -mlra" } */
 
 #ifndef TYPE
 #define TYPE float
diff --git a/gcc/testsuite/gcc.target/powerpc/dform-3.c b/gcc/testsuite/gcc.target/powerpc/dform-3.c
new file mode 100644 (file)
index 0000000..b1c481f
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-options "-mcpu=power9 -mpower9-dform -O2 -mlra" } */
+
+#ifndef TYPE
+#define TYPE vector double
+#endif
+
+struct foo {
+  TYPE a, b, c, d;
+};
+
+/* Test whether ISA 3.0 vector d-form instructions are implemented.  */
+void
+add (struct foo *p)
+{
+  p->b = p->c + p->d;
+}
+
+/* Make sure we don't use direct moves to get stuff into GPR registers.  */
+void
+gpr (struct foo *p)
+{
+  TYPE x = p->c;
+
+  __asm__ (" # reg = %0" : "+r" (x));
+
+  p->b = x;
+}
+
+/* { dg-final { scan-assembler     "lxv "      } } */
+/* { dg-final { scan-assembler     "stxv "     } } */
+/* { dg-final { scan-assembler-not "lxvx "     } } */
+/* { dg-final { scan-assembler-not "stxvx "    } } */
+/* { dg-final { scan-assembler-not "mfvsrd "   } } */
+/* { dg-final { scan-assembler-not "mfvsrld "  } } */
+/* { dg-final { scan-assembler     "l\[dq\] "  } } */
+/* { dg-final { scan-assembler     "st\[dq\] " } } */
index 31e07dd2b41572a56a426431e13829e0efa5cbd7..5ba772f53015716343ef69a3f1cc06ff4c02536a 100644 (file)
@@ -2,7 +2,7 @@
 /* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
 /* { dg-require-effective-target powerpc_p8vector_ok } */
 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
-/* { dg-options "-mcpu=power8 -O3 -mvsx-timode" } */
+/* { dg-options "-mcpu=power8 -O3 -mvsx-timode -mlra" } */
 
 #include <altivec.h>
 
index f4454a9e2d2e16db6554cc77442c70d4e210950f..5510811107da4e03ff33555109c360743007ae92 100644 (file)
@@ -1,6 +1,6 @@
 /* { dg-do compile { target powerpc64le-*-* } } */
 /* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
-/* { dg-options "-O2 -mvsx-timode -mcpu=power8" } */
+/* { dg-options "-O2 -mvsx-timode -mcpu=power8 -mlra" } */
 
 typedef struct bar {
   void *a;