]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/592 ([ARM/Thumb] Poor choice of PIC register)
authorRichard Earnshaw <rearnsha@arm.com>
Tue, 17 Jan 2006 20:22:19 +0000 (20:22 +0000)
committerRichard Earnshaw <rearnsha@gcc.gnu.org>
Tue, 17 Jan 2006 20:22:19 +0000 (20:22 +0000)
PR target/592
PR middle-end/11135
* arm.h (struct machine_function): Add pic_reg.
* arm.c (arm_pic_register): Make unsigned.
(arm_override_options): Only set arm_pic_register if
TARGET_SINGLE_PIC_BASE.
(use_return_insn): Only test for a pic register if it is fixed.
(arm_compute_save_reg0_reg12_mask): Likewise.
(thumb_compute_save_reg_mask): Likewise.
(legitimate_pic_operand): Factor out some known invariants.
(legitimize_pic_address): If we don't have a fixed pic register,
then set up a pseudo in the function entry sequence.  Handle the
pic base being in a pseudo.
(arm_load_pic_register): Handle the pic register being in a pseudo.
(arm_expand_prologue): Only set up the pic register if it is fixed.
(thumb_expand_prologue): Likewise.
* arm.md (pic_load_addr_based): Handle the pic base being a pseudo.
(pic_load_addr_based_insn): Likewise.
(builtin_setjmp_receiver): Don't restore the pic base if it isn't
fixed.

From-SVN: r109839

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md

index 252bab04b370487478c7f38d0e9b162b7b1f69f7..0fb17c1f3523fd2076083ba1d3a798e9b893d17e 100644 (file)
@@ -1,3 +1,26 @@
+2006-01-17  Richard Earnshaw  <rearnsha@arm.com>
+
+       PR target/592
+       PR middle-end/11135
+       * arm.h (struct machine_function): Add pic_reg.
+       * arm.c (arm_pic_register): Make unsigned.
+       (arm_override_options): Only set arm_pic_register if
+       TARGET_SINGLE_PIC_BASE.
+       (use_return_insn): Only test for a pic register if it is fixed.
+       (arm_compute_save_reg0_reg12_mask): Likewise.
+       (thumb_compute_save_reg_mask): Likewise.
+       (legitimate_pic_operand): Factor out some known invariants.
+       (legitimize_pic_address): If we don't have a fixed pic register,
+       then set up a pseudo in the function entry sequence.  Handle the
+       pic base being in a pseudo.
+       (arm_load_pic_register): Handle the pic register being in a pseudo.
+       (arm_expand_prologue): Only set up the pic register if it is fixed.
+       (thumb_expand_prologue): Likewise.
+       * arm.md (pic_load_addr_based): Handle the pic base being a pseudo.
+       (pic_load_addr_based_insn): Likewise.
+       (builtin_setjmp_receiver): Don't restore the pic base if it isn't
+       fixed.
+
 2006-01-18  Ben Elliston  <bje@au.ibm.com>
 
        * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Reject
index 8e3ade5caabacbe74fe275bec403b9f8b5c9c51f..e5309e046dddee03692dfce26b6c2b934dd31ee2 100644 (file)
@@ -1,6 +1,6 @@
 /* Output routines for GCC for ARM.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005  Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com).
@@ -524,7 +524,7 @@ int arm_cpp_interwork = 0;
 enum machine_mode output_memory_reference_mode;
 
 /* The register number to be used for the PIC offset register.  */
-int arm_pic_register = INVALID_REGNUM;
+unsigned arm_pic_register = INVALID_REGNUM;
 
 /* Set to 1 when a return insn is output, this means that the epilogue
    is not needed.  */
@@ -1096,7 +1096,7 @@ arm_override_options (void)
 
   /* If stack checking is disabled, we can use r10 as the PIC register,
      which keeps r9 available.  */
-  if (flag_pic)
+  if (flag_pic && TARGET_SINGLE_PIC_BASE)
     arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
 
   if (TARGET_APCS_FLOAT)
@@ -1547,7 +1547,9 @@ use_return_insn (int iscond, rtx sibling)
       if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
        return 0;
 
-      if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+      if (flag_pic 
+         && arm_pic_register != INVALID_REGNUM
+         && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
        return 0;
     }
 
@@ -3171,16 +3173,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 /* Addressing mode support functions.  */
 
 /* Return nonzero if X is a legitimate immediate operand when compiling
-   for PIC.  */
+   for PIC.  We know that X satisfies CONSTANT_P and flag_pic is true.  */
 int
 legitimate_pic_operand_p (rtx x)
 {
-  if (CONSTANT_P (x)
-      && flag_pic
-      && (GET_CODE (x) == SYMBOL_REF
-         || (GET_CODE (x) == CONST
-             && GET_CODE (XEXP (x, 0)) == PLUS
-             && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)))
+  if (GET_CODE (x) == SYMBOL_REF
+      || (GET_CODE (x) == CONST
+         && GET_CODE (XEXP (x, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
     return 0;
 
   return 1;
@@ -3198,6 +3198,49 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
       rtx insn;
       int subregs = 0;
 
+      /* If this function doesn't have a pic register, create one now.
+        A lot of the logic here is made obscure by the fact that this
+        routine gets called as part of the rtx cost estimation
+        process.  We don't want those calls to affect any assumptions
+        about the real function; and further, we can't call
+        entry_of_function() until we start the real expansion
+        process.  */
+      if (!current_function_uses_pic_offset_table)
+       {
+         gcc_assert (!no_new_pseudos);
+         if (arm_pic_register != INVALID_REGNUM)
+           {
+             cfun->machine->pic_reg = gen_rtx_REG (Pmode, arm_pic_register);
+
+             /* Play games to avoid marking the function as needing pic
+                if we are being called as part of the cost-estimation
+                process.  */
+             if (!ir_type())
+               current_function_uses_pic_offset_table = 1;
+           }
+         else
+           {
+             rtx seq;
+
+             cfun->machine->pic_reg = gen_reg_rtx (Pmode);
+
+             /* Play games to avoid marking the function as needing pic
+                if we are being called as part of the cost-estimation
+                process.  */
+             if (!ir_type())
+               {
+                 current_function_uses_pic_offset_table = 1;
+                 start_sequence ();
+
+                 arm_load_pic_register (0UL);
+
+                 seq = get_insns ();
+                 end_sequence ();
+                 emit_insn_after (seq, entry_of_function ());
+               }
+           }
+       }
+
       if (reg == 0)
        {
          gcc_assert (!no_new_pseudos);
@@ -3225,17 +3268,16 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
           || (GET_CODE (orig) == SYMBOL_REF &&
               SYMBOL_REF_LOCAL_P (orig)))
          && NEED_GOT_RELOC)
-       pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
+       pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
       else
        {
          pic_ref = gen_const_mem (Pmode,
-                                  gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
+                                  gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
                                                 address));
        }
 
       insn = emit_move_insn (reg, pic_ref);
 #endif
-      current_function_uses_pic_offset_table = 1;
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
@@ -3247,7 +3289,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
       rtx base, offset;
 
       if (GET_CODE (XEXP (orig, 0)) == PLUS
-         && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+         && XEXP (XEXP (orig, 0), 0) == cfun->machine->pic_reg)
        return orig;
 
       if (GET_CODE (XEXP (orig, 0)) == UNSPEC
@@ -3387,13 +3429,14 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
 
   if (TARGET_ARM)
     {
-      emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx));
-      emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx,
-                                            pic_offset_table_rtx, labelno));
+      emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
+      emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
+                                            cfun->machine->pic_reg, labelno));
     }
   else
     {
-      if (REGNO (pic_offset_table_rtx) > LAST_LO_REGNUM)
+      if (arm_pic_register != INVALID_REGNUM
+         && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
        {
          /* We will have pushed the pic register, so we should always be
             able to find a work register.  */
@@ -3403,14 +3446,14 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
          emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
        }
       else
-       emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx));
-      emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx,
-                                           pic_offset_table_rtx, labelno));
+       emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
+      emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
+                                           cfun->machine->pic_reg, labelno));
     }
 
   /* Need to emit this whether or not we obey regdecls,
      since setjmp/longjmp can cause life info to screw up.  */
-  emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+  emit_insn (gen_rtx_USE (VOIDmode, cfun->machine->pic_reg));
 #endif /* AOF_ASSEMBLER */
 }
 
@@ -3690,7 +3733,7 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
   /* This is PC relative data before arm_reorg runs.  */
   else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
           && GET_CODE (x) == SYMBOL_REF
-           && CONSTANT_POOL_ADDRESS_P (x) && ! flag_pic)
+           && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
     return 1;
 
   /* This is PC relative data after arm_reorg runs.  */
@@ -9173,6 +9216,7 @@ arm_compute_save_reg0_reg12_mask (void)
       /* Also save the pic base register if necessary.  */
       if (flag_pic
          && !TARGET_SINGLE_PIC_BASE
+         && arm_pic_register != INVALID_REGNUM
          && current_function_uses_pic_offset_table)
        save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
     }
@@ -9195,6 +9239,7 @@ arm_compute_save_reg0_reg12_mask (void)
         don't stack it even though it may be live.  */
       if (flag_pic
          && !TARGET_SINGLE_PIC_BASE
+         && arm_pic_register != INVALID_REGNUM
          && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
              || current_function_uses_pic_offset_table))
        save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
@@ -9312,6 +9357,7 @@ thumb_compute_save_reg_mask (void)
 
   if (flag_pic
       && !TARGET_SINGLE_PIC_BASE
+      && arm_pic_register != INVALID_REGNUM
       && current_function_uses_pic_offset_table)
     mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
 
@@ -10822,7 +10868,7 @@ arm_expand_prologue (void)
     }
 
 
-  if (flag_pic)
+  if (flag_pic && arm_pic_register != INVALID_REGNUM)
     arm_load_pic_register (0UL);
 
   /* If we are profiling, make sure no instructions are scheduled before
@@ -13584,7 +13630,7 @@ thumb_expand_prologue (void)
   live_regs_mask = thumb_compute_save_reg_mask ();
   /* Load the pic register before setting the frame pointer,
      so we can use r7 as a temporary work register.  */
-  if (flag_pic)
+  if (flag_pic && arm_pic_register != INVALID_REGNUM)
     arm_load_pic_register (live_regs_mask);
 
   if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
index b7b775c18bb3f8c0409b4eaccd0438c424330928..e2826dce49a7cf86a48d1497e59d2316d3c98e08 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions of target machine for GNU compiler, for ARM.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com)
@@ -1519,6 +1519,8 @@ typedef struct machine_function GTY(())
   /* Records if sibcalls are blocked because an argument
      register is needed to preserve stack alignment.  */
   int sibcall_blocked;
+  /* The PIC register for this function.  This might be a pseudo.  */
+  rtx pic_reg;
   /* Labels for per-function Thumb call-via stubs.  One per potential calling
      register.  We can never call via LR or PC.  We can call via SP if a
      trampoline happens to be on the top of the stack.  */
@@ -2206,7 +2208,7 @@ do {                                                      \
 /* We decide which register to use based on the compilation options and
    the assembler in use; this is more general than the APCS restriction of
    using sb (r9) all the time.  */
-extern int arm_pic_register;
+extern unsigned arm_pic_register;
 
 /* The register number of the register used to address a table of static
    data addresses in memory.  */
index a161d4d5a43f2f198a5426a52f9bf24de5391132..239961ad554c1ed32106089dd7f1d6592edf5427 100644 (file)
@@ -1,6 +1,6 @@
 ;;- Machine description for ARM for GNU compiler
 ;;  Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000,
-;;  2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
+;;  2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
 ;;  Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
 ;;  and Martin Simmons (@harleqn.co.uk).
 ;;  More major hacks by Richard Earnshaw (rearnsha@arm.com).
   [(set (match_operand:SI 0 "s_register_operand" "")
        (unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))]
   "TARGET_ARM && flag_pic"
-  "operands[2] = pic_offset_table_rtx;"
+  "operands[2] = cfun->machine->pic_reg;"
 )
 
 (define_insn "*pic_load_addr_based_insn"
        (unspec:SI [(match_operand 1 "" "")
                    (match_operand 2 "s_register_operand" "r")]
                   UNSPEC_PIC_SYM))]
-  "TARGET_EITHER && flag_pic && operands[2] == pic_offset_table_rtx"
+  "TARGET_EITHER && flag_pic && operands[2] == cfun->machine->pic_reg"
   "*
 #ifdef AOF_ASSEMBLER
   operands[1] = aof_pic_entry (operands[1]);
 {
   /* r3 is clobbered by set/longjmp, so we can use it as a scratch
      register.  */
-  arm_load_pic_register (3);
+  if (arm_pic_register != INVALID_REGNUM)
+    arm_load_pic_register (1UL << 3);
   DONE;
 }")