Index: gcc/config/rs6000/pcrel-opt.c
===================================================================
--- gcc/config/rs6000/pcrel-opt.c	(revision 278315)
+++ gcc/config/rs6000/pcrel-opt.c	(working copy)
@@ -223,6 +223,27 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
   rtx mem_inner = mem;
   unsigned int reg_regno = reg_or_subregno (reg);
 
+  // LWA is a DS format instruction, but LWZ is a D format instruction.  We use
+  // DImode for the mode to force checking whether the bottom 2 bits are 0.
+  // However FPR and vector registers uses the LFIWAX instruction which is
+  // indexed only.
+  if (GET_CODE (mem) == SIGN_EXTEND && GET_MODE (XEXP (mem, 0)) == SImode)
+    {
+      if (!INT_REGNO_P (reg_regno))
+	return false;
+
+      mem_inner = XEXP (mem, 0);
+      mem_mode = DImode;
+    }
+
+  else if (GET_CODE (mem) == SIGN_EXTEND
+	   || GET_CODE (mem) == ZERO_EXTEND
+	   || GET_CODE (mem) == FLOAT_EXTEND)
+    {
+      mem_inner = XEXP (mem, 0);
+      mem_mode = GET_MODE (mem_inner);
+    }
+
   if (!MEM_P (mem_inner))
     return false;
 
@@ -275,8 +296,9 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
       return false;
     }
 
-  // Update the load insn.  Add an explicit clobber of the GOT register just in
-  // case something runs after this pass.
+  // Update the load insn.  If the mem had a sign/zero/float extend, add that
+  // also after doing the UNSPEC.  Add an explicit clobber of the GOT register
+  // just in case something runs after this pass.
   //
   // (parallel [(set (reg)
   //                 (unspec:<MODE> [(mem (got)
@@ -288,6 +310,9 @@ pcrel_opt::do_pcrel_opt_load (rtx_insn *
   rtx new_load = gen_rtx_UNSPEC (GET_MODE (mem_inner), v_load,
 				 UNSPEC_PCREL_OPT_LD_RELOC);
 
+  if (GET_CODE (mem) != GET_CODE (mem_inner))
+    new_load = gen_rtx_fmt_e (GET_CODE (mem), reg_mode, new_load);
+
   rtx old_load_set = PATTERN (load_insn);
   rtx new_load_set = gen_rtx_SET (reg, new_load);
   rtx load_clobber = gen_rtx_CLOBBER (VOIDmode,
@@ -484,11 +509,21 @@ pcrel_opt::do_pcrel_opt_got_addr (rtx_in
     {
       reg = SET_DEST (load_set);
       mem = SET_SRC (load_set);
-      if (!MEM_P (mem))
-	return;
+      switch (GET_CODE (mem))
+	{
+	case MEM:
+	  break;
 
-      if (!REG_P (reg) && !SUBREG_P (reg))
-	return;
+	case SIGN_EXTEND:
+	case ZERO_EXTEND:
+	case FLOAT_EXTEND:
+	  if (!MEM_P (XEXP (mem, 0)))
+	    return;
+	  break;
+
+	default:
+	  return;
+	}
 
       // If there were any stores in the insns between loading the GOT address
       // and doing the load, turn off the optimization.
@@ -499,6 +534,9 @@ pcrel_opt::do_pcrel_opt_got_addr (rtx_in
   else
     return;
 
+  if (!REG_P (reg) && !SUBREG_P (reg))
+    return;
+
   machine_mode mode = GET_MODE (reg);
   unsigned int regno = reg_or_subregno (reg);
   unsigned int size = GET_MODE_SIZE (mode);
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 278315)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -14813,6 +14813,61 @@ (define_insn "*pcrel_opt_ld<mode>"
   "%r2l<wd>z %0,%1"
   [(set_attr "type" "load")])
 
+(define_insn "*pcrel_opt_ldsi_sext<mode>"
+  [(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r")
+	(sign_extend:EXTSI
+	 (unspec:SI [(match_operand:SI 1 "non_prefixed_memory" "o")
+		     (match_operand 2 "const_int_operand" "n")]
+		    UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX"))]
+  "TARGET_PCREL_OPT"
+  "%r2lwa %0,%1"
+  [(set_attr "type" "load")])
+
+(define_insn "*pcrel_opt_ldhi_sext<mode>"
+  [(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r")
+	(sign_extend:EXTHI
+	 (unspec:HI [(match_operand:HI 1 "non_prefixed_memory" "o")
+		     (match_operand 2 "const_int_operand" "n")]
+		    UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX"))]
+  "TARGET_PCREL_OPT"
+  "%r2lha %0,%1"
+  [(set_attr "type" "load")])
+
+(define_insn "*pcrel_opt_ldsi_zext<mode>"
+  [(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r")
+	(zero_extend:EXTSI
+	 (unspec:SI [(match_operand:SI 1 "non_prefixed_memory" "o")
+		     (match_operand 2 "const_int_operand" "n")]
+		    UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX"))]
+  "TARGET_PCREL_OPT"
+  "%r2lwz %0,%1"
+  [(set_attr "type" "load")])
+
+(define_insn "*pcrel_opt_ldhi_zext<mode>"
+  [(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r")
+	(zero_extend:EXTHI
+	 (unspec:HI [(match_operand:HI 1 "non_prefixed_memory" "o")
+		     (match_operand 2 "const_int_operand" "n")]
+		    UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX"))]
+  "TARGET_PCREL_OPT"
+  "%r2lhz %0,%1"
+  [(set_attr "type" "load")])
+
+(define_insn "*pcrel_opt_ldqi_zext<mode>"
+  [(set (match_operand:EXTQI 0 "gpc_reg_operand" "=r")
+	(zero_extend:EXTQI
+	 (unspec:QI [(match_operand:QI 1 "non_prefixed_memory" "o")
+		     (match_operand 2 "const_int_operand" "n")]
+		    UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX"))]
+  "TARGET_PCREL_OPT"
+  "%r2lbz %0,%1"
+  [(set_attr "type" "load")])
+
 (define_insn "*pcrel_opt_lddi"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r,d,v")
 	(unspec:DI [(match_operand:DI 1 "non_prefixed_memory" "o,o,o")
@@ -14839,6 +14894,19 @@ (define_insn "*pcrel_opt_ldsf"
    %r2lwz %0,%1"
   [(set_attr "type" "fpload,fpload,load")])
 
+(define_insn "*pcrel_opt_ldsf_extend"
+  [(set (match_operand:DF 0 "gpc_reg_operand" "=d,v")
+	(float_extend:DF
+	 (unspec:SF [(match_operand:SF 1 "non_prefixed_memory" "o,o")
+		     (match_operand 2 "const_int_operand" "n,n")]
+		    UNSPEC_PCREL_OPT_LD_RELOC)))
+   (clobber (match_scratch:DI 3 "=bX,bX"))]
+  "TARGET_PCREL_OPT"
+  "@
+   %r2lfs %0,%1
+   %r2lxssp %0,%1"
+  [(set_attr "type" "fpload")])
+
 (define_insn "*pcrel_opt_lddf"
   [(set (match_operand:DF 0 "gpc_reg_operand" "=d,v,r")
 	(unspec:DF [(match_operand:DF 1 "non_prefixed_memory" "o,o,o")
