OSDN Git Service

* PA PIC support.
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 11 Nov 1994 04:33:43 +0000 (04:33 +0000)
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 11 Nov 1994 04:33:43 +0000 (04:33 +0000)
* pa.c (secondary_reload_class): Refine.  Readonly data needs a
secondary reload only during PIC generation.  Loading a floating
point register with a constant requires a register from R1_REGS
during -fPIC code generation.
(read_only_operand): Constant pool entries are no longer read only
during PIC code generation.
(hppa_legitimize_address): If flag_pic is nonzero, then
immediately call legitimize_pic_address.
(emit_move_sequence): Call legitimize_pic_address to handle
constant data.  Handle secondary reloads for PIC.  Use
pic_label_operand rather than open coding the test.  Handle
loading a LABEL_REF when generating PIC.
(legitimzie_pic_address): Handle constant data addressing for PIC
here.   Fix loading of symbolic addresses for -fPIC generation.
(pic_label_operand): Renamed from pic_operand.  Handle any read
only operand (such as constant data).  Reject function addresses,
Accept SYMBOL_REF with the read-only bit set.  Generalize to
handle (const (plus (reg) (int))).
(finalize_pic): Delete unused function.
(check_pic): Delete function.
(pic_pc_rtx): Delete variable definition.
(current_function_uses_pic_offset_table): Delete extern decl.
(force_reg, validize_mem): Likewise.
        (output_global_address): Don't tack on "-$global$" when generating
        PIC code.
(finalize_pic): Don't emit code for initialization of
hppa_save_pic_table_rtx here.  Don't claim we USE
pic_offset_table_rtx at function end.
* pa.h (SELECT_RTX_SECTION): Define.  During PIC generation
everything (in the constant pool) goes into the data space.
(PRINT_OPERAND_ADDRESS): Handle CONST_INTs during PIC
generation.  Handle LO_SUM address during -fPIC generation.
(LEGITIMATE_CONSTANT_P): Reject function labels when generating
PIC code.
(GO_IF_LEGITIMATE_ADDRESS): Only accept pic_reg + SYMBOL_REF for
-fpic.
(EXTRA_SECTION_FUNCTIONS): For -fpic, use the TEXT section for
constants to avoid GAS lossage.
(OVERRIDE_OPTIONS): Delete.
(PIC_OFFSET_TABLE_REG_CALL_CLOBBERED): Define.
(FINALIZE_PIC): Delete definition.
(INIT_EXPANDERS): Define.  Clear hppa_save_pic_table_rtx here.
* pa.md: Use !flag_pic rather than calling check_pic.
(HImode high and lo_sum): Only accept const_int_operands.
(pic_load_label): Force output to be in %r1.
(pic_highpart): New pattern.  Output must go into %r1.  More
linker trickery.
(symbolic high and lo_sum): Disallow during PIC generation if
source is a symbolic operand.  Handle CONST_INT LO_SUM during PIC
generation.  Simplify.
(define_split for symbolic_operand load): Do not accept a symbolic
operand that is a pic_label_operand.
(pic_load_label): Name this pattern.  Mask least significant bits
and optimize when a simple label is within reach of an ldo.
(call, call_value): Emit new-style USE information for
pic_offset_table_rtx.  Emit code for initialization of
hppa_save_pic_table_rtx and wrap it into push_topmost_sequence()
and pop_topmost_sequence() calls.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@8419 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/pa/pa.c
gcc/config/pa/pa.h
gcc/config/pa/pa.md

index 168cf0c..2ec55ba 100644 (file)
@@ -219,11 +219,29 @@ reg_or_cint_move_operand (op, mode)
 }
 
 int
-pic_operand (op, mode)
+pic_label_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  return flag_pic && GET_CODE (op) == LABEL_REF;
+  if (!flag_pic)
+    return 0;
+
+  switch (GET_CODE (op))
+    {
+    case LABEL_REF:
+      return 1;
+    case SYMBOL_REF:
+      return (read_only_operand (op) && !FUNCTION_NAME_P (XSTR (op, 0)));
+    case CONST:
+      op = XEXP (op, 0);
+      return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+               && read_only_operand (XEXP (op, 0))
+               && !FUNCTION_NAME_P (XSTR (XEXP (op, 0), 0)))
+              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+             && GET_CODE (XEXP (op, 1)) == CONST_INT);
+    default:
+      return 0;
+    }
 }
 
 int
@@ -235,32 +253,6 @@ fp_reg_operand (op, mode)
 }
 
 \f
-extern int current_function_uses_pic_offset_table;
-extern rtx force_reg (), validize_mem ();
-
-/* The rtx for the global offset table which is a special form
-   that *is* a position independent symbolic constant.  */
-rtx pic_pc_rtx;
-
-/* Ensure that we are not using patterns that are not OK with PIC.  */
-
-int
-check_pic (i)
-     int i;
-{
-  extern rtx recog_operand[];
-  switch (flag_pic)
-    {
-    case 1:
-      if (GET_CODE (recog_operand[i]) == SYMBOL_REF
-         || (GET_CODE (recog_operand[i]) == CONST
-             && ! rtx_equal_p (pic_pc_rtx, recog_operand[i])))
-       abort ();
-    case 2:
-    default:
-      return 1;
-    }
-}
 
 /* Return truth value of whether OP can be used as an operand in a
    three operand arithmetic insn that accepts registers of mode MODE
@@ -480,6 +472,13 @@ legitimize_pic_address (orig, mode, reg)
 {
   rtx pic_ref = orig;
 
+  /* Lables and read-only data need special handling.  */
+  if (pic_label_operand (orig))
+    {
+      emit_insn (gen_pic_load_label (reg, orig));
+      current_function_uses_pic_offset_table = 1;
+      return reg;
+    }
   if (GET_CODE (orig) == SYMBOL_REF)
     {
       if (reg == 0)
@@ -487,15 +486,12 @@ legitimize_pic_address (orig, mode, reg)
 
       if (flag_pic == 2)
        {
-         emit_insn (gen_rtx (SET, VOIDmode, reg,
-                             gen_rtx (HIGH, Pmode, orig)));
-         emit_insn (gen_rtx (SET, VOIDmode, reg,
-                             gen_rtx (LO_SUM, Pmode, reg, orig)));
-         orig = reg;
+         emit_insn (gen_pic_highpart (reg, pic_offset_table_rtx, orig));
+         pic_ref = (gen_rtx (MEM, Pmode, gen_rtx (LO_SUM, Pmode, reg, orig)));
        }
-      pic_ref = gen_rtx (MEM, Pmode,
-                        gen_rtx (PLUS, Pmode,
-                                 pic_offset_table_rtx, orig));
+      else
+       pic_ref = gen_rtx (MEM, Pmode,
+                          gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig));
       current_function_uses_pic_offset_table = 1;
       RTX_UNCHANGING_P (pic_ref) = 1;
       emit_move_insn (reg, pic_ref);
@@ -531,24 +527,6 @@ legitimize_pic_address (orig, mode, reg)
   return pic_ref;
 }
 
-/* Emit special PIC prologues and epilogues.  */
-
-void
-finalize_pic ()
-{
-  if (hppa_save_pic_table_rtx)
-    {
-      emit_insn_after (gen_rtx (SET, VOIDmode,
-                               hppa_save_pic_table_rtx,
-                               gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)),
-                      get_insns ());
-      /* Need to emit this whether or not we obey regdecls,
-        since setjmp/longjmp can cause life info to screw up.  */
-      hppa_save_pic_table_rtx = 0;
-    }
-  emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));
-}
-
 /* Try machine-dependent ways of modifying an illegitimate address
    to be legitimate.  If we find one, return the new, valid address.
    This macro is used in only one place: `memory_address' in explow.c.
@@ -607,6 +585,9 @@ hppa_legitimize_address (x, oldx, mode)
 {
   rtx orig = x;
 
+  if (flag_pic)
+    return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
+
   /* Strip off CONST. */
   if (GET_CODE (x) == CONST)
     x = XEXP (x, 0);
@@ -727,9 +708,6 @@ hppa_legitimize_address (x, oldx, mode)
        }
     }
 
-  if (flag_pic)
-    return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
-
   return orig;
 }
 
@@ -895,16 +873,16 @@ emit_move_sequence (operands, mode, scratch_reg)
              rtx temp;
 
              if (reload_in_progress || reload_completed)
-               temp = operand0;
+               temp = scratch_reg ? scratch_reg : operand0;
              else
                temp = gen_reg_rtx (Pmode);
 
              operands[1] = legitimize_pic_address (operand1, mode, temp);
-              emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1]));
+             emit_insn (gen_rtx (SET, VOIDmode, operand0, operands[1]));
            }
-         /* On the HPPA, references to data space are supposed to */
-         /* use dp, register 27, but showing it in the RTL inhibits various
-            cse and loop optimizations.  */
+         /* On the HPPA, references to data space are supposed to use dp,
+            register 27, but showing it in the RTL inhibits various cse
+            and loop optimizations.  */
          else
            {
              rtx temp, set, const_part = NULL;
@@ -982,8 +960,16 @@ read_only_operand (operand)
 {
   if (GET_CODE (operand) == CONST)
     operand = XEXP (XEXP (operand, 0), 0);
-  if (GET_CODE (operand) == SYMBOL_REF)
-    return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
+  if (flag_pic)
+    {
+      if (GET_CODE (operand) == SYMBOL_REF)
+       return SYMBOL_REF_FLAG (operand) && !CONSTANT_POOL_ADDRESS_P (operand);
+    }
+  else
+    {
+      if (GET_CODE (operand) == SYMBOL_REF)
+       return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand);
+    }
   return 1;
 }
 
@@ -2950,7 +2936,7 @@ output_global_address (file, x)
 
   if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x))
     assemble_name (file, XSTR (x, 0));
-  else if (GET_CODE (x) == SYMBOL_REF)
+  else if (GET_CODE (x) == SYMBOL_REF && !flag_pic)
     {
       assemble_name (file, XSTR (x, 0));
       fprintf (file, "-$global$");
@@ -2994,7 +2980,7 @@ output_global_address (file, x)
        sep = "-";
       else abort ();
 
-      if (!read_only_operand (base))
+      if (!read_only_operand (base) && !flag_pic)
        fprintf (file, "-$global$");
       fprintf (file, "%s", sep);
       if (offset) fprintf (file,"%d", offset);
@@ -3261,6 +3247,14 @@ secondary_reload_class (class, mode, in)
 {
   int regno = true_regnum (in);
 
+  /* Trying to load a constant into a FP register during PIC code
+     generation will require %r1 as a scratch register.  */
+  if (flag_pic == 2
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && FP_REG_CLASS_P (class)
+      && (GET_CODE (in) == CONST_INT || GET_CODE (in) == CONST_DOUBLE))
+    return R1_REGS;
+
   if (((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
        && GET_MODE_CLASS (mode) == MODE_INT
        && FP_REG_CLASS_P (class))
@@ -3270,6 +3264,11 @@ secondary_reload_class (class, mode, in)
   if (GET_CODE (in) == HIGH)
     in = XEXP (in, 0);
 
+  if (!flag_pic
+      && symbolic_operand (in, VOIDmode)
+      && read_only_operand (in))
+    return NO_REGS;
+
   if (class != R1_REGS && symbolic_operand (in, VOIDmode))
     return R1_REGS;
 
index bc7624d..cf880af 100644 (file)
@@ -182,21 +182,6 @@ extern int target_flags;
 #define WCHAR_TYPE "unsigned int"
 #define WCHAR_TYPE_SIZE 32
 
-/* Sometimes certain combinations of command options do not make sense
-   on a particular target machine.  You can define a macro
-   `OVERRIDE_OPTIONS' to take account of this.  This macro, if
-   defined, is executed once just after all the command options have
-   been parsed.
-
-   On the PA, it is used to explicitly warn the user that -fpic and -fPIC
-   do not work.  */
-
-#define OVERRIDE_OPTIONS \
-{                                                              \
-  if (flag_pic != 0)                                           \
-    warning ("-fpic and -fPIC are not supported on the PA.");  \
-}
-
 /* Show we can debug even without a frame pointer.  */
 #define CAN_DEBUG_WITHOUT_FP
 
@@ -495,8 +480,12 @@ extern int target_flags;
    data references.  */
 
 #define PIC_OFFSET_TABLE_REGNUM 19
+#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED 1
 
-#define FINALIZE_PIC finalize_pic ()
+/* Initialize hppa_save_pic_table_rtx before RTL generation for
+   each function.  We used to do this in FINALIZE_PIC, but FINALIZE_PIC
+   isn't always called for static inline functions.  */
+#define INIT_EXPANDERS hppa_save_pic_table_rtx = 0;
 
 /* SOM ABI says that objects larger than 64 bits are returned in memory.  */
 #define RETURN_IN_MEMORY(TYPE) \
@@ -1185,8 +1174,9 @@ extern union tree_node *current_function_decl;
    floating-point, except for floating-point zero.  */
 
 #define LEGITIMATE_CONSTANT_P(X)               \
-  (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
-    || (X) == CONST0_RTX (GET_MODE (X)))
+  ((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT        \
+    || (X) == CONST0_RTX (GET_MODE (X)))       \
+   && !(flag_pic && function_label_operand (X, VOIDmode)))
 
 /* Subroutine for EXTRA_CONSTRAINT.
 
@@ -1307,9 +1297,7 @@ extern union tree_node *current_function_decl;
              && REG_OK_FOR_BASE_P (XEXP (X, 1)))       \
            goto ADDR;                                  \
          else if (flag_pic == 1                        \
-                  && GET_CODE (XEXP (X, 1)) != REG     \
-                  && GET_CODE (XEXP (X, 1)) != LO_SUM  \
-                  && GET_CODE (XEXP (X, 1)) != MEM)    \
+                  && GET_CODE (XEXP (X, 1)) == SYMBOL_REF)\
            goto ADDR;                                  \
        }                                               \
       else if (REG_P (XEXP (X, 0))                     \
@@ -1427,6 +1415,17 @@ while (0)
                             1 + (SYMBOL_NAME)[1] == '@'\
                             : (SYMBOL_NAME)[0] == '@'))
 
+/* Arghh.  This is used for stuff in the constant pool; this may include
+   function addresses on the PA, which during PIC code generation must
+   reside in the data space.  Unfortuantely, there's no way to determine
+   if a particular label in the constant pool refers to a function address.
+   So just force everything into the data space during PIC generation.  */
+#define SELECT_RTX_SECTION(RTX,MODE)   \
+  if (flag_pic)                                \
+    data_section ();                   \
+  else                                 \
+    readonly_data_section ();
+
 /* Specify the machine mode that this machine uses
    for the index in the tablejump instruction.  */
 #define CASE_VECTOR_MODE DImode
@@ -1682,6 +1681,10 @@ do { fprintf (FILE, "\t.SPACE $PRIVATE$\n\
 
 #define EXTRA_SECTIONS in_bss, in_readonly_data
 
+/* FIXME: GAS doesn't grok expressions involving two symbols in different
+   segments (aka subspaces).  Two avoid creating such expressions, we place
+   readonly data into the $CODE$ subspace when generating PIC code.  If
+   GAS ever handles such expressions, this hack can disappear.  */
 #define EXTRA_SECTION_FUNCTIONS                                                \
 void                                                                   \
 bss_section ()                                                         \
@@ -1697,7 +1700,10 @@ readonly_data ()                                                 \
 {                                                                      \
   if (in_section != in_readonly_data)                                  \
     {                                                                  \
-      fprintf (asm_out_file, "%s\n", READONLY_DATA_ASM_OP);            \
+      if (flag_pic)                                                    \
+       fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);            \
+      else                                                             \
+       fprintf (asm_out_file, "%s\n", READONLY_DATA_ASM_OP);           \
       in_section = in_readonly_data;                                   \
     }                                                                  \
 }
@@ -1980,7 +1986,12 @@ readonly_data ()                                                 \
       fprintf (FILE, "%d(0,%s)", offset, reg_names [REGNO (base)]);    \
       break;                                                           \
     case LO_SUM:                                                       \
-      fputs ("R'", FILE);                                              \
+      if (flag_pic == 0 || !symbolic_operand (XEXP (addr, 1)))         \
+       fputs ("R'", FILE);                                             \
+      else if (flag_pic == 1)                                          \
+       abort ();                                                       \
+      else if (flag_pic == 2)                                          \
+       fputs ("RT'", FILE);                                            \
       output_global_address (FILE, XEXP (addr, 1));                    \
       fputs ("(", FILE);                                               \
       output_operand (XEXP (addr, 0), 0);                              \
index 81b3341..3bb5b07 100644 (file)
    (set_attr "length" "4")])
 
 ;; For pic
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (match_operand:SI 1 "pic_operand" "i"))
-   (clobber (match_scratch:SI 2 "=a"))]
+;; Note since this pattern can be created at reload time (via movsi), all
+;; the same rules for movsi apply here.  (no new pseudos, no temporaries).
+(define_insn "pic_load_label"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (match_operand:SI 1 "pic_label_operand" ""))]
   ""
   "*
 {
   xoperands[0] = operands[0];
   xoperands[1] = operands[1];
   xoperands[2] = label_rtx;
-  output_asm_insn (\"bl .+8,%0\;addil L'%1-%2,%0\", xoperands);
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label_rtx));
-  output_asm_insn (\"ldo R'%1-%2(1),%0\", xoperands);
+  output_asm_insn (\"bl .+8,%0\", xoperands);
+  output_asm_insn (\"depi 0,31,2,%0\", xoperands);
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+                            CODE_LABEL_NUMBER (label_rtx));
+
+  /* If we're trying to load the address of a label that happens to be
+     close, then we can use a shorter sequence.  */
+  if (GET_CODE (operands[1]) == LABEL_REF
+      && insn_addresses
+      && abs (insn_addresses[INSN_UID (XEXP (operands[1], 0))]
+               - insn_current_address) < 8100)
+    {
+      /* Prefixing with R% here is wrong, it extracts just 11 bits and is
+        always non-negative.  */
+      output_asm_insn (\"ldo %1-%2(%0),%0\", xoperands);
+    }
+  else
+    {
+      output_asm_insn (\"addil L%%%1-%2,%0\", xoperands);
+      output_asm_insn (\"ldo R%%%1-%2(%0),%0\", xoperands);
+    }
   return \"\";
-  }
-"
+}"
   [(set_attr "type" "multi")
-   (set_attr "length" "12")])
+   (set_attr "length" "16")])          ; 12 or 16
+
+(define_insn "pic_highpart"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (plus (match_operand:SI 1 "register_operand" "r")
+             (high:SI (match_operand 2 "" ""))))]
+  "symbolic_operand (operands[2], Pmode)
+   && ! function_label_operand (operands[2])
+   && ! read_only_operand (operands[2])
+   && flag_pic == 2"
+  "addil LT'%G2,%1"
+  [(set_attr "type" "binary")
+   (set_attr "length" "4")])
 
 ;; Always use addil rather than ldil;add sequences.  This allows the
 ;; HP linker to eliminate the dp relocation if the symbolic operand
        (high:SI (match_operand 1 "" "")))]
   "symbolic_operand (operands[1], Pmode)
    && ! function_label_operand (operands[1])
-   && ! read_only_operand (operands[1])"
-  "@
-   addil L'%G1,%%r27"
+   && ! read_only_operand (operands[1])
+   && ! flag_pic"
+  "addil L'%G1,%%r27"
   [(set_attr "type" "binary")
    (set_attr "length" "4")])
 
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=r")
        (high:SI (match_operand 1 "" "")))]
-  "check_pic (1) && !is_function_label_plus_const (operands[1])"
+  "(!flag_pic || !symbolic_operand (operands[1]), Pmode)
+    && !is_function_label_plus_const (operands[1])"
   "ldil L'%G1,%0"
   [(set_attr "type" "move")
    (set_attr "length" "4")])
        (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
                   (match_operand:SI 2 "immediate_operand" "i")))]
   "!is_function_label_plus_const (operands[2])"
-  "ldo R'%G2(%1),%0"
+  "*
+{
+  if (flag_pic == 2 && symbolic_operand (operands[2], Pmode))
+    return \"ldw RT'%G2(%1),%0\";
+  else if (flag_pic == 1 && symbolic_operand (operands[2], Pmode))
+    abort ();
+  else
+    return \"ldo R'%G2(%1),%0\";
+}"
   [(set_attr "length" "4")])
 
 ;; Now that a symbolic_address plus a constant is broken up early
   [(set (match_operand:SI 0 "register_operand" "")
        (match_operand:SI 1 "symbolic_operand" ""))
    (clobber (match_operand:SI 2 "register_operand" ""))]
-  ""
+  "! (flag_pic && pic_label_operand (operands[1], SImode))"
   [(set (match_dup 2) (high:SI (match_dup 1)))
    (set (match_dup 0) (lo_sum:SI (match_dup 2) (match_dup 1)))]
   "")
 
 (define_insn ""
   [(set (match_operand:HI 0 "register_operand" "=r")
-       (high:HI (match_operand 1 "" "")))]
-  "check_pic (1)"
+       (high:HI (match_operand 1 "const_int_operand" "")))]
+  ""
   "ldil L'%G1,%0"
   [(set_attr "type" "move")
    (set_attr "length" "4")])
 (define_insn ""
   [(set (match_operand:HI 0 "register_operand" "=r")
        (lo_sum:HI (match_operand:HI 1 "register_operand" "r")
-                  (match_operand 2 "immediate_operand" "i")))]
+                  (match_operand 2 "const_int_operand" "i")))]
   ""
   "ldo R'%G2(%1),%0"
   [(set_attr "length" "4")])
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
        (high:DI (match_operand 1 "" "")))]
-  "check_pic (1)"
+  ""
   "*
 {
   rtx op0 = operands[0];
   "
 {
   rtx op;
-
-  if (flag_pic)
-    emit_insn (gen_rtx (USE, VOIDmode,
-                       gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
+  rtx call_insn;
 
   if (TARGET_LONG_CALLS)
     op = force_reg (SImode, XEXP (operands[0], 0));
      to change the named call into an indirect call in some cases (using
      two patterns keeps CSE from performing this optimization).  */
   if (GET_CODE (op) == SYMBOL_REF)
-    emit_call_insn (gen_call_internal_symref (op, operands[1]));
+    call_insn = emit_call_insn (gen_call_internal_symref (op, operands[1]));
   else
-    emit_call_insn (gen_call_internal_reg (force_reg (SImode, op),
-                                          operands[1]));
+    call_insn = emit_call_insn (gen_call_internal_reg (force_reg (SImode, op),
+                                                      operands[1]));
 
   if (flag_pic)
     {
+      use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+
       if (!hppa_save_pic_table_rtx)
-       hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
-      emit_insn (gen_rtx (SET, VOIDmode,
-                         gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM),
+       {
+         hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
+         push_topmost_sequence ();
+         emit_insn_after (gen_rtx (SET, VOIDmode,
+                                   hppa_save_pic_table_rtx,
+                                   pic_offset_table_rtx),
+                          get_insns ());
+         pop_topmost_sequence ();
+       }
+
+      emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
                          hppa_save_pic_table_rtx));
     }
   DONE;
                   (call (match_operand:SI 1 "" "")
                         (match_operand 2 "" "")))
              (clobber (reg:SI 2))])]
-  ;;- Don't use operand 1 for most machines.
   ""
   "
 {
   rtx op;
-
-  if (flag_pic)
-    emit_insn (gen_rtx (USE, VOIDmode,
-                       gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM)));
+  rtx call_insn;
 
   if (TARGET_LONG_CALLS)
     op = force_reg (SImode, XEXP (operands[1], 0));
      to change the named call into an indirect call in some cases (using
      two patterns keeps CSE from performing this optimization).  */
   if (GET_CODE (op) == SYMBOL_REF)
-    emit_call_insn (gen_call_value_internal_symref (operands[0], op,
-                                                   operands[2]));
+    call_insn = emit_call_insn (gen_call_value_internal_symref (operands[0],
+                                                               op,
+                                                               operands[2]));
   else
-    emit_call_insn (gen_call_value_internal_reg (operands[0],
-                                                force_reg (SImode, op),
-                                                operands[2]));
+    call_insn = emit_call_insn (gen_call_value_internal_reg (operands[0],
+                                                            force_reg (SImode, op),
+                                                            operands[2]));
 
   if (flag_pic)
     {
+      use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+
       if (!hppa_save_pic_table_rtx)
-       hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
-      emit_insn (gen_rtx (SET, VOIDmode,
-                         gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM),
+       {
+         hppa_save_pic_table_rtx = gen_reg_rtx (Pmode);
+         push_topmost_sequence ();
+         emit_insn_after (gen_rtx (SET, VOIDmode,
+                                   hppa_save_pic_table_rtx,
+                                   pic_offset_table_rtx),
+                          get_insns ());
+         pop_topmost_sequence ();
+       }
+
+      emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx,
                          hppa_save_pic_table_rtx));
     }
   DONE;
              (match_operand 2 "" "i")))
    (clobber (reg:SI 2))
    (use (const_int 1))]
-  ;;- Don't use operand 1 for most machines.
   ""
   "*
 {