rs6000.c (rs6000_call_indirect_aix): Rename to ...
authorUlrich Weigand <uweigand@de.ibm.com>
Thu, 14 Nov 2013 18:32:48 +0000 (18:32 +0000)
committerUlrich Weigand <uweigand@gcc.gnu.org>
Thu, 14 Nov 2013 18:32:48 +0000 (18:32 +0000)
2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>

* config/rs6000/rs6000.c (rs6000_call_indirect_aix): Rename to ...
(rs6000_call_aix): ... this.  Handle both direct and indirect calls.
Create call insn directly instead of via various gen_... routines.
Mention special registers used by the call in CALL_INSN_FUNCTION_USAGE.
(rs6000_sibcall_aix): New function.
* config/rs6000/rs6000.md (TOC_SAVE_OFFSET_32BIT): Remove.
(TOC_SAVE_OFFSET_64BIT): Likewise.
(AIX_FUNC_DESC_TOC_32BIT): Likewise.
(AIX_FUNC_DESC_TOC_64BIT): Likewise.
(AIX_FUNC_DESC_SC_32BIT): Likewise.
(AIX_FUNC_DESC_SC_64BIT): Likewise.
("call" expander): Call rs6000_call_aix.
("call_value" expander): Likewise.
("call_indirect_aix<ptrsize>"): Replace this pattern ...
("call_indirect_aix<ptrsize>_nor11"): ... and this pattern ...
("*call_indirect_aix<mode>"): ... by this insn pattern.
("call_value_indirect_aix<ptrsize>"): Replace this pattern ...
("call_value_indirect_aix<ptrsize>_nor11"): ... and this pattern ...
("*call_value_indirect_aix<mode>"): ... by this insn pattern.
("*call_nonlocal_aix32", "*call_nonlocal_aix64"): Replace by ...
("*call_nonlocal_aix<mode>"): ... this pattern.
("*call_value_nonlocal_aix32", "*call_value_nonlocal_aix64"): Replace
("*call_value_nonlocal_aix<mode>"): ... by this pattern.
("*call_local_aix<mode>"): New insn pattern.
("*call_value_local_aix<mode>"): Likewise.
("sibcall" expander): Call rs6000_sibcall_aix.
("sibcall_value" expander): Likewise.  Move earlier in file.
("*sibcall_nonlocal_aix<mode>"): Replace by ...
("*sibcall_aix<mode>"): ... this pattern.
("*sibcall_value_nonlocal_aix<mode>"): Replace by ...
("*sibcall_value_aix<mode>"): ... this pattern.
* config/rs6000/rs6000-protos.h (rs6000_call_indirect_aix): Remove.
(rs6000_call_aix): Add prototype.
(rs6000_sibcall_aix): Likewise.

From-SVN: r204803

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

index 8d0d893..e27898d 100644 (file)
@@ -1,3 +1,40 @@
+2013-11-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+
+       * config/rs6000/rs6000.c (rs6000_call_indirect_aix): Rename to ...
+       (rs6000_call_aix): ... this.  Handle both direct and indirect calls.
+       Create call insn directly instead of via various gen_... routines.
+       Mention special registers used by the call in CALL_INSN_FUNCTION_USAGE.
+       (rs6000_sibcall_aix): New function.
+       * config/rs6000/rs6000.md (TOC_SAVE_OFFSET_32BIT): Remove.
+       (TOC_SAVE_OFFSET_64BIT): Likewise.
+       (AIX_FUNC_DESC_TOC_32BIT): Likewise.
+       (AIX_FUNC_DESC_TOC_64BIT): Likewise.
+       (AIX_FUNC_DESC_SC_32BIT): Likewise.
+       (AIX_FUNC_DESC_SC_64BIT): Likewise.
+       ("call" expander): Call rs6000_call_aix.
+       ("call_value" expander): Likewise.
+       ("call_indirect_aix<ptrsize>"): Replace this pattern ...
+       ("call_indirect_aix<ptrsize>_nor11"): ... and this pattern ...
+       ("*call_indirect_aix<mode>"): ... by this insn pattern.
+       ("call_value_indirect_aix<ptrsize>"): Replace this pattern ...
+       ("call_value_indirect_aix<ptrsize>_nor11"): ... and this pattern ...
+       ("*call_value_indirect_aix<mode>"): ... by this insn pattern.
+       ("*call_nonlocal_aix32", "*call_nonlocal_aix64"): Replace by ...
+       ("*call_nonlocal_aix<mode>"): ... this pattern.
+       ("*call_value_nonlocal_aix32", "*call_value_nonlocal_aix64"): Replace
+       ("*call_value_nonlocal_aix<mode>"): ... by this pattern.
+       ("*call_local_aix<mode>"): New insn pattern.
+       ("*call_value_local_aix<mode>"): Likewise.
+       ("sibcall" expander): Call rs6000_sibcall_aix.
+       ("sibcall_value" expander): Likewise.  Move earlier in file.
+       ("*sibcall_nonlocal_aix<mode>"): Replace by ...
+       ("*sibcall_aix<mode>"): ... this pattern.
+       ("*sibcall_value_nonlocal_aix<mode>"): Replace by ...
+       ("*sibcall_value_aix<mode>"): ... this pattern.
+       * config/rs6000/rs6000-protos.h (rs6000_call_indirect_aix): Remove.
+       (rs6000_call_aix): Add prototype.
+       (rs6000_sibcall_aix): Likewise.
+
 2013-11-14  Jakub Jelinek  <jakub@redhat.com>
 
        PR sanitizer/59122
index d1d1737..3c99c3c 100644 (file)
@@ -182,7 +182,8 @@ extern unsigned int rs6000_dbx_register_number (unsigned int);
 extern void rs6000_emit_epilogue (int);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern const char * output_isel (rtx *);
-extern void rs6000_call_indirect_aix (rtx, rtx, rtx);
+extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
+extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 extern void get_ppc476_thunk_name (char name[32]);
 extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
index 1628bf3..e3ca62e 100644 (file)
@@ -30604,118 +30604,138 @@ rs6000_legitimate_constant_p (enum machine_mode mode, rtx x)
 }
 
 \f
-/* A function pointer under AIX is a pointer to a data area whose first word
-   contains the actual address of the function, whose second word contains a
-   pointer to its TOC, and whose third word contains a value to place in the
-   static chain register (r11).  Note that if we load the static chain, our
-   "trampoline" need not have any executable code.  */
+
+/* Expand code to perform a call under the AIX ABI.  */
 
 void
-rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag)
+rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 {
+  rtx toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
+  rtx toc_load = NULL_RTX;
+  rtx toc_restore = NULL_RTX;
   rtx func_addr;
-  rtx toc_reg;
-  rtx sc_reg;
-  rtx stack_ptr;
-  rtx stack_toc_offset;
-  rtx stack_toc_mem;
-  rtx func_toc_offset;
-  rtx func_toc_mem;
-  rtx func_sc_offset;
-  rtx func_sc_mem;
+  rtx abi_reg = NULL_RTX;
+  rtx call[4];
+  int n_call;
   rtx insn;
-  rtx (*call_func) (rtx, rtx, rtx, rtx);
-  rtx (*call_value_func) (rtx, rtx, rtx, rtx, rtx);
-
-  stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
-  toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
-
-  /* Load up address of the actual function.  */
-  func_desc = force_reg (Pmode, func_desc);
-  func_addr = gen_reg_rtx (Pmode);
-  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
-
-  if (TARGET_32BIT)
-    {
 
-      stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_32BIT);
-      func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_32BIT);
-      func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_32BIT);
-      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
-       {
-         call_func = gen_call_indirect_aix32bit;
-         call_value_func = gen_call_value_indirect_aix32bit;
-       }
+  /* Handle longcall attributes.  */
+  if (INTVAL (cookie) & CALL_LONG)
+    func_desc = rs6000_longcall_ref (func_desc);
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func_desc) != SYMBOL_REF
+      || !SYMBOL_REF_FUNCTION_P (func_desc))
+    {
+      /* Save the TOC into its reserved slot before the call,
+        and prepare to restore it after the call.  */
+      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+      rtx stack_toc_offset = GEN_INT (5 * GET_MODE_SIZE (Pmode));
+      rtx stack_toc_mem = gen_frame_mem (Pmode,
+                                        gen_rtx_PLUS (Pmode, stack_ptr,
+                                                      stack_toc_offset));
+      toc_restore = gen_rtx_SET (VOIDmode, toc_reg, stack_toc_mem);
+
+      /* Can we optimize saving the TOC in the prologue or
+        do we need to do it at every call?  */
+      if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
+       cfun->machine->save_toc_in_prologue = true;
       else
        {
-         call_func = gen_call_indirect_aix32bit_nor11;
-         call_value_func = gen_call_value_indirect_aix32bit_nor11;
+         MEM_VOLATILE_P (stack_toc_mem) = 1;
+         emit_move_insn (stack_toc_mem, toc_reg);
+       }
+
+      /* A function pointer under AIX is a pointer to a data area whose
+        first word contains the actual address of the function, whose
+        second word contains a pointer to its TOC, and whose third word
+        contains a value to place in the static chain register (r11).
+        Note that if we load the static chain, our "trampoline" need
+        not have any executable code.  */
+
+      /* Load up address of the actual function.  */
+      func_desc = force_reg (Pmode, func_desc);
+      func_addr = gen_reg_rtx (Pmode);
+      emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
+
+      /* Prepare to load the TOC of the called function.  Note that the
+        TOC load must happen immediately before the actual call so
+        that unwinding the TOC registers works correctly.  See the
+        comment in frob_update_context.  */
+      rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode));
+      rtx func_toc_mem = gen_rtx_MEM (Pmode,
+                                     gen_rtx_PLUS (Pmode, func_desc,
+                                                   func_toc_offset));
+      toc_load = gen_rtx_USE (VOIDmode, func_toc_mem);
+
+      /* If we have a static chain, load it up.  */
+      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+       {
+         rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+         rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
+         rtx func_sc_mem = gen_rtx_MEM (Pmode,
+                                        gen_rtx_PLUS (Pmode, func_desc,
+                                                      func_sc_offset));
+         emit_move_insn (sc_reg, func_sc_mem);
+         abi_reg = sc_reg;
        }
     }
   else
     {
-      stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_64BIT);
-      func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_64BIT);
-      func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_64BIT);
-      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
-       {
-         call_func = gen_call_indirect_aix64bit;
-         call_value_func = gen_call_value_indirect_aix64bit;
-       }
-      else
-       {
-         call_func = gen_call_indirect_aix64bit_nor11;
-         call_value_func = gen_call_value_indirect_aix64bit_nor11;
-       }
+      /* Direct calls use the TOC: for local calls, the callee will
+        assume the TOC register is set; for non-local calls, the
+        PLT stub needs the TOC register.  */
+      abi_reg = toc_reg;
+      func_addr = func_desc;
     }
 
-  /* Reserved spot to store the TOC.  */
-  stack_toc_mem = gen_frame_mem (Pmode,
-                                gen_rtx_PLUS (Pmode,
-                                              stack_ptr,
-                                              stack_toc_offset));
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (VOIDmode, value, call[0]);
+  n_call = 1;
 
-  gcc_assert (cfun);
-  gcc_assert (cfun->machine);
+  if (toc_load)
+    call[n_call++] = toc_load;
+  if (toc_restore)
+    call[n_call++] = toc_restore;
 
-  /* Can we optimize saving the TOC in the prologue or do we need to do it at
-     every call?  */
-  if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
-    cfun->machine->save_toc_in_prologue = true;
+  call[n_call++] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
 
-  else
-    {
-      MEM_VOLATILE_P (stack_toc_mem) = 1;
-      emit_move_insn (stack_toc_mem, toc_reg);
-    }
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (n_call, call));
+  insn = emit_call_insn (insn);
 
-  /* Calculate the address to load the TOC of the called function.  We don't
-     actually load this until the split after reload.  */
-  func_toc_mem = gen_rtx_MEM (Pmode,
-                             gen_rtx_PLUS (Pmode,
-                                           func_desc,
-                                           func_toc_offset));
+  /* Mention all registers defined by the ABI to hold information
+     as uses in CALL_INSN_FUNCTION_USAGE.  */
+  if (abi_reg)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
+}
 
-  /* If we have a static chain, load it up.  */
-  if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
-    {
-      func_sc_mem = gen_rtx_MEM (Pmode,
-                                gen_rtx_PLUS (Pmode,
-                                              func_desc,
-                                              func_sc_offset));
+/* Expand code to perform a sibling call under the AIX ABI.  */
 
-      sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
-      emit_move_insn (sc_reg, func_sc_mem);
-    }
+void
+rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+{
+  rtx call[2];
+  rtx insn;
+
+  gcc_assert (INTVAL (cookie) == 0);
 
   /* Create the call.  */
-  if (value)
-    insn = call_value_func (value, func_addr, flag, func_toc_mem,
-                           stack_toc_mem);
-  else
-    insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (VOIDmode, value, call[0]);
+
+  call[1] = simple_return_rtx;
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (2, call));
+  insn = emit_call_insn (insn);
 
-  emit_call_insn (insn);
+  /* Note use of the TOC register.  */
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
+  /* We need to also mark a use of the link register since the function we
+     sibling-call to will use it to return to our caller.  */
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, LR_REGNO));
 }
 
 /* Return whether we need to always update the saved TOC pointer when we update
index 2020468..b3311e6 100644 (file)
    (TFHAR_REGNO                        114)
    (TFIAR_REGNO                        115)
    (TEXASR_REGNO               116)
-
-   ; ABI defined stack offsets for storing the TOC pointer with AIX calls.
-   (TOC_SAVE_OFFSET_32BIT      20)
-   (TOC_SAVE_OFFSET_64BIT      40)
-
-   ; Function TOC offset in the AIX function descriptor.
-   (AIX_FUNC_DESC_TOC_32BIT    4)
-   (AIX_FUNC_DESC_TOC_64BIT    8)
-
-   ; Static chain offset in the AIX function descriptor.
-   (AIX_FUNC_DESC_SC_32BIT     8)
-   (AIX_FUNC_DESC_SC_64BIT     16)
   ])
 
 ;;
 
   operands[0] = XEXP (operands[0], 0);
 
+  if (DEFAULT_ABI == ABI_AIX)
+    {
+      rs6000_call_aix (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
+    }
+
   if (GET_CODE (operands[0]) != SYMBOL_REF
-      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0]))
       || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
     {
       if (INTVAL (operands[2]) & CALL_LONG)
          operands[0] = force_reg (Pmode, operands[0]);
          break;
 
-       case ABI_AIX:
-         /* AIX function pointers are really pointers to a three word
-            area.  */
-         rs6000_call_indirect_aix (NULL_RTX, operands[0], operands[1]);
-         DONE;
-
        default:
          gcc_unreachable ();
        }
 
   operands[1] = XEXP (operands[1], 0);
 
+  if (DEFAULT_ABI == ABI_AIX)
+    {
+      rs6000_call_aix (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
+    }
+
   if (GET_CODE (operands[1]) != SYMBOL_REF
-      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1]))
       || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
     {
       if (INTVAL (operands[3]) & CALL_LONG)
          operands[1] = force_reg (Pmode, operands[1]);
          break;
 
-       case ABI_AIX:
-         /* AIX function pointers are really pointers to a three word
-            area.  */
-         rs6000_call_indirect_aix (operands[0], operands[1], operands[2]);
-         DONE;
-
        default:
          gcc_unreachable ();
        }
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
-;; Call to indirect functions with the AIX abi using a 3 word descriptor.
-;; Operand0 is the addresss of the function to call
-;; Operand1 is the flag for System V.4 for unprototyped or FP registers
-;; Operand2 is the location in the function descriptor to load r2 from
-;; Operand3 is the stack location to hold the current TOC pointer
-
-(define_insn "call_indirect_aix<ptrsize>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-        (match_operand 1 "" "g,g"))
-   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (use (reg:P STATIC_CHAIN_REGNUM))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && TARGET_POINTERS_TO_NESTED_FUNCTIONS"
-  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-;; Like call_indirect_aix<ptrsize>, but no use of the static chain
-;; Operand0 is the addresss of the function to call
-;; Operand1 is the flag for System V.4 for unprototyped or FP registers
-;; Operand2 is the location in the function descriptor to load r2 from
-;; Operand3 is the stack location to hold the current TOC pointer
-
-(define_insn "call_indirect_aix<ptrsize>_nor11"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-        (match_operand 1 "" "g,g"))
-   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && !TARGET_POINTERS_TO_NESTED_FUNCTIONS"
-  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-;; Operand0 is the return result of the function
-;; Operand1 is the addresss of the function to call
-;; Operand2 is the flag for System V.4 for unprototyped or FP registers
-;; Operand3 is the location in the function descriptor to load r2 from
-;; Operand4 is the stack location to hold the current TOC pointer
-
-(define_insn "call_value_indirect_aix<ptrsize>"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-             (match_operand 2 "" "g,g")))
-   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
-   (use (reg:P STATIC_CHAIN_REGNUM))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && TARGET_POINTERS_TO_NESTED_FUNCTIONS"
-  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-;; Like call_value_indirect_aix<ptrsize>, but no use of the static chain
-;; Operand0 is the return result of the function
-;; Operand1 is the addresss of the function to call
-;; Operand2 is the flag for System V.4 for unprototyped or FP registers
-;; Operand3 is the location in the function descriptor to load r2 from
-;; Operand4 is the stack location to hold the current TOC pointer
-
-(define_insn "call_value_indirect_aix<ptrsize>_nor11"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-             (match_operand 2 "" "g,g")))
-   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && !TARGET_POINTERS_TO_NESTED_FUNCTIONS"
-  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-;; Call to function which may be in another module.  Restore the TOC
-;; pointer (r2) after the call unless this is System V.
-;; Operand2 is nonzero if we are using the V.4 calling sequence and
-;; either the function was not prototyped, or it was prototyped as a
-;; variable argument function.  It is > 0 if FP registers were passed
-;; and < 0 if they were not.
-
-(define_insn "*call_nonlocal_aix32"
-  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s"))
-        (match_operand 1 "" "g"))
-   (use (match_operand:SI 2 "immediate_operand" "O"))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT
-   && DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[2]) & CALL_LONG) == 0"
-  "bl %z0\;nop"
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-   
-(define_insn "*call_nonlocal_aix64"
-  [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s"))
-        (match_operand 1 "" "g"))
-   (use (match_operand:SI 2 "immediate_operand" "O"))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT
-   && DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[2]) & CALL_LONG) == 0"
-  "bl %z0\;nop"
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*call_value_nonlocal_aix32"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s"))
-             (match_operand 2 "" "g")))
-   (use (match_operand:SI 3 "immediate_operand" "O"))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT
-   && DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[3]) & CALL_LONG) == 0"
-  "bl %z1\;nop"
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*call_value_nonlocal_aix64"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s"))
-             (match_operand 2 "" "g")))
-   (use (match_operand:SI 3 "immediate_operand" "O"))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT
-   && DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[3]) & CALL_LONG) == 0"
-  "bl %z1\;nop"
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
 
 ;; A function pointer under System V is just a normal pointer
 ;; operands[0] is the function pointer
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
 
+
+;; Call to AIX abi function in the same module.
+
+(define_insn "*call_local_aix<mode>"
+  [(call (mem:SI (match_operand:P 0 "current_file_function_operand" "s"))
+        (match_operand 1 "" "g"))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX"
+  "bl %z0"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*call_value_local_aix<mode>"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:P 1 "current_file_function_operand" "s"))
+             (match_operand 2 "" "g")))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX"
+  "bl %z1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+;; Call to AIX abi function which may be in another module.
+;; Restore the TOC pointer (r2) after the call.
+
+(define_insn "*call_nonlocal_aix<mode>"
+  [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s"))
+        (match_operand 1 "" "g"))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX"
+  "bl %z0\;nop"
+  [(set_attr "type" "branch")
+   (set_attr "length" "8")])
+
+(define_insn "*call_value_nonlocal_aix<mode>"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
+             (match_operand 2 "" "g")))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX"
+  "bl %z1\;nop"
+  [(set_attr "type" "branch")
+   (set_attr "length" "8")])
+
+;; Call to indirect functions with the AIX abi using a 3 word descriptor.
+;; Operand0 is the addresss of the function to call
+;; Operand2 is the location in the function descriptor to load r2 from
+;; Operand3 is the stack location to hold the current TOC pointer
+
+(define_insn "*call_indirect_aix<mode>"
+  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+        (match_operand 1 "" "g,g"))
+   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
+   (set (reg:P TOC_REGNUM) (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX"
+  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3"
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
+(define_insn "*call_value_indirect_aix<mode>"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
+   (set (reg:P TOC_REGNUM) (match_operand:P 4 "memory_operand" "<ptrm>,<ptrm>"))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX"
+  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4"
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
+
 ;; Call subroutine returning any type.
 (define_expand "untyped_call"
   [(parallel [(call (match_operand 0 "" "")
   gcc_assert (GET_CODE (operands[1]) == CONST_INT);
 
   operands[0] = XEXP (operands[0], 0);
+
+  if (DEFAULT_ABI == ABI_AIX)
+    {
+      rs6000_sibcall_aix (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
+    }
+}")
+
+(define_expand "sibcall_value"
+  [(parallel [(set (match_operand 0 "register_operand" "")
+               (call (mem:SI (match_operand 1 "address_operand" ""))
+                     (match_operand 2 "" "")))
+             (use (match_operand 3 "" ""))
+             (use (reg:SI LR_REGNO))
+             (simple_return)])]
+  ""
+  "
+{
+#if TARGET_MACHO
+  if (MACHOPIC_INDIRECT)
+    operands[1] = machopic_indirect_call_target (operands[1]);
+#endif
+
+  gcc_assert (GET_CODE (operands[1]) == MEM);
+  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
+
+  operands[1] = XEXP (operands[1], 0);
+
+  if (DEFAULT_ABI == ABI_AIX)
+    {
+      rs6000_sibcall_aix (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
+    }
 }")
 
 ;; this and similar patterns must be marked as using LR, otherwise
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
-
 (define_insn "*sibcall_value_local64"
   [(set (match_operand 0 "" "")
        (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
-(define_insn "*sibcall_nonlocal_aix<mode>"
-  [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
-        (match_operand 1 "" "g,g"))
-   (use (match_operand:SI 2 "immediate_operand" "O,O"))
-   (use (reg:SI LR_REGNO))
-   (simple_return)]
-  "DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[2]) & CALL_LONG) == 0"
-  "@
-   b %z0
-   b%T0"
-  [(set_attr "type" "branch")
-   (set_attr "length" "4")])
-
-(define_insn "*sibcall_value_nonlocal_aix<mode>"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
-             (match_operand 2 "" "g,g")))
-   (use (match_operand:SI 3 "immediate_operand" "O,O"))
-   (use (reg:SI LR_REGNO))
-   (simple_return)]
-  "DEFAULT_ABI == ABI_AIX
-   && (INTVAL (operands[3]) & CALL_LONG) == 0"
-  "@
-   b %z1
-   b%T1"
-  [(set_attr "type" "branch")
-   (set_attr "length" "4")])
-
 (define_insn "*sibcall_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c"))
         (match_operand 1 "" ""))
   [(set_attr "type" "branch")
    (set_attr "length" "4,8,4,8")])
 
-(define_expand "sibcall_value"
-  [(parallel [(set (match_operand 0 "register_operand" "")
-               (call (mem:SI (match_operand 1 "address_operand" ""))
-                     (match_operand 2 "" "")))
-             (use (match_operand 3 "" ""))
-             (use (reg:SI LR_REGNO))
-             (simple_return)])]
-  ""
-  "
-{
-#if TARGET_MACHO
-  if (MACHOPIC_INDIRECT)
-    operands[1] = machopic_indirect_call_target (operands[1]);
-#endif
-
-  gcc_assert (GET_CODE (operands[1]) == MEM);
-  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
-
-  operands[1] = XEXP (operands[1], 0);
-}")
-
 (define_insn "*sibcall_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
        (call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c"))
   [(set_attr "type" "branch")
    (set_attr "length" "4,8,4,8")])
 
+;; AIX ABI sibling call patterns.
+
+(define_insn "*sibcall_aix<mode>"
+  [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
+        (match_operand 1 "" "g,g"))
+   (simple_return)]
+  "DEFAULT_ABI == ABI_AIX"
+  "@
+   b %z0
+   b%T0"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
+(define_insn "*sibcall_value_aix<mode>"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
+             (match_operand 2 "" "g,g")))
+   (simple_return)]
+  "DEFAULT_ABI == ABI_AIX"
+  "@
+   b %z1
+   b%T1"
+  [(set_attr "type" "branch")
+   (set_attr "length" "4")])
+
 (define_expand "sibcall_epilogue"
   [(use (const_int 0))]
   ""