ia64-protos.h: Update.
authorRichard Henderson <rth@cygnus.com>
Sun, 24 Sep 2000 23:58:24 +0000 (16:58 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Sun, 24 Sep 2000 23:58:24 +0000 (16:58 -0700)
        * config/ia64/ia64-protos.h: Update.
        * config/ia64/ia64.c (call_multiple_values_operation): Remove.
        (ia64_expand_call): New.
        (ia64_expand_prologue): Emit an alloc if we need extra input
        registers.
        (ia64_expand_epilogue): New arg sibcall_p; don't emit the return
        instruction if true.
        (struct reg_flags): Add is_sibcall.
        (rtx_needs_barrier): A sibcall does not use CFM et al.  Ignore USEs.
        (emit_insn_group_barriers): Set flags.is_sibcall.  Remove hacks
        for CODE_FOR_gr_spill_internal/CODE_FOR_gr_restore_internal.
        * config/ia64/ia64.h (PREDICATE_CODES): Update.
        * config/ia64/ia64.md (call): Use ia64_expand_call.
        (call_value): Likewise.
        (sibcall, sibcall_value): New.
        (call patterns): Remove extra expanders; tidy.
        (sibcall_epilogue): New.
        (set_bsp): Remove the extra USE.  Put the operand inside the UNSPEC.

From-SVN: r36597

gcc/ChangeLog
gcc/config/ia64/ia64-protos.h
gcc/config/ia64/ia64.c
gcc/config/ia64/ia64.h
gcc/config/ia64/ia64.md

index 0e48841c911ca9705f99d2cf61b6b8237a85e14d..aa4a660fd41072bede02a564324730d338acbf95 100644 (file)
@@ -1,3 +1,24 @@
+2000-09-24  Richard Henderson  <rth@cygnus.com>
+
+       * config/ia64/ia64-protos.h: Update.
+       * config/ia64/ia64.c (call_multiple_values_operation): Remove.
+       (ia64_expand_call): New.
+       (ia64_expand_prologue): Emit an alloc if we need extra input
+       registers.
+       (ia64_expand_epilogue): New arg sibcall_p; don't emit the return
+       instruction if true.
+       (struct reg_flags): Add is_sibcall.
+       (rtx_needs_barrier): A sibcall does not use CFM et al.  Ignore USEs.
+       (emit_insn_group_barriers): Set flags.is_sibcall.  Remove hacks
+       for CODE_FOR_gr_spill_internal/CODE_FOR_gr_restore_internal.
+       * config/ia64/ia64.h (PREDICATE_CODES): Update.
+       * config/ia64/ia64.md (call): Use ia64_expand_call.
+       (call_value): Likewise.
+       (sibcall, sibcall_value): New.
+       (call patterns): Remove extra expanders; tidy.
+       (sibcall_epilogue): New.
+       (set_bsp): Remove the extra USE.  Put the operand inside the UNSPEC.
+
 2000-09-24  Richard Henderson  <rth@cygnus.com>
 
        * emit-rtl.c (gen_lowpart_common): Use trunc_int_for_mode.
index 7cde4ea8ca25c4d17c96d53a1ad1db7dcd6583d7..839648cdf2cf72e2854a4f68b3ad2dcee3a31d3f 100644 (file)
@@ -57,7 +57,6 @@ extern int fr_reg_or_fp01_operand PARAMS((rtx, enum machine_mode));
 extern int normal_comparison_operator PARAMS((rtx, enum machine_mode));
 extern int adjusted_comparison_operator PARAMS((rtx, enum machine_mode));
 extern int signed_inequality_operator PARAMS((rtx, enum machine_mode));
-extern int call_multiple_values_operation PARAMS((rtx, enum machine_mode));
 extern int destination_operand PARAMS((rtx, enum machine_mode));
 extern int not_postinc_memory_operand PARAMS((rtx, enum machine_mode));
 extern int predicate_operator PARAMS((rtx, enum machine_mode));
@@ -73,10 +72,11 @@ extern rtx ia64_gp_save_reg PARAMS((int));
 extern rtx ia64_split_timode PARAMS((rtx[], rtx, rtx));
 extern rtx spill_tfmode_operand PARAMS((rtx, int));
 extern rtx ia64_expand_compare PARAMS((enum rtx_code, enum machine_mode));
+extern void ia64_expand_call PARAMS((rtx, rtx, rtx, int));
 
 extern HOST_WIDE_INT ia64_initial_elimination_offset PARAMS((int, int));
 extern void ia64_expand_prologue PARAMS((void));
-extern void ia64_expand_epilogue PARAMS((void));
+extern void ia64_expand_epilogue PARAMS((int));
 extern void ia64_function_prologue PARAMS((FILE *, int));
 extern void ia64_function_epilogue PARAMS((FILE *, int));
 
index 31c54bceb4ff4ae2af1358fc851a0739d78975d1..a6de7843dfb8699e793d192e5ea237263bed5f18 100644 (file)
@@ -676,41 +676,6 @@ signed_inequality_operator (op, mode)
              || code == LE || code == LT));
 }
 
-/* Return 1 if OP is a call returning an HFA.  It is known to be a PARALLEL
-   and the first section has already been tested.  */
-
-int
-call_multiple_values_operation (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-{
-  int count = XVECLEN (op, 0) - 2;
-  int i;
-  unsigned int dest_regno;
-
-  /* Perform a quick check so we don't block up below.  */
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != CALL)
-    return 0;
-
-  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
-
-  for (i = 1; i < count; i++)
-    {
-      rtx elt = XVECEXP (op, 0, i + 2);
-
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_SRC (elt)) != CALL
-         || GET_CODE (SET_DEST (elt)) != REG
-         || REGNO (SET_DEST (elt)) != dest_regno + i)
-       return 0;
-    }
-
-  return 1;
-}
-
 /* Return 1 if this operator is valid for predication.  */
 
 int
@@ -1044,6 +1009,98 @@ ia64_expand_compare (code, mode)
 
   return gen_rtx_fmt_ee (code, mode, cmp, const0_rtx);
 }
+
+/* Emit the appropriate sequence for a call.  */
+
+void
+ia64_expand_call (retval, addr, nextarg, sibcall_p)
+     rtx retval;
+     rtx addr;
+     rtx nextarg;
+     int sibcall_p;
+{
+  rtx insn, b0, gp_save, narg_rtx;
+  int narg;
+
+  addr = XEXP (addr, 0);
+  b0 = gen_rtx_REG (DImode, R_BR (0));
+
+  if (! nextarg)
+    narg = 0;
+  else if (IN_REGNO_P (REGNO (nextarg)))
+    narg = REGNO (nextarg) - IN_REG (0);
+  else
+    narg = REGNO (nextarg) - OUT_REG (0);
+  narg_rtx = GEN_INT (narg);
+
+  if (TARGET_NO_PIC || TARGET_AUTO_PIC)
+    {
+      if (sibcall_p)
+       insn = gen_sibcall_nopic (addr, narg_rtx, b0);
+      else if (! retval)
+       insn = gen_call_nopic (addr, narg_rtx, b0);
+      else
+       insn = gen_call_value_nopic (retval, addr, narg_rtx, b0);
+      emit_call_insn (insn);
+      return;
+    }
+
+  if (sibcall_p)
+    gp_save = NULL_RTX;
+  else
+    gp_save = ia64_gp_save_reg (setjmp_operand (addr, VOIDmode));
+
+  /* If this is an indirect call, then we have the address of a descriptor.  */
+  if (! symbolic_operand (addr, VOIDmode))
+    {
+      rtx dest;
+
+      if (! sibcall_p)
+       emit_move_insn (gp_save, pic_offset_table_rtx);
+
+      dest = force_reg (DImode, gen_rtx_MEM (DImode, addr));
+      emit_move_insn (pic_offset_table_rtx,
+                     gen_rtx_MEM (DImode, plus_constant (addr, 8)));
+
+      if (sibcall_p)
+       insn = gen_sibcall_pic (dest, narg_rtx, b0);
+      else if (! retval)
+       insn = gen_call_pic (dest, narg_rtx, b0);
+      else
+       insn = gen_call_value_pic (retval, dest, narg_rtx, b0);
+      emit_call_insn (insn);
+
+      if (! sibcall_p)
+       emit_move_insn (pic_offset_table_rtx, gp_save);
+    }
+  else if (TARGET_CONST_GP)
+    {
+      if (sibcall_p)
+       insn = gen_sibcall_nopic (addr, narg_rtx, b0);
+      else if (! retval)
+       insn = gen_call_nopic (addr, narg_rtx, b0);
+      else
+       insn = gen_call_value_nopic (retval, addr, narg_rtx, b0);
+      emit_call_insn (insn);
+    }
+  else
+    {
+      if (sibcall_p)
+       emit_call_insn (gen_sibcall_pic (addr, narg_rtx, b0));
+      else
+       {
+         emit_move_insn (gp_save, pic_offset_table_rtx);
+
+         if (! retval)
+           insn = gen_call_pic (addr, narg_rtx, b0);
+         else
+           insn = gen_call_value_pic (retval, addr, narg_rtx, b0);
+         emit_call_insn (insn);
+
+         emit_move_insn (pic_offset_table_rtx, gp_save);
+       }
+    }
+}
 \f
 /* Begin the assembly file.  */
 
@@ -1819,7 +1876,8 @@ ia64_expand_prologue ()
 
   /* We don't need an alloc instruction if we've used no outputs or locals.  */
   if (current_frame_info.n_local_regs == 0
-      && current_frame_info.n_output_regs == 0)
+      && current_frame_info.n_output_regs == 0
+      && current_frame_info.n_input_regs <= current_function_args_info.words)
     {
       /* If there is no alloc, but there are input registers used, then we
         need a .regstk directive.  */
@@ -2090,7 +2148,8 @@ ia64_expand_prologue ()
    insn to prevent such scheduling.  */
 
 void
-ia64_expand_epilogue ()
+ia64_expand_epilogue (sibcall_p)
+     int sibcall_p;
 {
   rtx insn, reg, alt_reg, ar_unat_save_reg;
   int regno, alt_regno, cfa_off;
@@ -2303,7 +2362,8 @@ ia64_expand_epilogue ()
   if (cfun->machine->ia64_eh_epilogue_bsp)
     emit_insn (gen_set_bsp (cfun->machine->ia64_eh_epilogue_bsp));
  
-  emit_jump_insn (gen_return_internal (gen_rtx_REG (DImode, BR_REG (0))));
+  if (! sibcall_p)
+    emit_jump_insn (gen_return_internal (gen_rtx_REG (DImode, BR_REG (0))));
 }
 
 /* Return 1 if br.ret can do all the work required to return from a
@@ -3642,6 +3702,7 @@ struct reg_flags
   unsigned int is_branch : 1;  /* Is register used as part of a branch?  */
   unsigned int is_and : 1;     /* Is register used as part of and.orcm?  */
   unsigned int is_or : 1;      /* Is register used as part of or.andcm?  */
+  unsigned int is_sibcall : 1; /* Is this a sibling or normal call?  */
 };
 
 static void rws_update PARAMS ((struct reg_write_state *, int,
@@ -3935,9 +3996,7 @@ rtx_needs_barrier (x, flags, pred)
 
       /* Avoid multiple register writes, in case this is a pattern with
         multiple CALL rtx.  This avoids an abort in rws_access_reg.  */
-      /* ??? This assumes that no rtx other than CALL/RETURN sets REG_AR_CFM,
-        and that we don't have predicated calls/returns.  */
-      if (! rws_insn[REG_AR_CFM].write_count)
+      if (! flags.is_sibcall && ! rws_insn[REG_AR_CFM].write_count)
        {
          new_flags.is_write = 1;
          need_barrier |= rws_access_regno (REG_RP, new_flags, pred);
@@ -3968,12 +4027,7 @@ rtx_needs_barrier (x, flags, pred)
       return need_barrier;
 
     case CLOBBER:
-#if 0
     case USE:
-      /* We must handle USE here in case it occurs within a PARALLEL.
-        For instance, the mov ar.pfs= instruction has a USE which requires
-        a barrier between it and an immediately preceeding alloc.  */
-#endif
       /* Clobber & use are for earlier compiler-phases only.  */
       break;
 
@@ -4096,6 +4150,7 @@ rtx_needs_barrier (x, flags, pred)
          break;
 
        case 7: /* pred_rel_mutex */
+       case 9: /* pic call */
         case 12: /* mf */
         case 19: /* fetchadd_acq */
        case 20: /* mov = ar.bsp */
@@ -4185,6 +4240,7 @@ rtx_needs_barrier (x, flags, pred)
          default:
            abort ();
          }
+      break;
     }
   return need_barrier;
 }
@@ -4229,6 +4285,7 @@ emit_insn_group_barriers (insns)
 
        case CALL_INSN:
          flags.is_branch = 1;
+         flags.is_sibcall = SIBLING_CALL_P (insn);
          memset (rws_insn, 0, sizeof (rws_insn));
          need_barrier = rtx_needs_barrier (PATTERN (insn), flags, 0);
 
@@ -4300,18 +4357,6 @@ emit_insn_group_barriers (insns)
                  pat = XVECEXP (pat, 0, 1);
                  break;
 
-                 /* We include ar.unat in the rtl pattern so that sched2
-                    does not move the ar.unat save/restore after/before
-                    a gr spill/fill.  However, we special case these
-                    insns based on their unspec number so as to model
-                    their precise ar.unat bit operations.  If we pass on
-                    the use/clobber of the whole ar.unat register we'll
-                    waste this effort.  */
-               case CODE_FOR_gr_spill_internal:
-               case CODE_FOR_gr_restore_internal:
-                 pat = XVECEXP (pat, 0, 0);
-                 break;
-
                  /* Doesn't generate code.  */
                case CODE_FOR_pred_rel_mutex:
                  continue;
index f2402a38ea430c90eba4450f84babbc5f0b2dbcf..6126fa65debab5931fae55989a4b5bcae7677e42 100644 (file)
@@ -2697,7 +2697,6 @@ do {                                                                      \
 { "normal_comparison_operator", {EQ, NE, GT, LE, GTU, LEU}},           \
 { "adjusted_comparison_operator", {LT, GE, LTU, GEU}},                 \
 { "signed_inequality_operator", {GE, GT, LE, LT}},                     \
-{ "call_multiple_values_operation", {PARALLEL}},                       \
 { "predicate_operator", {NE, EQ}},                                     \
 { "ar_lc_reg_operand", {REG}},                                         \
 { "ar_ccv_reg_operand", {REG}},                                                \
index 45479a22c771d82801fb0669e6ba86c67ea60fb1..11b14c01fe03d48556746bcdeaae2c7ff6de699a 100644 (file)
@@ -62,6 +62,7 @@
 ;;     5       recip_approx
 ;;     7       pred_rel_mutex
 ;;     8       popcnt
+;;     9       pic call
 ;;     12      mf
 ;;     13      cmpxchg_acq
 ;;     19      fetchadd_acq
   ""
   "
 {
-  /* ??? Stripping off the MEM isn't correct.  Will lose alias info.  */
-  rtx addr = XEXP (operands[0], 0);
-  enum machine_mode mode = GET_MODE (addr);
-
-  if (TARGET_NO_PIC || TARGET_AUTO_PIC)
-    emit_call_insn (gen_call_internal (addr, operands[1],
-                                      gen_rtx_REG (DImode, R_BR (0))));
-
-  /* If this is an indirect call, then we have the address of a descriptor.  */
-  else if (! symbolic_operand (addr, mode))
-    emit_insn (gen_indirect_call_pic (addr, operands[1]));
-  else if (TARGET_CONST_GP)
-    emit_call_insn (gen_call_internal (addr, operands[1],
-                                      gen_rtx_REG (DImode, R_BR (0))));
-  else
-    emit_insn (gen_call_pic (addr, operands[1]));
-
+  ia64_expand_call (NULL_RTX, operands[0], operands[2], 0);
   DONE;
 }")
 
-(define_expand "indirect_call_pic"
-  [(set (match_dup 2) (reg:DI 1))
-   (set (match_dup 3) (mem:DI (match_operand 0 "" "")))
-   (set (match_dup 4) (plus:DI (match_dup 0) (const_int 8)))
-   (set (reg:DI 1) (mem:DI (match_dup 4)))
-   (parallel [(call (mem:DI (match_dup 3)) (match_operand 1 "" ""))
-             (use (reg:DI 1))
-             (clobber (reg:DI 320))])
-   (set (reg:DI 1) (match_dup 2))]
-  ""
-  "
-{
-  operands[2] = ia64_gp_save_reg (0);
-  operands[3] = gen_reg_rtx (DImode);
-  operands[4] = gen_reg_rtx (DImode);
-}")
-
-;; ??? Saving/restoring the GP register is not needed if we are calling
-;; a function in the same module.
-
-(define_expand "call_pic"
-  [(set (match_dup 2) (reg:DI 1))
-   (parallel [(call (mem:DI (match_operand 0 "" "")) (match_operand 1 "" ""))
-             (use (reg:DI 1))
-             (clobber (reg:DI 320))])
-   (set (reg:DI 1) (match_dup 2))]
+(define_expand "sibcall"
+  [(use (match_operand:DI 0 "" ""))
+   (use (match_operand 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (match_operand 3 "" ""))]
   ""
   "
 {
-  /* ??? Using setjmp_operand is an unsatisfying solution.  Should rethink.  */
-  operands[2] = ia64_gp_save_reg (setjmp_operand (XEXP (operands[0], 0),
-                                                 VOIDmode));
+  ia64_expand_call (NULL_RTX, operands[0], operands[2], 1);
+  DONE;
 }")
 
-(define_insn "call_internal"
-  [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
-        (match_operand 1 "" ""))
-   (clobber (match_operand:DI 2 "register_operand" "=b"))]
-  ""
-  "br.call%+.many %2 = %0"
-  [(set_attr "type" "B")])
-
-(define_insn "*call_internal1"
-  [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
-        (match_operand 1 "" ""))
-   (use (reg:DI 1))
-   (clobber (match_operand:DI 2 "register_operand" "=b"))]
-  ""
-  "br.call%+.many %2 = %0"
-  [(set_attr "type" "B")])
-
 ;; Subroutine call instruction returning a value.  Operand 0 is the hard
-;; register in which the value is returned.  There are three more operands, the
-;; same as the three operands of the `call' instruction (but with numbers
+;; register in which the value is returned.  There are three more operands,
+;; the same as the three operands of the `call' instruction (but with numbers
 ;; increased by one).
-
+;;
 ;; Subroutines that return `BLKmode' objects use the `call' insn.
 
 (define_expand "call_value"
   ""
   "
 {
-  /* ??? Stripping off the MEM isn't correct.  Will lose alias info.  */
-  rtx addr = XEXP (operands[1], 0);
-  enum machine_mode mode = GET_MODE (addr);
-
-  if (TARGET_NO_PIC || TARGET_AUTO_PIC)
-    emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
-                                            gen_rtx_REG (DImode, R_BR (0))));
-
-  /* If this is an indirect call, then we have the address of a descriptor.  */
-  else if (! symbolic_operand (addr, mode))
-    {
-      /* This is for HFA returns.  */
-      if (GET_CODE (operands[0]) == PARALLEL)
-       emit_insn (gen_indirect_call_multiple_values_pic (operands[0], addr,
-                                                         operands[2]));
-      else
-       emit_insn (gen_indirect_call_value_pic (operands[0], addr,
-                                               operands[2]));
-    }
-  else if (TARGET_CONST_GP)
-    emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
-                                            gen_rtx_REG (DImode, R_BR (0))));
-  /* This is for HFA returns.  */
-  else if (GET_CODE (operands[0]) == PARALLEL)
-    emit_insn (gen_call_multiple_values_pic (operands[0], addr, operands[2]));
-  else
-    emit_insn (gen_call_value_pic (operands[0], addr, operands[2]));
-
+  ia64_expand_call (operands[0], operands[1], operands[3], 0);
   DONE;
 }")
 
-(define_expand "indirect_call_value_pic"
-  [(set (match_dup 3) (reg:DI 1))
-   (set (match_dup 4) (mem:DI (match_operand 1 "" "")))
-   (set (match_dup 5) (plus:DI (match_dup 1) (const_int 8)))
-   (set (reg:DI 1) (mem:DI (match_dup 5)))
-   (parallel [(set (match_operand 0 "" "")
-                  (call (mem:DI (match_dup 4)) (match_operand 2 "" "")))
-             (use (reg:DI 1))
-             (clobber (reg:DI 320))])
-   (set (reg:DI 1) (match_dup 3))]
-  ""
-  "
-{
-  operands[3] = ia64_gp_save_reg (0);
-  operands[4] = gen_reg_rtx (DImode);
-  operands[5] = gen_reg_rtx (DImode);
-}")
-
-(define_expand "indirect_call_multiple_values_pic"
-  [(set (match_dup 3) (reg:DI 1))
-   (set (match_dup 4) (mem:DI (match_operand 1 "" "")))
-   (set (match_dup 5) (plus:DI (match_dup 1) (const_int 8)))
-   (set (reg:DI 1) (mem:DI (match_dup 5)))
-   (match_par_dup 6 [(set (match_operand 0 "" "")
-                         (call (mem:DI (match_dup 4))
-                               (match_operand 2 "" "")))
-                    (use (reg:DI 1))
-                    (clobber (reg:DI 320))])
-   (set (reg:DI 1) (match_dup 3))]
-  ""
-  "
-{
-  int count;
-  int i;
-  rtx call;
-
-  operands[3] = ia64_gp_save_reg (0);
-  operands[4] = gen_reg_rtx (DImode);
-  operands[5] = gen_reg_rtx (DImode);
-
-  /* This code is the same as the code in call_multiple_values_pic, except
-     that op3 was replaced with op6 and op1 was replaced with op4.  */
-  call = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (DImode, operands[4]),
-                      operands[2]);
-
-  count = XVECLEN (operands[0], 0);
-  operands[6] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 2));
-  
-  XVECEXP (operands[6], 0, 0)
-    = gen_rtx_SET (VOIDmode, XEXP (XVECEXP (operands[0], 0, 0), 0), call);
-
-  XVECEXP (operands[6], 0, 1)
-    = gen_rtx_USE (DImode, gen_rtx_REG (DImode, GR_REG (1)));
-  XVECEXP (operands[6], 0, 2)
-    = gen_rtx_CLOBBER (DImode, gen_rtx_REG (DImode, BR_REG (0)));
-
-  for (i = 1; i < count; i++)
-    XVECEXP (operands[6], 0, i + 2)
-      = gen_rtx_SET (VOIDmode, XEXP (XVECEXP (operands[0], 0, i), 0), call);
-
-}")
-
-;; ??? Saving/restoring the GP register is not needed if we are calling
-;; a function in the same module.
-
-(define_expand "call_value_pic"
-  [(set (match_dup 3) (reg:DI 1))
-   (parallel [(set (match_operand 0 "" "")
-                  (call (mem:DI (match_operand 1 "" ""))
-                        (match_operand 2 "" "")))
-             (use (reg:DI 1))
-             (clobber (reg:DI 320))])
-   (set (reg:DI 1) (match_dup 3))]
-  ""
-  "
-{
-  /* ??? Using setjmp_operand is an unsatisfying solution.  Should rethink.  */
-  operands[3] = ia64_gp_save_reg (setjmp_operand (XEXP (operands[1], 0),
-                                                 VOIDmode));
-}")
-
-;; ??? Saving/restoring the GP register is not needed if we are calling
-;; a function in the same module.
-
-(define_expand "call_multiple_values_pic"
-  [(set (match_dup 4) (reg:DI 1))
-   (match_par_dup 3 [(set (match_operand 0 "" "")
-                         (call (mem:DI (match_operand 1 "" ""))
-                               (match_operand 2 "" "")))
-                    (use (reg:DI 1))
-                    (clobber (reg:DI 320))])
-   (set (reg:DI 1) (match_dup 4))]
+(define_expand "sibcall_value"
+  [(use (match_operand 0 "" ""))
+   (use (match_operand:DI 1 "" ""))
+   (use (match_operand 2 "" ""))
+   (use (match_operand 3 "" ""))
+   (use (match_operand 4 "" ""))]
   ""
   "
 {
-  int count;
-  int i;
-  rtx call;
-
-  operands[4] = ia64_gp_save_reg (0);
-
-  call = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (DImode, operands[1]),
-                      operands[2]);
-
-  count = XVECLEN (operands[0], 0);
-  operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 2));
-  
-  XVECEXP (operands[3], 0, 0)
-    = gen_rtx_SET (VOIDmode, XEXP (XVECEXP (operands[0], 0, 0), 0), call);
-
-  XVECEXP (operands[3], 0, 1)
-    = gen_rtx_USE (DImode, gen_rtx_REG (DImode, GR_REG (1)));
-  XVECEXP (operands[3], 0, 2)
-    = gen_rtx_CLOBBER (DImode, gen_rtx_REG (DImode, BR_REG (0)));
-
-  for (i = 1; i < count; i++)
-    XVECEXP (operands[3], 0, i + 2)
-      = gen_rtx_SET (VOIDmode, XEXP (XVECEXP (operands[0], 0, i), 0), call);
+  ia64_expand_call (operands[0], operands[1], operands[3], 1);
+  DONE;
 }")
 
-(define_insn "call_value_internal"
-  [(set (match_operand 0 "register_operand" "=rf")
-       (call (mem:DI (match_operand:DI 1 "call_operand" "bi"))
-             (match_operand 2 "" "")))
-   (clobber (match_operand:DI 3 "register_operand" "=b"))]
-  ""
-  "br.call%+.many %3 = %1"
-  [(set_attr "type" "B")])
-
-(define_insn "*call_value_internal1"
-  [(set (match_operand 0 "register_operand" "=rf")
-       (call (mem:DI (match_operand:DI 1 "call_operand" "bi"))
-             (match_operand 2 "" "")))
-   (use (reg:DI 1))
-   (clobber (match_operand:DI 3 "register_operand" "=b"))]
-  ""
-  "br.call%+.many %3 = %1"
-  [(set_attr "type" "B")])
-
-(define_insn "*call_multiple_values_internal1"
-  [(match_parallel 0 "call_multiple_values_operation"
-                  [(set (match_operand 1 "register_operand" "=rf")
-                        (call (mem:DI (match_operand:DI 2 "call_operand" "bi"))
-                              (match_operand 3 "" "")))
-                   (use (reg:DI 1))
-                   (clobber (match_operand:DI 4 "register_operand" "=b"))])]
-  ""
-  "br.call%+.many %4 = %2"
-  [(set_attr "type" "B")])
-
 ;; Call subroutine returning any type.
 
 (define_expand "untyped_call"
   DONE;
 }")
 
+(define_insn "call_nopic"
+  [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
+        (match_operand 1 "" ""))
+   (clobber (match_operand:DI 2 "register_operand" "=b"))]
+  ""
+  "br.call%+.many %2 = %0"
+  [(set_attr "type" "B")])
+
+(define_insn "call_value_nopic"
+  [(set (match_operand 0 "" "")
+       (call (mem:DI (match_operand:DI 1 "call_operand" "bi"))
+             (match_operand 2 "" "")))
+   (clobber (match_operand:DI 3 "register_operand" "=b"))]
+  ""
+  "br.call%+.many %3 = %1"
+  [(set_attr "type" "B")])
+
+(define_insn "sibcall_nopic"
+  [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
+        (match_operand 1 "" ""))
+   (use (match_operand:DI 2 "register_operand" "=b"))]
+  ""
+  "br%+.many %0"
+  [(set_attr "type" "B")])
+
+(define_insn "call_pic"
+  [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
+        (match_operand 1 "" ""))
+   (use (unspec [(reg:DI 1)] 9))
+   (clobber (match_operand:DI 2 "register_operand" "=b"))]
+  ""
+  "br.call%+.many %2 = %0"
+  [(set_attr "type" "B")])
+
+(define_insn "call_value_pic"
+  [(set (match_operand 0 "" "")
+       (call (mem:DI (match_operand:DI 1 "call_operand" "bi"))
+             (match_operand 2 "" "")))
+   (use (unspec [(reg:DI 1)] 9))
+   (clobber (match_operand:DI 3 "register_operand" "=b"))]
+  ""
+  "br.call%+.many %3 = %1"
+  [(set_attr "type" "B")])
+
+(define_insn "sibcall_pic"
+  [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
+        (match_operand 1 "" ""))
+   (use (unspec [(reg:DI 1)] 9))
+   (use (match_operand:DI 2 "register_operand" "=b"))]
+  ""
+  "br%+.many %0"
+  [(set_attr "type" "B")])
+
 (define_insn "return_internal"
   [(return)
    (use (match_operand:DI 0 "register_operand" "b"))]
 }")
 
 (define_expand "epilogue"
-  [(const_int 2)]
+  [(return)]
+  ""
+  "
+{
+  ia64_expand_epilogue (0);
+  DONE;
+}")
+
+(define_expand "sibcall_epilogue"
+  [(return)]
   ""
   "
 {
-  ia64_expand_epilogue ();
+  ia64_expand_epilogue (1);
   DONE;
 }")
 
   [(set_attr "type" "I")])
 
 (define_insn "set_bsp"
-  [(unspec_volatile [(const_int 0)] 5)
-   (use (match_operand:DI 0 "register_operand" "r"))]
+  [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")] 5)]
   ""
   "flushrs\;mov r19=ar.rsc\;;;\;and r19=0x1c,r19\;;;\;mov ar.rsc=r19\;;;\;mov ar.bspstore=%0\;;;\;or r19=0x3,r19\;;;\;loadrs\;invala\;;;\;mov ar.rsc=r19"
   [(set_attr "type" "unknown")