Add -mno-r11 support to PowerPC 64
authorMichael Meissner <meissner@linux.vnet.ibm.com>
Wed, 6 Jul 2011 23:09:20 +0000 (23:09 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Wed, 6 Jul 2011 23:09:20 +0000 (23:09 +0000)
From-SVN: r175943

gcc/ChangeLog
gcc/config/rs6000/rs6000-protos.h
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/rs6000.opt
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/no-r11-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/no-r11-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/no-r11-3.c [new file with mode: 0644]

index 147b828facf021014c1cdd590da224c643b4dabb..c9bcc574ec8cd0b9cc278d56b660f05e217c0688 100644 (file)
@@ -1,3 +1,69 @@
+2011-07-06  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * config/rs6000/rs6000-protos.h (rs6000_call_indirect_aix): New
+       declaration.
+       (rs6000_save_toc_in_prologue_p): Ditto.
+
+       * config/rs6000/rs6000.opt (-mr11): New switch to disable loading
+       up the static chain (r11) during indirect function calls.
+       (-msave-toc-indirect): New undocumented debug switch.
+
+       * config/rs6000/rs6000.c (struct machine_function): Add
+       save_toc_in_prologue field to note whether the prologue needs to
+       save the TOC value in the reserved stack location.
+       (rs6000_emit_prologue): Use TOC_REGNUM instead of 2.  If we need
+       to save the TOC in the prologue, do so.
+       (rs6000_trampoline_init): Don't allow creating AIX style
+       trampolines if -mno-r11 is in effect.
+       (rs6000_call_indirect_aix): New function to create AIX style
+       indirect calls, adding support for -mno-r11 to suppress loading
+       the static chain, and saving the TOC in the prologue instead of
+       the call body.
+       (rs6000_save_toc_in_prologue_p): Return true if we are saving the
+       TOC in the prologue.
+
+       * config/rs6000/rs6000.md (STACK_POINTER_REGNUM): Add more fixed
+       register numbers.
+       (TOC_REGNUM): Ditto.
+       (STATIC_CHAIN_REGNUM): Ditto.
+       (ARG_POINTER_REGNUM): Ditto.
+       (SFP_REGNO): Delete, unused.
+       (TOC_SAVE_OFFSET_32BIT): Add constants for AIX TOC save and
+       function descriptor offsets.
+       (TOC_SAVE_OFFSET_64BIT): Ditto.
+       (AIX_FUNC_DESC_TOC_32BIT): Ditto.
+       (AIX_FUNC_DESC_TOC_64BIT): Ditto.
+       (AIX_FUNC_DESC_SC_32BIT): Ditto.
+       (AIX_FUNC_DESC_SC_64BIT): Ditto.
+       (ptrload): New mode attribute for the appropriate load of a
+       pointer.
+       (call_indirect_aix32): Delete, rewrite AIX indirect function
+       calls.
+       (call_indirect_aix64): Ditto.
+       (call_value_indirect_aix32): Ditto.
+       (call_value_indirect_aix64): Ditto.
+       (call_indirect_nonlocal_aix32_internal): Ditto.
+       (call_indirect_nonlocal_aix32): Ditto.
+       (call_indirect_nonlocal_aix64_internal): Ditto.
+       (call_indirect_nonlocal_aix64): Ditto.
+       (call): Rewrite AIX indirect function calls.  Add support for
+       eliminating the static chain, and for moving the save of the TOC
+       to the function prologue.
+       (call_value): Ditto.
+       (call_indirect_aix<ptrsize>): Ditto.
+       (call_indirect_aix<ptrsize>_internal): Ditto.
+       (call_indirect_aix<ptrsize>_internal2): Ditto.
+       (call_indirect_aix<ptrsize>_nor11): Ditto.
+       (call_value_indirect_aix<ptrsize>): Ditto.
+       (call_value_indirect_aix<ptrsize>_internal): Ditto.
+       (call_value_indirect_aix<ptrsize>_internal2): Ditto.
+       (call_value_indirect_aix<ptrsize>_nor11): Ditto.
+       (call_nonlocal_aix32): Relocate in the rs6000.md file.
+       (call_nonlocal_aix64): Ditto.
+
+       * doc/invoke.texi (RS/6000 and PowerPC Options): Add -mr11 and
+       -mno-r11 documentation.
+
 2011-07-06  Jonathan Wakely  <jwakely.gcc@gmail.com>
 
        PR other/49658
index 36f2a4c124a06a43497d932cd61ba1a7787faf7d..357f7e720051cadc80102d5e8c10a68172c057b9 100644 (file)
@@ -171,6 +171,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 bool rs6000_save_toc_in_prologue_p (void);
 
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 
index a87280c8ec49c20aa6507d3b0c3ce826435cc76b..65de2e3f2fd422c9cf0799c3200c64320ae1f4de 100644 (file)
@@ -130,6 +130,9 @@ typedef struct GTY(()) machine_function
   int ra_need_lr;
   /* Cache lr_save_p after expansion of builtin_eh_return.  */
   int lr_save_state;
+  /* Whether we need to save the TOC to the reserved stack location in the
+     function prologue.  */
+  bool save_toc_in_prologue;
   /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
      varargs save area.  */
   HOST_WIDE_INT varargs_save_offset;
@@ -20325,7 +20328,7 @@ rs6000_emit_prologue (void)
       JUMP_LABEL (jump) = toc_save_done;
       LABEL_NUSES (toc_save_done) += 1;
 
-      emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2,
+      emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, TOC_REGNUM,
                       sp_offset + 5 * reg_size, info->total_size);
       emit_label (toc_save_done);
       if (using_static_chain_p)
@@ -20516,6 +20519,11 @@ rs6000_emit_prologue (void)
        emit_move_insn (lr, gen_rtx_REG (Pmode, 0));
     }
 #endif
+
+  /* If we need to, save the TOC register after doing the stack setup.  */
+  if (rs6000_save_toc_in_prologue_p ())
+    emit_frame_save (sp_reg_rtx, sp_reg_rtx, reg_mode, TOC_REGNUM,
+                    5 * reg_size, info->total_size);
 }
 
 /* Write function prologue.  */
@@ -24469,9 +24477,14 @@ rs6000_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
     /* Under AIX, just build the 3 word function descriptor */
     case ABI_AIX:
       {
-       rtx fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
-       rtx fn_reg = gen_reg_rtx (Pmode);
-       rtx toc_reg = gen_reg_rtx (Pmode);
+       rtx fnmem, fn_reg, toc_reg;
+
+       if (!TARGET_R11)
+         error ("-mno-r11 must not be used if you have trampolines");
+
+       fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
+       fn_reg = gen_reg_rtx (Pmode);
+       toc_reg = gen_reg_rtx (Pmode);
 
   /* Macro to shorten the code expansions below.  */
 # define MEM_PLUS(MEM, OFFSET) adjust_address (MEM, Pmode, OFFSET)
@@ -27760,4 +27773,132 @@ rs6000_legitimate_constant_p (enum machine_mode mode, rtx x)
          || easy_vector_constant (x, mode));
 }
 
+\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.  */
+
+void
+rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag)
+{
+  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 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_R11)
+       {
+         call_func = gen_call_indirect_aix32bit;
+         call_value_func = gen_call_value_indirect_aix32bit;
+       }
+      else
+       {
+         call_func = gen_call_indirect_aix32bit_nor11;
+         call_value_func = gen_call_value_indirect_aix32bit_nor11;
+       }
+    }
+  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_R11)
+       {
+         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;
+       }
+    }
+
+  /* Reserved spot to store the TOC.  */
+  stack_toc_mem = gen_frame_mem (Pmode,
+                                gen_rtx_PLUS (Pmode,
+                                              stack_ptr,
+                                              stack_toc_offset));
+
+  gcc_assert (cfun);
+  gcc_assert (cfun->machine);
+
+  /* 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->calls_setjmp && !cfun->has_nonlocal_label
+      && !cfun->can_throw_non_call_exceptions
+      && ((flags_from_decl_or_type (cfun->decl) & ECF_NOTHROW) == ECF_NOTHROW))
+    cfun->machine->save_toc_in_prologue = true;
+
+  else
+    {
+      MEM_VOLATILE_P (stack_toc_mem) = 1;
+      emit_move_insn (stack_toc_mem, toc_reg);
+    }
+
+  /* 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));
+
+  /* If we have a static chain, load it up.  */
+  if (TARGET_R11)
+    {
+      func_sc_mem = gen_rtx_MEM (Pmode,
+                                gen_rtx_PLUS (Pmode,
+                                              func_desc,
+                                              func_sc_offset));
+
+      sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+      emit_move_insn (sc_reg, func_sc_mem);
+    }
+
+  /* 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);
+
+  emit_call_insn (insn);
+  return;
+}
+
+/* Return whether we need to always update the saved TOC pointer when we update
+   the stack pointer.  */
+
+bool
+rs6000_save_toc_in_prologue_p (void)
+{
+  return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);
+}
+
 #include "gt-rs6000.h"
index e70598d9f3e7707aac518dd7203c6ae9949db237..8c0e299a2e76b3b49857a61940d677d5cee51bb5 100644 (file)
 ;;
 
 (define_constants
-  [(MQ_REGNO                   64)
+  [(STACK_POINTER_REGNUM       1)
+   (TOC_REGNUM                 2)
+   (STATIC_CHAIN_REGNUM                11)
+   (HARD_FRAME_POINTER_REGNUM  31)
+   (MQ_REGNO                   64)
    (LR_REGNO                   65)
    (CTR_REGNO                  66)
+   (ARG_POINTER_REGNUM         67)
    (CR0_REGNO                  68)
    (CR1_REGNO                  69)
    (CR2_REGNO                  70)
    (VSCR_REGNO                 110)
    (SPE_ACC_REGNO              111)
    (SPEFSCR_REGNO              112)
-   (SFP_REGNO                  113)
+   (FRAME_POINTER_REGNUM       113)
+
+   ; 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)
   ])
 
 ;;
 (define_mode_attr mptrsize [(SI "si")
                            (DI "di")])
 
+(define_mode_attr ptrload [(SI "{l|lwz}")
+                          (DI "ld")])
+
 (define_mode_attr rreg [(SF   "f")
                        (DF   "ws")
                        (V4SF "wf")
    "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
    "{cal %0,%2@l(%1)|addi %0,%1,%2@l}")
 \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.
-
-(define_expand "call_indirect_aix32"
-  [(set (match_dup 2)
-       (mem:SI (match_operand:SI 0 "gpc_reg_operand" "")))
-   (set (mem:SI (plus:SI (reg:SI 1) (const_int 20)))
-       (reg:SI 2))
-   (set (reg:SI 11)
-       (mem:SI (plus:SI (match_dup 0)
-                        (const_int 8))))
-   (parallel [(call (mem:SI (match_dup 2))
-                   (match_operand 1 "" ""))
-             (use (mem:SI (plus:SI (match_dup 0) (const_int 4))))
-             (use (reg:SI 11))
-             (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-             (clobber (reg:SI LR_REGNO))])]
-  "TARGET_32BIT"
-  "
-{ operands[2] = gen_reg_rtx (SImode); }")
-
-(define_expand "call_indirect_aix64"
-  [(set (match_dup 2)
-       (mem:DI (match_operand:DI 0 "gpc_reg_operand" "")))
-   (set (mem:DI (plus:DI (reg:DI 1) (const_int 40)))
-       (reg:DI 2))
-   (set (reg:DI 11)
-       (mem:DI (plus:DI (match_dup 0)
-                        (const_int 16))))
-   (parallel [(call (mem:SI (match_dup 2))
-                   (match_operand 1 "" ""))
-             (use (mem:DI (plus:DI (match_dup 0) (const_int 8))))
-             (use (reg:DI 11))
-             (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-             (clobber (reg:SI LR_REGNO))])]
-  "TARGET_64BIT"
-  "
-{ operands[2] = gen_reg_rtx (DImode); }")
-
-(define_expand "call_value_indirect_aix32"
-  [(set (match_dup 3)
-       (mem:SI (match_operand:SI 1 "gpc_reg_operand" "")))
-   (set (mem:SI (plus:SI (reg:SI 1) (const_int 20)))
-       (reg:SI 2))
-   (set (reg:SI 11)
-       (mem:SI (plus:SI (match_dup 1)
-                        (const_int 8))))
-   (parallel [(set (match_operand 0 "" "")
-                  (call (mem:SI (match_dup 3))
-                        (match_operand 2 "" "")))
-             (use (mem:SI (plus:SI (match_dup 1) (const_int 4))))
-             (use (reg:SI 11))
-             (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-             (clobber (reg:SI LR_REGNO))])]
-  "TARGET_32BIT"
-  "
-{ operands[3] = gen_reg_rtx (SImode); }")
-
-(define_expand "call_value_indirect_aix64"
-  [(set (match_dup 3)
-       (mem:DI (match_operand:DI 1 "gpc_reg_operand" "")))
-   (set (mem:DI (plus:DI (reg:DI 1) (const_int 40)))
-       (reg:DI 2))
-   (set (reg:DI 11)
-       (mem:DI (plus:DI (match_dup 1)
-                        (const_int 16))))
-   (parallel [(set (match_operand 0 "" "")
-                  (call (mem:SI (match_dup 3))
-                        (match_operand 2 "" "")))
-             (use (mem:DI (plus:DI (match_dup 1) (const_int 8))))
-             (use (reg:DI 11))
-             (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-             (clobber (reg:SI LR_REGNO))])]
-  "TARGET_64BIT"
-  "
-{ operands[3] = gen_reg_rtx (DImode); }")
-
-;; Now the definitions for the call and call_value insns
+;; Call and call_value insns
 (define_expand "call"
   [(parallel [(call (mem:SI (match_operand 0 "address_operand" ""))
                    (match_operand 1 "" ""))
        case ABI_AIX:
          /* AIX function pointers are really pointers to a three word
             area.  */
-         emit_call_insn (TARGET_32BIT
-                         ? gen_call_indirect_aix32 (force_reg (SImode,
-                                                               operands[0]),
-                                                    operands[1])
-                         : gen_call_indirect_aix64 (force_reg (DImode,
-                                                               operands[0]),
-                                                    operands[1]));
+         rs6000_call_indirect_aix (NULL_RTX, operands[0], operands[1]);
          DONE;
 
        default:
        case ABI_AIX:
          /* AIX function pointers are really pointers to a three word
             area.  */
-         emit_call_insn (TARGET_32BIT
-                         ? gen_call_value_indirect_aix32 (operands[0],
-                                                          force_reg (SImode,
-                                                                     operands[1]),
-                                                          operands[2])
-                         : gen_call_value_indirect_aix64 (operands[0],
-                                                          force_reg (DImode,
-                                                                     operands[1]),
-                                                          operands[2]));
+         rs6000_call_indirect_aix (operands[0], operands[1], operands[2]);
          DONE;
 
        default:
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
-;; 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.
+;; 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_and_split "*call_indirect_nonlocal_aix32_internal"
-  [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l"))
-                (match_operand 1 "" "g,g"))
-   (use (mem:SI (plus:SI (match_operand:SI 2 "register_operand" "b,b") (const_int 4))))
-   (use (reg:SI 11))
-   (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX"
+(define_insn_and_split "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" "m,m"))
+   (use (match_operand:P 3 "memory_operand" "m,m"))
+   (use (reg:P STATIC_CHAIN_REGNUM))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && TARGET_R11"
   "#"
   "&& reload_completed"
-  [(set (reg:SI 2)
-       (mem:SI (plus:SI (match_dup 2) (const_int 4))))
+  [(set (reg:P TOC_REGNUM) (match_dup 2))
    (parallel [(call (mem:SI (match_dup 0))
                    (match_dup 1))
-             (use (reg:SI 2))
-             (use (reg:SI 11))
-             (set (reg:SI 2)
-                  (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-             (clobber (reg:SI LR_REGNO))])]
+             (use (reg:P TOC_REGNUM))
+             (use (reg:P STATIC_CHAIN_REGNUM))
+             (use (match_dup 3))
+             (set (reg:P TOC_REGNUM) (match_dup 3))
+             (clobber (reg:P LR_REGNO))])]
   ""
   [(set_attr "type" "jmpreg")
    (set_attr "length" "12")])
 
-(define_insn "*call_indirect_nonlocal_aix32"
-  [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l"))
+(define_insn "*call_indirect_aix<ptrsize>_internal"
+  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
         (match_operand 1 "" "g,g"))
-   (use (reg:SI 2))
-   (use (reg:SI 11))
-   (set (reg:SI 2)
-       (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
-  "b%T0l\;{l|lwz} 2,20(1)"
+   (use (reg:P TOC_REGNUM))
+   (use (reg:P STATIC_CHAIN_REGNUM))
+   (use (match_operand:P 2 "memory_operand" "m,m"))
+   (set (reg:P TOC_REGNUM) (match_dup 2))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && reload_completed && TARGET_R11"
+  "b%T0l\;<ptrload> 2,%2"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
-(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\;%."
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-   
-(define_insn_and_split "*call_indirect_nonlocal_aix64_internal"
-  [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l"))
-                (match_operand 1 "" "g,g"))
-   (use (mem:DI (plus:DI (match_operand:DI 2 "register_operand" "b,b")
-                        (const_int 8))))
-   (use (reg:DI 11))
-   (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX"
+;; Like call_indirect_aix<ptrsize>, except don't load 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_and_split "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" "m,m"))
+   (use (match_operand:P 3 "memory_operand" "m,m"))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && !TARGET_R11"
   "#"
   "&& reload_completed"
-  [(set (reg:DI 2)
-       (mem:DI (plus:DI (match_dup 2) (const_int 8))))
+  [(set (reg:P TOC_REGNUM) (match_dup 2))
    (parallel [(call (mem:SI (match_dup 0))
                    (match_dup 1))
-             (use (reg:DI 2))
-             (use (reg:DI 11))
-             (set (reg:DI 2)
-                  (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-             (clobber (reg:SI LR_REGNO))])]
+             (use (reg:P TOC_REGNUM))
+             (use (match_dup 3))
+             (set (reg:P TOC_REGNUM) (match_dup 3))
+             (clobber (reg:P LR_REGNO))])]
   ""
   [(set_attr "type" "jmpreg")
    (set_attr "length" "12")])
 
-(define_insn "*call_indirect_nonlocal_aix64"
-  [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l"))
+(define_insn "*call_indirect_aix<ptrsize>_internal2"
+  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
         (match_operand 1 "" "g,g"))
-   (use (reg:DI 2))
-   (use (reg:DI 11))
-   (set (reg:DI 2)
-       (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
-  "b%T0l\;ld 2,40(1)"
+   (use (reg:P TOC_REGNUM))
+   (use (match_operand:P 2 "memory_operand" "m,m"))
+   (set (reg:P TOC_REGNUM) (match_dup 2))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && reload_completed && !TARGET_R11"
+  "b%T0l\;<ptrload> 2,%2"
   [(set_attr "type" "jmpreg")
    (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\;%."
-  [(set_attr "type" "branch")
+;; 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_and_split "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" "m,m"))
+   (use (match_operand:P 4 "memory_operand" "m,m"))
+   (use (reg:P STATIC_CHAIN_REGNUM))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && TARGET_R11"
+  "#"
+  "&& reload_completed"
+  [(set (reg:P TOC_REGNUM) (match_dup 3))
+   (parallel [(set (match_dup 0)
+                  (call (mem:SI (match_dup 1))
+                        (match_dup 2)))
+             (use (reg:P TOC_REGNUM))
+             (use (reg:P STATIC_CHAIN_REGNUM))
+             (use (match_dup 4))
+             (set (reg:P TOC_REGNUM) (match_dup 4))
+             (clobber (reg:P LR_REGNO))])]
+  ""
+  [(set_attr "type" "jmpreg")
+   (set_attr "length" "12")])
+
+(define_insn "*call_value_indirect_aix<ptrsize>_internal"
+  [(set (match_operand 0 "" "")
+       (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+             (match_operand 2 "" "g,g")))
+   (use (reg:P TOC_REGNUM))
+   (use (reg:P STATIC_CHAIN_REGNUM))
+   (use (match_operand:P 3 "memory_operand" "m,m"))
+   (set (reg:P TOC_REGNUM) (match_dup 3))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && reload_completed && TARGET_R11"
+  "b%T1l\;<ptrload> 2,%3"
+  [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
-(define_insn_and_split "*call_value_indirect_nonlocal_aix32_internal"
+;; Like call_value_indirect_aix<ptrsize>, but don't load 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_and_split "call_value_indirect_aix<ptrsize>_nor11"
   [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l"))
-                     (match_operand 2 "" "g,g")))
-       (use (mem:SI (plus:SI (match_operand:SI 3 "register_operand" "b,b")
-                             (const_int 4))))
-       (use (reg:SI 11))
-       (use (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-       (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX"
+       (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+             (match_operand 2 "" "g,g")))
+   (use (match_operand:P 3 "memory_operand" "m,m"))
+   (use (match_operand:P 4 "memory_operand" "m,m"))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && !TARGET_R11"
   "#"
   "&& reload_completed"
-  [(set (reg:SI 2)
-       (mem:SI (plus:SI (match_dup 3) (const_int 4))))
-   (parallel [(set (match_dup 0) (call (mem:SI (match_dup 1))
-                                      (match_dup 2)))
-             (use (reg:SI 2))
-             (use (reg:SI 11))
-             (set (reg:SI 2)
-                  (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-             (clobber (reg:SI LR_REGNO))])]
+  [(set (reg:P TOC_REGNUM) (match_dup 3))
+   (parallel [(set (match_dup 0)
+                  (call (mem:SI (match_dup 1))
+                        (match_dup 2)))
+             (use (reg:P TOC_REGNUM))
+             (use (match_dup 4))
+             (set (reg:P TOC_REGNUM) (match_dup 4))
+             (clobber (reg:P LR_REGNO))])]
   ""
   [(set_attr "type" "jmpreg")
    (set_attr "length" "12")])
 
-(define_insn "*call_value_indirect_nonlocal_aix32"
+(define_insn "*call_value_indirect_aix<ptrsize>_internal2"
   [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l"))
+       (call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
              (match_operand 2 "" "g,g")))
-   (use (reg:SI 2))
-   (use (reg:SI 11))
-   (set (reg:SI 2)
-       (mem:SI (plus:SI (reg:SI 1) (const_int 20))))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_32BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
-  "b%T1l\;{l|lwz} 2,20(1)"
+   (use (reg:P TOC_REGNUM))
+   (use (match_operand:P 3 "memory_operand" "m,m"))
+   (set (reg:P TOC_REGNUM) (match_dup 3))
+   (clobber (reg:P LR_REGNO))]
+  "DEFAULT_ABI == ABI_AIX && reload_completed && !TARGET_R11"
+  "b%T1l\;<ptrload> 2,%3"
   [(set_attr "type" "jmpreg")
    (set_attr "length" "8")])
 
+;; 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\;%."
+  [(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\;%."
+  [(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"))
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
-(define_insn_and_split "*call_value_indirect_nonlocal_aix64_internal"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l"))
-                     (match_operand 2 "" "g,g")))
-       (use (mem:DI (plus:DI (match_operand:DI 3 "register_operand" "b,b")
-                             (const_int 8))))
-       (use (reg:DI 11))
-       (use (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-       (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX"
-  "#"
-  "&& reload_completed"
-  [(set (reg:DI 2)
-       (mem:DI (plus:DI (match_dup 3) (const_int 8))))
-   (parallel [(set (match_dup 0) (call (mem:SI (match_dup 1))
-                                      (match_dup 2)))
-             (use (reg:DI 2))
-             (use (reg:DI 11))
-             (set (reg:DI 2)
-                  (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-             (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-(define_insn "*call_value_indirect_nonlocal_aix64"
-  [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l"))
-             (match_operand 2 "" "g,g")))
-   (use (reg:DI 2))
-   (use (reg:DI 11))
-   (set (reg:DI 2)
-       (mem:DI (plus:DI (reg:DI 1) (const_int 40))))
-   (clobber (reg:SI LR_REGNO))]
-  "TARGET_64BIT && DEFAULT_ABI == ABI_AIX && reload_completed"
-  "b%T1l\;ld 2,40(1)"
-  [(set_attr "type" "jmpreg")
-   (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"))
index 35c936fe53e0e35cae263aa1b2edfb3b6a35e0ca..329104c441c1da90a05a5b5d564b6b24c56a1f28 100644 (file)
@@ -521,4 +521,10 @@ mxilinx-fpu
 Target Var(rs6000_xilinx_fpu) Save
 Specify Xilinx FPU.
 
+mr11
+Target Report Var(TARGET_R11) Init(1) Save
+Use/do not use r11 to hold the static link in calls.
 
+msave-toc-indirect
+Target Undocumented Var(TARGET_SAVE_TOC_INDIRECT) Save Init(1)
+; Control whether we save the TOC in the prologue for indirect calls or generate the save inline
index c5e369ac6f89de61a0d37fc81390b846587fc765..223a9d525ab087eb9bc80730f2a3109a5c2f2dcb 100644 (file)
@@ -807,7 +807,7 @@ See RS/6000 and PowerPC Options.
 -msdata=@var{opt}  -mvxworks  -G @var{num}  -pthread @gol
 -mrecip -mrecip=@var{opt} -mno-recip -mrecip-precision @gol
 -mno-recip-precision @gol
--mveclibabi=@var{type} -mfriz -mno-friz}
+-mveclibabi=@var{type} -mfriz -mno-friz -mr11 -mno-r11}
 
 @emph{RX Options}
 @gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
@@ -16325,6 +16325,19 @@ Generate (do not generate) the @code{friz} instruction when the
 rounding a floating point value to 64-bit integer and back to floating
 point.  The @code{friz} instruction does not return the same value if
 the floating point number is too large to fit in an integer.
+
+@item -mr11
+@itemx -mno-r11
+@opindex mr11
+Generate (do not generate) code to load up the static chain register
+(@var{r11}) when calling through a pointer on AIX and 64-bit Linux
+systems where a function pointer points to a 3 word descriptor giving
+the function address, TOC value to be loaded in register @var{r2}, and
+static chain value to be loaded in register @var{r11}.  The
+@option{-mr11} is on by default.  You will not be able to call through
+pointers to nested functions or pointers to functions compiled in
+other languages that use the static chain if you use the
+@option{-mno-r11}.
 @end table
 
 @node RX Options
index 6ca307d68ed20dc0a9c0666ef838ebf617f562b2..f176a448cb50947ce19f36b54de8fd7b24ebe6c0 100644 (file)
@@ -1,3 +1,9 @@
+2011-07-06  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * gcc.target/powerpc/no-r11-1.c: New test for -mr11, -mno-r11.
+       * gcc.target/powerpc/no-r11-2.c: Ditto.
+       * gcc.target/powerpc/no-r11-3.c: Ditto.
+
 2011-07-06  Uros Bizjak  <ubizjak@gmail.com>
 
        * gcc.dg/stack-layout-2.c: Cleanup expand rtl dump.
diff --git a/gcc/testsuite/gcc.target/powerpc/no-r11-1.c b/gcc/testsuite/gcc.target/powerpc/no-r11-1.c
new file mode 100644 (file)
index 0000000..7e880e7
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
+/* { dg-options "-O2 -mno-r11" } */
+
+int
+call_ptr (int (func) (void))
+{
+  return func () + 1;
+}
+
+/* { dg-final { scan-assembler-not "ld 11,16(3)" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/no-r11-2.c b/gcc/testsuite/gcc.target/powerpc/no-r11-2.c
new file mode 100644 (file)
index 0000000..981bc0c
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
+/* { dg-options "-O2 -mr11" } */
+
+int
+call_ptr (int (func) (void))
+{
+  return func () + 1;
+}
+
+/* { dg-final { scan-assembler "ld 11,16" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/no-r11-3.c b/gcc/testsuite/gcc.target/powerpc/no-r11-3.c
new file mode 100644 (file)
index 0000000..bc57385
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */
+/* { dg-options "-O2 -mno-r11" } */
+
+extern void ext_call (int (func) (void));
+
+int
+outer_func (int init)  /* { dg-error "-mno-r11 must not be used if you have trampolines" "" } */
+{
+  int value = init;
+
+  int inner (void)
+  {
+    return ++value;
+  }
+
+  ext_call (inner);
+  return value;
+}
+