Index: gcc/config/rs6000/rs6000-prefixed.c
===================================================================
--- gcc/config/rs6000/rs6000-prefixed.c	(revision 0)
+++ gcc/config/rs6000/rs6000-prefixed.c	(working copy)
@@ -0,0 +1,188 @@
+/* Subroutines used to support prefixed addressing on the PowerPC.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#define IN_TARGET_CODE 1
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "memmodel.h"
+#include "df.h"
+#include "tm_p.h"
+#include "ira.h"
+#include "print-tree.h"
+#include "varasm.h"
+#include "explow.h"
+#include "expr.h"
+#include "output.h"
+#include "tree-pass.h"
+#include "rtx-vector-builder.h"
+#include "print-rtl.h"
+#include "insn-attr.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "tm-constrs.h"
+
+/* Whether the next instruction needs a 'p' prefix issued before the
+   instruction is printed out.  */
+static bool next_insn_prefixed_p;
+
+/* Define FINAL_PRESCAN_INSN if some processing needs to be done before
+   outputting the assembler code.  On the PowerPC, we remember if the current
+   insn is a prefixed insn where we need to emit a 'p' before the insn.  */
+void
+rs6000_final_prescan_insn (rtx_insn *insn)
+{
+  next_insn_prefixed_p = (get_attr_prefixed (insn) != PREFIXED_NO);
+  return;
+}
+
+/* Define ASM_OUTPUT_OPCODE to do anything special before emitting an opcode.
+   We use it to emit a 'p' for prefixed insns that is set in
+   FINAL_PRESCAN_INSN.  We also use it for PCREL_OPT to emit the relocation
+   that ties the load of the GOT pointer with the load/store that uses the GOT
+   number.  */
+void
+rs6000_asm_output_opcode (FILE *stream, const char *)
+{
+  if (next_insn_prefixed_p)
+    {
+      next_insn_prefixed_p = false;
+      fprintf (stream, "p");
+    }
+
+  return;
+}
+
+
+/* Whether a load instruction is a prefixed instruction.  This is called from
+   the prefixed attribute processing.  We can't use operands[0] and
+   operands[1], because there are several load insns that don't use the
+   standard destination and source operands (mov<mode>_update1, etc.).  */
+
+bool
+prefixed_load_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx reg = SET_DEST (set);
+  rtx mem = SET_SRC (set);
+  bool sign_p = false;
+
+  /* Allow sign/zero/float extend as part of the load.  */
+  if (GET_CODE (mem) == SIGN_EXTEND)
+    {
+      sign_p = true;
+      mem = XEXP (mem, 0);
+    }
+
+  else if (GET_CODE (mem) == ZERO_EXTEND || GET_CODE (mem) == FLOAT_EXTEND)
+    mem = XEXP (mem, 0);
+
+  /* Is this a load?  */
+  if (!MEM_P (mem))
+    return false;
+
+  machine_mode mode = GET_MODE (mem);
+  rtx addr = XEXP (mem, 0);
+
+  /* Special case LWA, which uses the DS instruction format, instead of the D
+     instruction format.  */
+  enum insn_form iform = (sign_p && mode == SImode && GET_CODE (addr) == PLUS
+			  ? INSN_FORM_DS
+			  : reg_to_insn_form (reg, mode));
+
+  return prefixed_local_addr_p (addr, mode, iform);
+}
+
+/* Whether a store instruction is a prefixed instruction.  This is called from
+   the prefixed attribute processing.  */
+
+bool
+prefixed_store_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx mem = SET_DEST (set);
+  rtx reg = SET_SRC (set);
+
+  /* Is this a store?  */
+  if (!MEM_P (mem))
+    return false;
+
+  machine_mode mode = GET_MODE (mem);
+  enum insn_form iform = reg_to_insn_form (reg, mode);
+
+  return prefixed_local_addr_p (XEXP (mem, 0), mode, iform);
+}
+
+/* Whether a load immediate or add instruction is a prefixed instruction.  This
+   is called from the prefixed attribute processing.  */
+
+bool
+prefixed_paddi_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+  if (!set)
+    return false;
+
+  rtx dest = SET_DEST (set);
+  rtx src = SET_SRC (set);
+
+  if (!REG_P (dest) && !SUBREG_P (dest))
+    return false;
+
+  /* Is this a load immediate that can't be done with a simple ADDI or
+     ADDIS?  */
+  if (CONST_INT_P (src))
+    return (satisfies_constraint_eI (src)
+	    && !satisfies_constraint_I (src)
+	    && !satisfies_constraint_L (src));
+
+  /* Is this a PADDI instruction that can't be done with a simple ADDI or
+     ADDIS?  */
+  if (GET_CODE (src) == PLUS)
+    {
+      rtx op1 = XEXP (src, 1);
+
+      return (CONST_INT_P (op1)
+	      && satisfies_constraint_eI (op1)
+	      && !satisfies_constraint_I (op1)
+	      && !satisfies_constraint_L (op1));
+    }
+
+  /* If not, is it a load of a pc-relative address?  */
+  if (!TARGET_PCREL)
+    return false;
+
+  if (!SYMBOL_REF_P (src) && !LABEL_REF_P (src) && GET_CODE (src) != CONST)
+    return false;
+
+  /* Look for either pc-relative addresses of local symbols that we can use a
+     PLA to load or external symbols that we can load a GOT address via a
+     pc-relative load.  */
+  return pcrel_addr_p (src, true, true, PCREL_NULL);
+}
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
--- gcc/config/rs6000/rs6000-protos.h	(revision 274174)
+++ gcc/config/rs6000/rs6000-protos.h	(working copy)
@@ -245,7 +245,14 @@ extern void rs6000_d_target_versions (void);
 const char * rs6000_xcoff_strip_dollar (const char *);
 #endif
 
-void rs6000_final_prescan_insn (rtx_insn *, rtx *operand, int num_operands);
+/* Declare functions in rs6000-prefixed.c  */
+#ifdef RTX_CODE
+extern bool prefixed_load_p (rtx_insn *);
+extern bool prefixed_store_p (rtx_insn *);
+extern bool prefixed_paddi_p (rtx_insn *);
+extern void rs6000_asm_output_opcode (FILE *, const char *);
+void rs6000_final_prescan_insn (rtx_insn *);
+#endif
 
 extern unsigned char rs6000_class_max_nregs[][LIM_REG_CLASSES];
 extern unsigned char rs6000_hard_regno_nregs[][FIRST_PSEUDO_REGISTER];
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 274174)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -9815,6 +9815,17 @@ rs6000_emit_move (rtx dest, rtx source, machine_mo
 	  return;
 	}
 
+      /* Handle pc-relative addresses, either external symbols or internal
+	 within the function.  */
+      if (TARGET_PCREL)
+	{
+	  if (pcrel_addr_p (operands[1], true, true, PCREL_NULL))
+	    {
+	      emit_insn (gen_rtx_SET (operands[0], operands[1]));
+	      return;
+	    }
+	}
+
       if (DEFAULT_ABI == ABI_V4
 	  && mode == Pmode && mode == SImode
 	  && flag_pic == 1 && got_operand (operands[1], mode))
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 274173)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -2572,3 +2572,24 @@ typedef struct GTY(()) machine_function
   IN_RANGE ((VALUE),							\
 	    -(HOST_WIDE_INT_1 << 33),					\
 	    (HOST_WIDE_INT_1 << 33) - 1 - (EXTRA))
+
+/* Define this if some processing needs to be done before outputting the
+   assembler code.  On the PowerPC, we remember if the current insn is a normal
+   prefixed insn where we need to emit a 'p' before the insn.  */
+#define FINAL_PRESCAN_INSN(INSN, OPERANDS, NOPERANDS)			\
+do									\
+  {									\
+    if (TARGET_PREFIXED_ADDR)						\
+      rs6000_final_prescan_insn (INSN);					\
+  }									\
+while (0)
+
+/* Do anything special before emitting an opcode.  We use it to emit a 'p' for
+   prefixed insns that is set in FINAL_PRESCAN_INSN.  */
+#define ASM_OUTPUT_OPCODE(STREAM, OPCODE)				\
+  do									\
+    {									\
+     if (TARGET_PREFIXED_ADDR)						\
+       rs6000_asm_output_opcode (STREAM, OPCODE);			\
+    }									\
+  while (0)
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 274174)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -269,9 +269,48 @@
 			  x		; Indexed addressing
 			  prefixed])	; Prefixed instruction
 
-;; Length of the instruction (in bytes).
-(define_attr "length" "" (const_int 4))
+;; Whether an insn is a prefixed insn, and an initial 'p' should be printed
+;; before the instruction.  A prefixed instruction has a prefix instruction
+;; word that extends the immediate value of the instructions from 12-16 bits to
+;; 34 bits.  The macro ASM_OUTPUT_OPCODE emits a leading 'p' for prefixed
+;; insns.  The default "length" attribute will also be adjusted by default to
+;; be 12 bytes.
+(define_attr "prefixed" "no,yes"
+  (cond [(ior (match_test "!TARGET_PREFIXED_ADDR")
+	      (match_test "!NONJUMP_INSN_P (insn)"))
+	 (const_string "no")
 
+	 (eq_attr "type" "load,fpload,vecload")
+	 (if_then_else (match_test "prefixed_load_p (insn)")
+		       (const_string "yes")
+		       (const_string "no"))
+
+	 (eq_attr "type" "store,fpstore,vecstore")
+	 (if_then_else (match_test "prefixed_store_p (insn)")
+		       (const_string "yes")
+		       (const_string "no"))
+
+	 (eq_attr "type" "integer,add")
+	 (if_then_else (match_test "prefixed_paddi_p (insn)")
+		       (const_string "yes")
+		       (const_string "no"))]
+	(const_string "no")))
+
+;; Length in bytes of instructions that use prefixed addressing and length in
+;; bytes of instructions that does not use prefixed addressing.  This allows
+;; both lengths to be defined as constants, and the length attribute can pick
+;; the size as appropriate.
+(define_attr "prefixed_length" "" (const_int 12))
+(define_attr "non_prefixed_length" "" (const_int 4))
+
+;; Length of the instruction (in bytes).  Prefixed insns are 8 bytes, but the
+;; assembler might issue need to issue a NOP so that the prefixed instruction
+;; does not cross a cache boundary, which makes them possibly 12 bytes.
+(define_attr "length" ""
+  (if_then_else (eq_attr "prefixed" "yes")
+		(attr "prefixed_length")
+		(attr "non_prefixed_length")))
+
 ;; Processor type -- this attribute must exactly match the processor_type
 ;; enumeration in rs6000-opts.h.
 (define_attr "cpu"
@@ -9888,6 +9927,25 @@
   operands[6] = gen_rtx_PARALLEL (VOIDmode, p);
 })
 
+;; Load up a pc-relative address.  ASM_OUTPUT_OPCODE will emit the initial "p".
+(define_insn "*pcrel_addr"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r")
+	(match_operand:DI 1 "pcrel_address"))]
+  "TARGET_PCREL"
+  "la %0,%a1"
+  [(set_attr "prefixed" "yes")])
+
+;; Load up a pc-relative address to an external symbol.  If the symbol and the
+;; program are both defined in the main program, the linker will optimize this
+;; to a PADDI.  Otherwise, it will create a GOT address that is relocated by
+;; the dynamic linker and loaded up.
+(define_insn "*pcrel_ext_addr"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=b*r")
+	(match_operand:DI 1 "pcrel_external_address"))]
+  "TARGET_PCREL"
+  "ld %0,%a1"
+  [(set_attr "prefixed" "yes")])
+
 ;; TOC register handling.
 
 ;; Code to initialize the TOC register...
Index: gcc/config/rs6000/t-rs6000
===================================================================
--- gcc/config/rs6000/t-rs6000	(revision 274173)
+++ gcc/config/rs6000/t-rs6000	(working copy)
@@ -47,6 +47,10 @@ rs6000-call.o: $(srcdir)/config/rs6000/rs6000-call
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
+rs6000-prefixed.o: $(srcdir)/config/rs6000/rs6000-prefixed.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
 $(srcdir)/config/rs6000/rs6000-tables.opt: $(srcdir)/config/rs6000/genopt.sh \
   $(srcdir)/config/rs6000/rs6000-cpus.def
 	$(SHELL) $(srcdir)/config/rs6000/genopt.sh $(srcdir)/config/rs6000 > \
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 274173)
+++ gcc/config.gcc	(working copy)
@@ -500,6 +500,7 @@ or1k*-*-*)
 powerpc*-*-*)
 	cpu_type=rs6000
 	extra_objs="rs6000-string.o rs6000-p8swap.o rs6000-logue.o rs6000-call.o"
+	extra_objs="${extra_objs} rs6000-prefixed.o"
 	extra_headers="ppc-asm.h altivec.h htmintrin.h htmxlintrin.h"
 	extra_headers="${extra_headers} bmi2intrin.h bmiintrin.h"
 	extra_headers="${extra_headers} xmmintrin.h mm_malloc.h emmintrin.h"
@@ -514,6 +515,7 @@ powerpc*-*-*)
 	esac
 	extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"
 	target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-logue.c \$(srcdir)/config/rs6000/rs6000-call.c"
+	target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-prefixed.c"
 	;;
 pru-*-*)
 	cpu_type=pru
@@ -526,7 +528,9 @@ riscv*)
 rs6000*-*-*)
 	extra_options="${extra_options} g.opt fused-madd.opt rs6000/rs6000-tables.opt"
 	extra_objs="rs6000-string.o rs6000-p8swap.o rs6000-logue.o rs6000-call.o"
+	extra_objs="${extra_objs} rs6000-prefixed.o"
 	target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-logue.c \$(srcdir)/config/rs6000/rs6000-call.c"
+	target_gtfiles="$target_gtfiles \$(srcdir)/config/rs6000/rs6000-prefixed.c"
 	;;
 sparc*-*-*)
 	cpu_type=sparc
