diff --git a/gcc/calls.c b/gcc/calls.c
index 4285ec1..85dae6b 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1122,6 +1122,14 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
     call_expr_arg_iterator iter;
     tree arg;
 
+    if (targetm.calls.implicit_pic_arg (fndecl ? fndecl : fntype))
+      {
+	gcc_assert (pic_offset_table_rtx);
+	args[j].tree_value = make_tree (ptr_type_node,
+					pic_offset_table_rtx);
+	j--;
+      }
+
     if (struct_value_addr_value)
       {
 	args[j].tree_value = struct_value_addr_value;
@@ -2520,6 +2528,10 @@ expand_call (tree exp, rtx target, int ignore)
     /* Treat all args as named.  */
     n_named_args = num_actuals;
 
+  /* Add implicit PIC arg.  */
+  if (targetm.calls.implicit_pic_arg (fndecl ? fndecl : fntype))
+    num_actuals++;
+
   /* Make a vector to hold all the information about each arg.  */
   args = XALLOCAVEC (struct arg_data, num_actuals);
   memset (args, 0, num_actuals * sizeof (struct arg_data));
@@ -3133,6 +3145,8 @@ expand_call (tree exp, rtx target, int ignore)
 	{
 	  int arg_nr = return_flags & ERF_RETURN_ARG_MASK;
 	  arg_nr = num_actuals - arg_nr - 1;
+	  if (targetm.calls.implicit_pic_arg (fndecl ? fndecl : fntype))
+	    arg_nr--;
 	  if (arg_nr >= 0
 	      && arg_nr < num_actuals
 	      && args[arg_nr].reg
@@ -3700,8 +3714,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
      of the full argument passing conventions to limit complexity here since
      library functions shouldn't have many args.  */
 
-  argvec = XALLOCAVEC (struct arg, nargs + 1);
-  memset (argvec, 0, (nargs + 1) * sizeof (struct arg));
+  argvec = XALLOCAVEC (struct arg, nargs + 2);
+  memset (argvec, 0, (nargs + 2) * sizeof (struct arg));
 
 #ifdef INIT_CUMULATIVE_LIBCALL_ARGS
   INIT_CUMULATIVE_LIBCALL_ARGS (args_so_far_v, outmode, fun);
@@ -3717,6 +3731,23 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
 
   push_temp_slots ();
 
+  if (targetm.calls.implicit_pic_arg (fndecl ? fndecl : fntype))
+    {
+      gcc_assert (pic_offset_table_rtx);
+
+      argvec[count].value = pic_offset_table_rtx;
+      argvec[count].mode = Pmode;
+      argvec[count].partial = 0;
+
+      argvec[count].reg = targetm.calls.function_arg (args_so_far,
+						      Pmode, NULL_TREE, true);
+
+      targetm.calls.function_arg_advance (args_so_far, Pmode, NULL_TREE, true);
+
+      count++;
+      nargs++;
+    }
+
   /* If there's a structure value address to be passed,
      either pass it in the special place, or pass it as an extra argument.  */
   if (mem_value && struct_value == 0 && ! pcc_struct_value)
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index cc4b0c7..cfafcdd 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -6133,6 +6133,21 @@ ix86_maybe_switch_abi (void)
     reinit_regs ();
 }
 
+/* Return reg in which implicit PIC base address
+   arg is passed.  */
+static rtx
+ix86_implicit_pic_arg (const_tree fntype_or_decl ATTRIBUTE_UNUSED)
+{
+  if ((TARGET_64BIT
+       && (ix86_cmodel == CM_SMALL_PIC
+	   || TARGET_PECOFF))
+      || !flag_pic
+      || !X86_TUNE_RELAX_PIC_REG)
+    return NULL_RTX;
+
+  return gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM);
+}
+
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0.  */
@@ -6198,6 +6213,11 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
 		      ? (!prototype_p (fntype) || stdarg_p (fntype))
 		      : !libname);
 
+  if (caller)
+    cum->implicit_pic_arg = ix86_implicit_pic_arg (fndecl ? fndecl : fntype);
+  else
+    cum->implicit_pic_arg = NULL_RTX;
+
   if (!TARGET_64BIT)
     {
       /* If there are variable arguments, then we won't pass anything
@@ -7291,7 +7311,9 @@ ix86_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
   if (type)
     mode = type_natural_mode (type, NULL, false);
 
-  if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
+  if (cum->implicit_pic_arg)
+    cum->implicit_pic_arg = NULL_RTX;
+  else if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
     function_arg_advance_ms_64 (cum, bytes, words);
   else if (TARGET_64BIT)
     function_arg_advance_64 (cum, mode, type, words, named);
@@ -7542,7 +7564,9 @@ ix86_function_arg (cumulative_args_t cum_v, enum machine_mode omode,
   if (type && TREE_CODE (type) == VECTOR_TYPE)
     mode = type_natural_mode (type, cum, false);
 
-  if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
+  if (cum->implicit_pic_arg)
+    arg = cum->implicit_pic_arg;
+  else if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI)
     arg = function_arg_ms_64 (cum, mode, omode, named, bytes);
   else if (TARGET_64BIT)
     arg = function_arg_64 (cum, mode, omode, type, named);
@@ -9373,6 +9397,9 @@ gen_pop (rtx arg)
 static unsigned int
 ix86_select_alt_pic_regnum (void)
 {
+  if (ix86_implicit_pic_arg (NULL))
+    return INVALID_REGNUM;
+
   if (crtl->is_leaf
       && !crtl->profile
       && !ix86_current_function_calls_tls_descriptor)
@@ -11236,7 +11263,8 @@ ix86_expand_prologue (void)
 	}
       else
 	{
-          insn = emit_insn (gen_set_got (pic_offset_table_rtx));
+	  rtx reg = gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM);
+          insn = emit_insn (gen_set_got (reg));
 	  RTX_FRAME_RELATED_P (insn) = 1;
 	  add_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL_RTX);
 	}
@@ -11789,7 +11817,8 @@ ix86_expand_epilogue (int style)
 static void
 ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT)
 {
-  if (pic_offset_table_rtx)
+  if (pic_offset_table_rtx
+      && REGNO (pic_offset_table_rtx) < FIRST_PSEUDO_REGISTER)
     SET_REGNO (pic_offset_table_rtx, REAL_PIC_OFFSET_TABLE_REGNUM);
 #if TARGET_MACHO
   /* Mach-O doesn't support labels at the end of objects, so if
@@ -13107,6 +13136,15 @@ ix86_GOT_alias_set (void)
   return set;
 }
 
+/* Set regs_ever_live for PIC base address register
+   to true if required.  */
+static void
+set_pic_reg_ever_alive ()
+{
+  if (reload_in_progress)
+    df_set_regs_ever_live (REGNO (pic_offset_table_rtx), true);
+}
+
 /* Return a legitimate reference for ORIG (an address) using the
    register REG.  If REG is 0, a new pseudo is generated.
 
@@ -13157,8 +13195,7 @@ legitimize_pic_address (rtx orig, rtx reg)
       /* This symbol may be referenced via a displacement from the PIC
 	 base address (@GOTOFF).  */
 
-      if (reload_in_progress)
-	df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+      set_pic_reg_ever_alive ();
       if (GET_CODE (addr) == CONST)
 	addr = XEXP (addr, 0);
       if (GET_CODE (addr) == PLUS)
@@ -13190,8 +13227,7 @@ legitimize_pic_address (rtx orig, rtx reg)
       /* This symbol may be referenced via a displacement from the PIC
 	 base address (@GOTOFF).  */
 
-      if (reload_in_progress)
-	df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+      set_pic_reg_ever_alive ();
       if (GET_CODE (addr) == CONST)
 	addr = XEXP (addr, 0);
       if (GET_CODE (addr) == PLUS)
@@ -13252,8 +13288,7 @@ legitimize_pic_address (rtx orig, rtx reg)
 	  /* This symbol must be referenced via a load from the
 	     Global Offset Table (@GOT).  */
 
-	  if (reload_in_progress)
-	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+	  set_pic_reg_ever_alive ();
 	  new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
 	  new_rtx = gen_rtx_CONST (Pmode, new_rtx);
 	  if (TARGET_64BIT)
@@ -13305,8 +13340,7 @@ legitimize_pic_address (rtx orig, rtx reg)
 	    {
 	      if (!TARGET_64BIT)
 		{
-		  if (reload_in_progress)
-		    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+		  set_pic_reg_ever_alive ();
 		  new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
 					    UNSPEC_GOTOFF);
 		  new_rtx = gen_rtx_PLUS (Pmode, new_rtx, op1);
@@ -13601,8 +13635,7 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov)
 	}
       else if (flag_pic)
 	{
-	  if (reload_in_progress)
-	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+	  set_pic_reg_ever_alive ();
 	  pic = pic_offset_table_rtx;
 	  type = TARGET_ANY_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF;
 	}
@@ -14233,6 +14266,8 @@ ix86_pic_register_p (rtx x)
   if (GET_CODE (x) == VALUE && CSELIB_VAL_PTR (x))
     return (pic_offset_table_rtx
 	    && rtx_equal_for_cselib_p (x, pic_offset_table_rtx));
+  else if (pic_offset_table_rtx)
+    return REG_P (x) && REGNO (x) == REGNO (pic_offset_table_rtx);
   else
     return REG_P (x) && REGNO (x) == PIC_OFFSET_TABLE_REGNUM;
 }
@@ -14408,7 +14443,9 @@ ix86_delegitimize_address (rtx x)
 	 ...
 	 movl foo@GOTOFF(%ecx), %edx
 	 in which case we return (%ecx - %ebx) + foo.  */
-      if (pic_offset_table_rtx)
+      if (pic_offset_table_rtx
+	  && (!reload_completed
+	      || REGNO (pic_offset_table_rtx) < FIRST_PSEUDO_REGISTER))
         result = gen_rtx_PLUS (Pmode, gen_rtx_MINUS (Pmode, copy_rtx (addend),
 						     pic_offset_table_rtx),
 			       result);
@@ -24915,7 +24952,7 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
 		  && DEFAULT_ABI != MS_ABI))
 	  && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
 	  && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0)))
-	use_reg (&use, pic_offset_table_rtx);
+	use_reg (&use, gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM));
     }
 
   if (TARGET_64BIT && INTVAL (callarg2) >= 0)
@@ -47228,6 +47265,8 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
 #define TARGET_FUNCTION_ARG_ADVANCE ix86_function_arg_advance
 #undef TARGET_FUNCTION_ARG
 #define TARGET_FUNCTION_ARG ix86_function_arg
+#undef TARGET_IMPLICIT_PIC_ARG
+#define TARGET_IMPLICIT_PIC_ARG ix86_implicit_pic_arg
 #undef TARGET_FUNCTION_ARG_BOUNDARY
 #define TARGET_FUNCTION_ARG_BOUNDARY ix86_function_arg_boundary
 #undef TARGET_PASS_BY_REFERENCE
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 2c64162..d5fa250 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1243,11 +1243,13 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
 
 #define REAL_PIC_OFFSET_TABLE_REGNUM  BX_REG
 
-#define PIC_OFFSET_TABLE_REGNUM				\
-  ((TARGET_64BIT && (ix86_cmodel == CM_SMALL_PIC	\
-                     || TARGET_PECOFF))		\
-   || !flag_pic ? INVALID_REGNUM			\
-   : reload_completed ? REGNO (pic_offset_table_rtx)	\
+#define PIC_OFFSET_TABLE_REGNUM						\
+  ((TARGET_64BIT && (ix86_cmodel == CM_SMALL_PIC			\
+                     || TARGET_PECOFF))					\
+   || !flag_pic ? INVALID_REGNUM					\
+   : X86_TUNE_RELAX_PIC_REG ? (pic_offset_table_rtx ? INVALID_REGNUM	\
+			       : REAL_PIC_OFFSET_TABLE_REGNUM)		\
+   : reload_completed ? REGNO (pic_offset_table_rtx)			\
    : REAL_PIC_OFFSET_TABLE_REGNUM)
 
 #define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_"
@@ -1652,6 +1654,7 @@ typedef struct ix86_args {
   int float_in_sse;		/* Set to 1 or 2 for 32bit targets if
 				   SFmode/DFmode arguments should be passed
 				   in SSE registers.  Otherwise 0.  */
+  rtx implicit_pic_arg;         /* Implicit PIC base address arg if passed.  */
   enum calling_abi call_abi;	/* Set to SYSV_ABI for sysv abi. Otherwise
  				   MS_ABI for ms abi.  */
 } CUMULATIVE_ARGS;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 8e74eab..27028ba 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -2725,7 +2725,7 @@
 
 (define_insn "*pushtf"
   [(set (match_operand:TF 0 "push_operand" "=<,<")
-	(match_operand:TF 1 "general_no_elim_operand" "x,*roF"))]
+	(match_operand:TF 1 "nonimmediate_no_elim_operand" "x,*roF"))]
   "TARGET_64BIT || TARGET_SSE"
 {
   /* This insn should be already split before reg-stack.  */
@@ -2750,7 +2750,7 @@
 
 (define_insn "*pushxf"
   [(set (match_operand:XF 0 "push_operand" "=<,<")
-	(match_operand:XF 1 "general_no_elim_operand" "f,Yx*roF"))]
+	(match_operand:XF 1 "nonimmediate_no_elim_operand" "f,Yx*roF"))]
   ""
 {
   /* This insn should be already split before reg-stack.  */
@@ -2781,7 +2781,7 @@
 
 (define_insn "*pushdf"
   [(set (match_operand:DF 0 "push_operand" "=<,<,<,<")
-	(match_operand:DF 1 "general_no_elim_operand" "f,Yd*roF,rmF,x"))]
+	(match_operand:DF 1 "nonimmediate_no_elim_operand" "f,Yd*roF,rmF,x"))]
   ""
 {
   /* This insn should be already split before reg-stack.  */
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index 62970be..56eca24 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -580,6 +580,12 @@
     (match_operand 0 "register_no_elim_operand")
     (match_operand 0 "general_operand")))
 
+;; Return false if this is any eliminable register.  Otherwise nonimmediate_operand.
+(define_predicate "nonimmediate_no_elim_operand"
+  (if_then_else (match_code "reg,subreg")
+    (match_operand 0 "register_no_elim_operand")
+    (match_operand 0 "nonimmediate_operand")))
+
 ;; Return false if this is any eliminable register.  Otherwise
 ;; register_operand or a constant.
 (define_predicate "nonmemory_no_elim_operand"
diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
index 215c63c..ffb7a2d 100644
--- a/gcc/config/i386/x86-tune.def
+++ b/gcc/config/i386/x86-tune.def
@@ -537,3 +537,6 @@ DEF_TUNE (X86_TUNE_PROMOTE_QI_REGS, "promote_qi_regs", 0)
    unrolling small loop less important. For, such architectures we adjust
    the unroll factor so that the unrolled loop fits the loop buffer.  */
 DEF_TUNE (X86_TUNE_ADJUST_UNROLL, "adjust_unroll_factor", m_BDVER3 | m_BDVER4)
+
+/* X86_TUNE_RELAX_PIC_REG: Do not fix hard register for GOT base usage.  */
+DEF_TUNE (X86_TUNE_RELAX_PIC_REG, "relax_pic_reg", ~0)
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 9dd8d68..33b36be 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3967,6 +3967,12 @@ If @code{TARGET_FUNCTION_INCOMING_ARG} is not defined,
 @code{TARGET_FUNCTION_ARG} serves both purposes.
 @end deftypefn
 
+@deftypefn {Target Hook} rtx TARGET_IMPLICIT_PIC_ARG (const_tree @var{fntype_or_decl})
+This hook returns register holding PIC base address for functions
+which do not fix hard register but handle it similar to function arg
+assigning a virtual reg for it.
+@end deftypefn
+
 @deftypefn {Target Hook} int TARGET_ARG_PARTIAL_BYTES (cumulative_args_t @var{cum}, enum machine_mode @var{mode}, tree @var{type}, bool @var{named})
 This target hook returns the number of bytes at the beginning of an
 argument that must be put in registers.  The value must be zero for
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index dd72b98..3e6da2f 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -3413,6 +3413,8 @@ the stack.
 
 @hook TARGET_FUNCTION_INCOMING_ARG
 
+@hook TARGET_IMPLICIT_PIC_ARG
+
 @hook TARGET_ARG_PARTIAL_BYTES
 
 @hook TARGET_PASS_BY_REFERENCE
diff --git a/gcc/function.c b/gcc/function.c
index 8156766..3a85c16 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -3456,6 +3456,15 @@ assign_parms (tree fndecl)
 
   fnargs.release ();
 
+  /* Handle implicit PIC arg if any.  */
+  if (targetm.calls.implicit_pic_arg (fndecl))
+    {
+      rtx old_reg = targetm.calls.implicit_pic_arg (fndecl);
+      rtx new_reg = gen_reg_rtx (GET_MODE (old_reg));
+      emit_move_insn (new_reg, old_reg);
+      pic_offset_table_rtx = new_reg;
+    }
+
   /* Output all parameter conversion instructions (possibly including calls)
      now that all parameters have been copied out of hard registers.  */
   emit_insn (all.first_conversion_insn);
diff --git a/gcc/hooks.c b/gcc/hooks.c
index 5c06562..47784e2 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -352,6 +352,13 @@ hook_rtx_rtx_null (rtx x ATTRIBUTE_UNUSED)
   return NULL;
 }
 
+/* Generic hook that takes a const_tree arg and returns NULL_RTX.  */
+rtx
+hook_rtx_const_tree_null (const_tree a ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
 /* Generic hook that takes a tree and an int and returns NULL_RTX.  */
 rtx
 hook_rtx_tree_int_null (tree a ATTRIBUTE_UNUSED, int b ATTRIBUTE_UNUSED)
diff --git a/gcc/hooks.h b/gcc/hooks.h
index ba42b6c..cf830ef 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -100,6 +100,7 @@ extern bool default_can_output_mi_thunk_no_vcall (const_tree, HOST_WIDE_INT,
 
 extern rtx hook_rtx_rtx_identity (rtx);
 extern rtx hook_rtx_rtx_null (rtx);
+extern rtx hook_rtx_const_tree_null (const_tree);
 extern rtx hook_rtx_tree_int_null (tree, int);
 
 extern const char *hook_constcharptr_void_null (void);
diff --git a/gcc/ira.c b/gcc/ira.c
index 3f41061..dc2eaed 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3467,6 +3467,11 @@ update_equiv_regs (void)
 	  if (note && GET_CODE (XEXP (note, 0)) == EXPR_LIST)
 	    note = NULL_RTX;
 
+	  if (pic_offset_table_rtx
+	      && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER
+	      && contains_symbol_ref (insn))
+	    note = NULL_RTX;
+
 	  if (DF_REG_DEF_COUNT (regno) != 1
 	      && (! note
 		  || rtx_varies_p (XEXP (note, 0), 0)
@@ -3512,6 +3517,10 @@ update_equiv_regs (void)
 	      && MEM_P (SET_SRC (set))
 	      && validate_equiv_mem (insn, dest, SET_SRC (set)))
 	    note = set_unique_reg_note (insn, REG_EQUIV, copy_rtx (SET_SRC (set)));
+	  if (pic_offset_table_rtx
+	      && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER
+	      && contains_symbol_ref (insn))
+	    note = NULL_RTX;
 
 	  if (note)
 	    {
@@ -3886,11 +3895,19 @@ setup_reg_equiv (void)
 		      /* This is PLUS of frame pointer and a constant,
 			 or fp, or argp.  */
 		      ira_reg_equiv[i].invariant = x;
-		    else if (targetm.legitimate_constant_p (mode, x))
+		    else if (targetm.legitimate_constant_p (mode, x)
+			     && (!pic_offset_table_rtx
+				 || REGNO (pic_offset_table_rtx) < FIRST_PSEUDO_REGISTER
+				 || (GET_CODE (x) != CONST_DOUBLE
+				     && GET_CODE (x) != CONST_VECTOR)))
 		      ira_reg_equiv[i].constant = x;
 		    else
 		      {
 			ira_reg_equiv[i].memory = force_const_mem (mode, x);
+			if (pic_offset_table_rtx
+			    && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER
+			    && contains_symbol_ref (ira_reg_equiv[i].memory))
+			  ira_reg_equiv[i].memory = NULL_RTX;
 			if (ira_reg_equiv[i].memory == NULL_RTX)
 			  {
 			    ira_reg_equiv[i].defined_p = false;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index b6a21b6..02fcf96 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2610,6 +2610,7 @@ extern int rtx_referenced_p (rtx, rtx);
 extern bool tablejump_p (const_rtx, rtx *, rtx_jump_table_data **);
 extern int computed_jump_p (const_rtx);
 extern bool tls_referenced_p (rtx);
+extern bool contains_symbol_ref (rtx);
 
 typedef int (*rtx_function) (rtx *, void *);
 extern int for_each_rtx (rtx *, rtx_function, void *);
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index bc16437..21f2872 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -110,7 +110,8 @@ rtx_unstable_p (const_rtx x)
       /* ??? When call-clobbered, the value is stable modulo the restore
 	 that must happen after a call.  This currently screws up local-alloc
 	 into believing that the restore is not needed.  */
-      if (!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED && x == pic_offset_table_rtx)
+      if (!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED && x == pic_offset_table_rtx
+	  && REGNO (pic_offset_table_rtx) < FIRST_PSEUDO_REGISTER)
 	return 0;
       return 1;
 
@@ -185,7 +186,9 @@ rtx_varies_p (const_rtx x, bool for_alias)
 	     that must happen after a call.  This currently screws up
 	     local-alloc into believing that the restore is not needed, so we
 	     must return 0 only if we are called from alias analysis.  */
-	  && (!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED || for_alias))
+	  && ((!PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
+	       && REGNO (pic_offset_table_rtx) < FIRST_PSEUDO_REGISTER)
+	      || for_alias))
 	return 0;
       return 1;
 
@@ -5978,6 +5981,42 @@ get_index_code (const struct address_info *info)
   return SCRATCH;
 }
 
+/* Return true if RTL X contains a SYMBOL_REF.  */
+
+bool
+contains_symbol_ref (rtx x)
+{
+  const char *fmt;
+  RTX_CODE code;
+  int i;
+
+  if (!x)
+    return false;
+
+  code = GET_CODE (x);
+  if (code == SYMBOL_REF)
+    return true;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+	{
+	  if (contains_symbol_ref (XEXP (x, i)))
+	    return true;
+	}
+      else if (fmt[i] == 'E')
+	{
+	  int j;
+	  for (j = 0; j < XVECLEN (x, i); j++)
+	    if (contains_symbol_ref (XVECEXP (x, i, j)))
+	      return true;
+	}
+    }
+
+  return false;
+}
+
 /* Return 1 if *X is a thread-local symbol.  */
 
 static int
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index 5c34fee..50de8d5 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -448,7 +448,7 @@ try_shrink_wrapping (edge *entry_edge, edge orig_entry_edge,
     {
       HARD_REG_SET prologue_clobbered, prologue_used, live_on_edge;
       struct hard_reg_set_container set_up_by_prologue;
-      rtx p_insn;
+      rtx p_insn, reg;
       vec<basic_block> vec;
       basic_block bb;
       bitmap_head bb_antic_flags;
@@ -494,9 +494,13 @@ try_shrink_wrapping (edge *entry_edge, edge orig_entry_edge,
       if (frame_pointer_needed)
 	add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
 			     HARD_FRAME_POINTER_REGNUM);
-      if (pic_offset_table_rtx)
+      if (pic_offset_table_rtx
+	  && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
 	add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
 			     PIC_OFFSET_TABLE_REGNUM);
+      if ((reg = targetm.calls.implicit_pic_arg (current_function_decl)))
+	add_to_hard_reg_set (&set_up_by_prologue.set,
+			     Pmode, REGNO (reg));
       if (crtl->drap_reg)
 	add_to_hard_reg_set (&set_up_by_prologue.set,
 			     GET_MODE (crtl->drap_reg),
diff --git a/gcc/target.def b/gcc/target.def
index 3a41db1..5c221b6 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -3976,6 +3976,14 @@ If @code{TARGET_FUNCTION_INCOMING_ARG} is not defined,\n\
  default_function_incoming_arg)
 
 DEFHOOK
+(implicit_pic_arg,
+ "This hook returns register holding PIC base address for functions\n\
+which do not fix hard register but handle it similar to function arg\n\
+assigning a virtual reg for it.",
+ rtx, (const_tree fntype_or_decl),
+ hook_rtx_const_tree_null)
+
+DEFHOOK
 (function_arg_boundary,
  "This hook returns the alignment boundary, in bits, of an argument\n\
 with the specified mode and type.  The default hook returns\n\
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index a458380..63d2be5 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -661,7 +661,6 @@ static bool variable_different_p (variable, variable);
 static bool dataflow_set_different (dataflow_set *, dataflow_set *);
 static void dataflow_set_destroy (dataflow_set *);
 
-static bool contains_symbol_ref (rtx);
 static bool track_expr_p (tree, bool);
 static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
 static int add_uses (rtx *, void *);
@@ -5032,42 +5031,6 @@ dataflow_set_destroy (dataflow_set *set)
   set->vars = NULL;
 }
 
-/* Return true if RTL X contains a SYMBOL_REF.  */
-
-static bool
-contains_symbol_ref (rtx x)
-{
-  const char *fmt;
-  RTX_CODE code;
-  int i;
-
-  if (!x)
-    return false;
-
-  code = GET_CODE (x);
-  if (code == SYMBOL_REF)
-    return true;
-
-  fmt = GET_RTX_FORMAT (code);
-  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-    {
-      if (fmt[i] == 'e')
-	{
-	  if (contains_symbol_ref (XEXP (x, i)))
-	    return true;
-	}
-      else if (fmt[i] == 'E')
-	{
-	  int j;
-	  for (j = 0; j < XVECLEN (x, i); j++)
-	    if (contains_symbol_ref (XVECEXP (x, i, j)))
-	      return true;
-	}
-    }
-
-  return false;
-}
-
 /* Shall EXPR be tracked?  */
 
 static bool
