OSDN Git Service

Apply Philip Blundell <pb@nexus.co.uk>'s patch to add PIC support to the Thumb.
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Jul 1999 16:35:08 +0000 (16:35 +0000)
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Jul 1999 16:35:08 +0000 (16:35 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28268 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/arm/thumb.c
gcc/config/arm/thumb.h
gcc/config/arm/thumb.md
gcc/invoke.texi

index 6b34124..76e8aee 100644 (file)
@@ -1,3 +1,51 @@
+Mon Jul 26 17:24:51 1999  Philip Blundell  <pb@nexus.co.uk>
+
+       * config/arm/thumb.h (THUMB_FLAG_SINGLE_PIC_BASE): Define.
+       (TARGET_SINGLE_PIC_BASE): Likewise.
+       (GOT_PCREL, NEED_GOT_RELOC, NEED_PLT_RELOC): Provide default
+       definitions.
+       (TARGET_CALLEE_INTERWORKING): Fix typo in comment.
+       (TARGET_SWITCHES): Add -m{no-}single-pic-base.
+       (TARGET_OPTIONS): Add -mpic-register=N.
+       (OUTPUT_INT_ADDR_CONST): New macro.
+       (INDEX_REGISTER_RTX_P, PIC_OFFSET_TABLE_REGNUM, FINALIZE_PIC,
+       LEGITIMATE_PIC_OPERAND_P): Likewise.
+       (LEGITIMIZE_ADDRESS, GOT_IF_LEGITIMATE_ADDRESS): Support PIC.
+       (ASM_OUTPUT_INT): Use OUTPUT_INT_ADDR_CONST rather than calling
+       output_addr_const directly.
+       (PRINT_OPERAND_PUNCT_VALID_P): Accept `|' for compatibility with 
+       ARM port.
+       (thumb_pic_register, thumb_pic_register_string): Declare.
+       
+       * config/arm/thumb.c (symbol_mentioned_p): New function: Imported
+       from arm.c.
+       (label_mentioned_p): New function: Imported from arm.c.
+       (legitimize_pic_address): New function: Imported from arm.c.
+       (is_pic):New function: Imported from arm.c.
+       (thumb_finalize_pic):New function: Imported from arm.c.
+       (add_constant): Cope with PIC constants.
+       (fixit): Cope with PIC constants.
+       (output_return): Do not treat the PIC register as live if
+       TARGET_SINGLE_PIC_BASE is true.
+       (thumb_function_prologue): Do not treat the PIC register as live if
+       TARGET_SINGLE_PIC_BASE is true.
+       (thumb_expand_prologue): Do not treat the PIC register as live if
+       TARGET_SINGLE_PIC_BASE is true.
+       (thumb_unexpand_epilogue): Do not treat the PIC register as live if
+       TARGET_SINGLE_PIC_BASE is true.
+       (thumb_print_operand): Accept '|'.
+       (thumb_override_options): Process PIC options.
+       
+       * config/arm/thumb.md (movsi): Support PIC.
+       (call_insn): Change "i" constraint to "X".
+       (call_value_insn): Likewise.
+       (consttable_4, consttable_8, consttable_end): Set and clear
+       "making_const_table" as appropriate.
+       (pic_load_addr, pic_add_dot_plus_four): New insns.
+       
+       * invoke.texi (Thumb Options): Fix spelling.  Document new 
+       options -msingle-pic-base and -mpic-register=.
+       
 1999-07-26  Andrew Haley  <aph@cygnus.com>
 
        * config/m32r/initfini.c (__init): Use a full word immediate for
index 122cb24..fa09524 100644 (file)
@@ -32,6 +32,9 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "tree.h"
 #include "expr.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "toplev.h"
 
 \f
 int current_function_anonymous_args = 0;
@@ -40,12 +43,19 @@ int current_function_anonymous_args = 0;
 char * structure_size_string = NULL;
 int    arm_structure_size_boundary = 32; /* Used to be 8 */
 
+/* The register number to be used for the PIC offset register.  */
+const char * thumb_pic_register_string = NULL;
+int thumb_pic_register = 10;
+
+/* True if we are currently building a constant table. */
+int making_const_table;
+
 \f
 /* Predicates */
 int
 reload_memory_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED ;
 {
   int regno = true_regnum (op);
 
@@ -70,7 +80,6 @@ int
 thumb_shiftable_const (val)
      HOST_WIDE_INT val;
 {
-  unsigned HOST_WIDE_INT x = val;
   unsigned HOST_WIDE_INT mask = 0xff;
   int i;
 
@@ -106,6 +115,221 @@ thumb_trivial_epilogue ()
 }
 
 \f
+/* Return TRUE if X references a SYMBOL_REF.  */
+int
+symbol_mentioned_p (x)
+     rtx x;
+{
+  register char * fmt;
+  register int i;
+
+  if (GET_CODE (x) == SYMBOL_REF)
+    return 1;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (symbol_mentioned_p (XVECEXP (x, i, j)))
+             return 1;
+       }
+      else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Return TRUE if X references a LABEL_REF.  */
+int
+label_mentioned_p (x)
+     rtx x;
+{
+  register char * fmt;
+  register int i;
+
+  if (GET_CODE (x) == LABEL_REF)
+    return 1;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         register int j;
+
+         for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+           if (label_mentioned_p (XVECEXP (x, i, j)))
+             return 1;
+       }
+      else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
+       return 1;
+    }
+
+  return 0;
+}
+
+rtx
+legitimize_pic_address (orig, mode, reg)
+     rtx orig;
+     enum machine_mode mode;
+     rtx reg;
+{
+  if (GET_CODE (orig) == SYMBOL_REF)
+    {
+      rtx pic_ref, address;
+      rtx insn;
+      int subregs = 0;
+
+      if (reg == 0)
+       {
+         if (reload_in_progress || reload_completed)
+           abort ();
+         else
+           reg = gen_reg_rtx (Pmode);
+
+         subregs = 1;
+       }
+
+#ifdef AOF_ASSEMBLER
+      /* The AOF assembler can generate relocations for these directly, and
+        understands that the PIC register has to be added into the offset.
+        */
+      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
+#else
+      if (subregs)
+       address = gen_reg_rtx (Pmode);
+      else
+       address = reg;
+
+      emit_insn (gen_pic_load_addr (address, orig));
+
+      pic_ref = gen_rtx_MEM (Pmode,
+                            gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
+                                          address));
+      RTX_UNCHANGING_P (pic_ref) = 1;
+      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,
+                                           REG_NOTES (insn));
+      return reg;
+    }
+  else if (GET_CODE (orig) == CONST)
+    {
+      rtx base, offset;
+
+      if (GET_CODE (XEXP (orig, 0)) == PLUS
+         && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+       return orig;
+
+      if (reg == 0)
+       {
+         if (reload_in_progress || reload_completed)
+           abort ();
+         else
+           reg = gen_reg_rtx (Pmode);
+       }
+
+      if (GET_CODE (XEXP (orig, 0)) == PLUS)
+       {
+         base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+         offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+                                          base == reg ? 0 : reg);
+       }
+      else
+       abort ();
+
+      if (GET_CODE (offset) == CONST_INT)
+       {
+         /* The base register doesn't really matter, we only want to
+            test the index for the appropriate mode.  */
+         if (INDEX_REGISTER_RTX_P (offset) && GET_MODE_SIZE (mode) <= 4)
+           goto win;
+
+         if (! reload_in_progress && ! reload_completed)
+           offset = force_reg (Pmode, offset);
+         else
+           abort ();
+
+       win:
+         if (GET_CODE (offset) == CONST_INT)
+           return plus_constant_for_output (base, INTVAL (offset));
+       }
+
+      if (GET_MODE_SIZE (mode) > 4)
+       {
+         emit_insn (gen_addsi3 (reg, base, offset));
+         return reg;
+       }
+
+      return gen_rtx_PLUS (Pmode, base, offset);
+    }
+  else if (GET_CODE (orig) == LABEL_REF)
+    current_function_uses_pic_offset_table = 1;
+
+  return orig;
+}
+
+static rtx pic_rtx;
+
+int
+is_pic(x)
+     rtx x;
+{
+  if (x == pic_rtx)
+    return 1;
+  return 0;
+}
+
+void
+thumb_finalize_pic ()
+{
+#ifndef AOF_ASSEMBLER
+  rtx l1, pic_tmp, pic_tmp2, seq;
+  rtx global_offset_table;
+
+  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
+    return;
+
+  if (! flag_pic)
+    abort ();
+
+  start_sequence ();
+  l1 = gen_label_rtx ();
+
+  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+  /* On the Thumb the PC register contains 'dot + 4' at the time of the
+     addition.  XXX Is this true?  */
+  pic_tmp = plus_constant (gen_rtx_LABEL_REF (Pmode, l1), 4);
+  if (GOT_PCREL)
+    pic_tmp2 = gen_rtx_CONST (VOIDmode,
+                           gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
+  else
+    pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
+
+  pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
+  
+  emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx));
+  emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
+
+  seq = gen_sequence ();
+  end_sequence ();
+  emit_insn_after (seq, get_insns ());
+
+  /* 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));
+#endif /* AOF_ASSEMBLER */
+}
+
+\f
 /* Routines for handling the constant pool */
 /* This is unashamedly hacked from the version in sh.c, since the problem is
    extremely similar.  */
@@ -194,6 +418,10 @@ add_constant (x, mode)
   if (mode == SImode && GET_CODE (x) == MEM && CONSTANT_P (XEXP (x, 0))
       && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
     x = get_pool_constant (XEXP (x, 0));
+#ifndef AOF_ASSEMBLER
+  else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == 3)
+    x = XVECEXP (x, 0, 0);
+#endif
 
   /* First see if we've already got it */
  
@@ -272,6 +500,10 @@ fixit (src, mode)
      rtx src;
      enum machine_mode mode;
 {
+#ifndef AOF_ASSEMBLER
+  if (GET_CODE (src) == UNSPEC && XINT (src, 1) == 3)
+    return 1;
+#endif
   return ((CONSTANT_P (src)
           && (GET_CODE (src) != CONST_INT
               || ! (CONST_OK_FOR_LETTER_P (INTVAL (src), 'I')
@@ -1004,7 +1236,8 @@ output_return ()
   return_used_this_function = 1;
 
   for (regno = 0; regno < 8; regno++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno])
+    if (regs_ever_live[regno] && ! call_used_regs[regno]
+       && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register)))
       live_regs_mask |= 1 << regno;
 
   if (live_regs_mask == 0)
@@ -1120,7 +1353,8 @@ thumb_function_prologue (f, frame_size)
     }
 
   for (regno = 0; regno < 8; regno++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno])
+    if (regs_ever_live[regno] && ! call_used_regs[regno]
+       && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register)))
       live_regs_mask |= 1 << regno;
 
   if (live_regs_mask || ! leaf_function_p () || far_jump_used_p())
@@ -1214,7 +1448,8 @@ thumb_function_prologue (f, frame_size)
 
   for (regno = 8; regno < 13; regno++)
     {
-      if (regs_ever_live[regno] && ! call_used_regs[regno])
+      if (regs_ever_live[regno] && ! call_used_regs[regno]
+         && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register)))
        high_regs_pushed++;
     }
 
@@ -1226,7 +1461,8 @@ thumb_function_prologue (f, frame_size)
 
       for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--)
        {
-         if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg])
+         if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]
+             && ! (TARGET_SINGLE_PIC_BASE && (next_hi_reg == thumb_pic_register)))
            break;
        }
 
@@ -1253,7 +1489,9 @@ thumb_function_prologue (f, frame_size)
                    for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--)
                      {
                        if (regs_ever_live[next_hi_reg]
-                           && ! call_used_regs[next_hi_reg])
+                           && ! call_used_regs[next_hi_reg]
+                           && ! (TARGET_SINGLE_PIC_BASE 
+                                 && (next_hi_reg == thumb_pic_register)))
                          break;
                      }
                  else
@@ -1289,7 +1527,8 @@ thumb_expand_prologue ()
     {
       live_regs_mask = 0;
       for (regno = 0; regno < 8; regno++)
-       if (regs_ever_live[regno] && ! call_used_regs[regno])
+       if (regs_ever_live[regno] && ! call_used_regs[regno]
+           && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register)))
          live_regs_mask |= 1 << regno;
 
       if (amount < 512)
@@ -1399,12 +1638,14 @@ thumb_unexpanded_epilogue ()
     return "";
 
   for (regno = 0; regno < 8; regno++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno])
+    if (regs_ever_live[regno] && ! call_used_regs[regno]
+       && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register)))
       live_regs_mask |= 1 << regno;
 
   for (regno = 8; regno < 13; regno++)
     {
-      if (regs_ever_live[regno] && ! call_used_regs[regno])
+      if (regs_ever_live[regno] && ! call_used_regs[regno]
+         && ! (TARGET_SINGLE_PIC_BASE && (regno == thumb_pic_register)))
        high_regs_pushed ++;
     }
 
@@ -1455,7 +1696,8 @@ thumb_unexpanded_epilogue ()
        }
       
       for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
-       if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg])
+       if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]
+           && ! (TARGET_SINGLE_PIC_BASE && (next_hi_reg == thumb_pic_register)))
          break;
 
       while (high_regs_pushed)
@@ -1483,7 +1725,9 @@ thumb_unexpanded_epilogue ()
                               reg_names[next_hi_reg], reg_names[regno]);
                  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
                    if (regs_ever_live[next_hi_reg] && 
-                       ! call_used_regs[next_hi_reg])
+                       ! call_used_regs[next_hi_reg]
+                       && ! (TARGET_SINGLE_PIC_BASE 
+                             && (next_hi_reg == thumb_pic_register)))
                      break;
                }
            }
@@ -1788,6 +2032,10 @@ thumb_print_operand (f, x, code)
          fputs (ASM_COMMENT_START, f);
          return;
 
+       case '|':
+         /* fputs (REGISTER_PREFIX, f); */
+         return;
+
        case '_':
          fputs (user_label_prefix, f);
          return;
@@ -2042,10 +2290,23 @@ thumb_override_options ()
        warning ("Structure size boundary can only be set to 8 or 32");
     }
 
-  if (flag_pic)
+  if (thumb_pic_register_string != NULL)
     {
-      warning ("Position independent code not supported.  Ignored");
-      flag_pic = 0;
+      int pic_register;
+
+      if (! flag_pic)
+       warning ("-mpic-register= is useless without -fpic");
+
+      pic_register = decode_reg_name (thumb_pic_register_string);
+      
+      /* Prevent the user from choosing an obviously stupid PIC register.  */
+      if (pic_register < 0 || call_used_regs[pic_register]
+         || pic_register == HARD_FRAME_POINTER_REGNUM
+         || pic_register == STACK_POINTER_REGNUM
+         || pic_register >= PC_REGNUM)
+       error ("Unable to use '%s' for PIC register", thumb_pic_register_string);
+      else
+       thumb_pic_register = pic_register;
     }
 }
 \f
index be2a0e4..434bd5e 100644 (file)
@@ -59,6 +59,7 @@ Boston, MA 02111-1307, USA.  */
 #define THUMB_FLAG_BACKTRACE                   0x0002
 #define THUMB_FLAG_LEAF_BACKTRACE              0x0004
 #define ARM_FLAG_THUMB                         0x1000  /* same as in arm.h */
+#define THUMB_FLAG_SINGLE_PIC_BASE             0x4000  /* same as in arm.h */
 #define THUMB_FLAG_CALLEE_SUPER_INTERWORKING   0x40000 
 #define THUMB_FLAG_CALLER_SUPER_INTERWORKING   0x80000 
 
@@ -71,8 +72,17 @@ extern int target_flags;
 #define TARGET_BACKTRACE       (leaf_function_p()                            \
                                 ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \
                                 : (target_flags & THUMB_FLAG_BACKTRACE))
+#define TARGET_SINGLE_PIC_BASE (target_flags & THUMB_FLAG_SINGLE_PIC_BASE)
 
-/* Set if externally visable functions should assume that they
+#ifndef GOT_PCREL
+#define GOT_PCREL              0
+#endif
+
+#ifndef NEED_GOT_RELOC
+#define NEED_GOT_RELOC         1
+#endif
+
+/* Set if externally visible functions should assume that they
    might be called in ARM mode, from a non-thumb aware code.  */
 #define TARGET_CALLEE_INTERWORKING     \
      (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING)
@@ -101,6 +111,9 @@ extern int target_flags;
   {"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \
   {"caller-super-interworking",            THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \
   {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \
+  {"single-pic-base",              THUMB_FLAG_SINGLE_PIC_BASE, \
+     "Do not load the PIC register in function prologues" },   \
+  {"no-single-pic-base",          -THUMB_FLAG_SINGLE_PIC_BASE, "" }, \
   SUBTARGET_SWITCHES                                           \
   {"",                          TARGET_DEFAULT}                \
 }
@@ -108,6 +121,8 @@ extern int target_flags;
 #define TARGET_OPTIONS                                         \
 {                                                              \
   { "structure-size-boundary=", & structure_size_string },     \
+  { "pic-register=", & thumb_pic_register_string,              \
+     "Specify the register to be used for PIC addressing" }    \
 }
 
 #define REGISTER_PREFIX ""
@@ -170,7 +185,7 @@ extern int target_flags;
 #define ASM_OUTPUT_INT(STREAM,VALUE)                                   \
 {                                                                      \
   fprintf (STREAM, "\t.word\t");                                       \
-  output_addr_const (STREAM, (VALUE));                                 \
+  OUTPUT_INT_ADDR_CONST (STREAM, (VALUE));                             \
   fprintf (STREAM, "\n");                                              \
 }
 
@@ -556,6 +571,9 @@ enum reg_class
   ((REGNO) < 8                                 \
    || (unsigned) reg_renumber[REGNO] < 8)
 
+#define INDEX_REGISTER_RTX_P(X)  \
+  (GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X))
+
 /* ??? This looks suspiciously wrong.  */
 /* We need to leave BASE_REGS reloads alone, in order to avoid caller_save
    lossage.  Caller_saves requests a BASE_REGS reload (caller_save_spill_class)
@@ -633,6 +651,9 @@ int thumb_shiftable_const ();
 
 #define STATIC_CHAIN_REGNUM 9
 
+/* Define this if the program counter is overloaded on a register.  */
+#define PC_REGNUM              15
+
 #define FRAME_POINTER_REQUIRED 0
 
 #define ELIMINABLE_REGS                                \
@@ -798,6 +819,39 @@ int thumb_shiftable_const ();
 }
 
 \f
+/* Position Independent Code.  */
+/* We decide which register to use based on the compilation options and
+   the assembler in use.  @@@ Actually, we don't currently for Thumb.  */
+extern int thumb_pic_register;
+
+/* The register number of the register used to address a table of static
+   data addresses in memory.  */
+#define PIC_OFFSET_TABLE_REGNUM thumb_pic_register
+
+#define FINALIZE_PIC thumb_finalize_pic ()
+
+/* We can't directly access anything that contains a symbol,
+   nor can we indirect via the constant pool.  */
+#define LEGITIMATE_PIC_OPERAND_P(X)                            \
+       (! symbol_mentioned_p (X)                               \
+        && (! CONSTANT_POOL_ADDRESS_P (X)                      \
+            || ! symbol_mentioned_p (get_pool_constant (X))))
+
+/* We need to know when we are making a constant pool; this determines
+   whether data needs to be in the GOT or can be referenced via a GOT
+   offset.  */
+extern int making_const_table;
+
+#define CONDITIONAL_REGISTER_USAGE  \
+{                                                      \
+  if (flag_pic)                                                \
+    {                                                  \
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;         \
+      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;     \
+    }                                                  \
+}
+
+\f
 /* Implicit Calls to Library Routines */
 
 #define TARGET_MEM_FUNCTIONS 1
@@ -884,7 +938,7 @@ int thumb_shiftable_const ();
     goto WIN;                                                          \
   /* This is PC relative data before MACHINE_DEPENDENT_REORG runs.  */ \
   else if (GET_MODE_SIZE (MODE) >= 4 && CONSTANT_P (X)                 \
-          && CONSTANT_POOL_ADDRESS_P (X))                              \
+          && CONSTANT_POOL_ADDRESS_P (X) && ! flag_pic)                \
     goto WIN;                                                          \
   /* This is PC relative data after MACHINE_DEPENDENT_REORG runs.  */  \
   else if (GET_MODE_SIZE (MODE) >= 4 && reload_completed               \
@@ -955,6 +1009,12 @@ int thumb_shiftable_const ();
               && (INTVAL (XEXP (X, 1)) & 3) == 0)                      \
        goto WIN;                                                       \
     }                                                                  \
+  else if (GET_MODE_CLASS (MODE) != MODE_FLOAT                         \
+          && GET_CODE (X) == SYMBOL_REF                                \
+          && CONSTANT_POOL_ADDRESS_P (X)                               \
+          && ! (flag_pic                                               \
+                && symbol_mentioned_p (get_pool_constant (X))))        \
+    goto WIN;                                                          \
 }
 
 /* ??? If an HImode FP+large_offset address is converted to an HImode
@@ -985,7 +1045,10 @@ int thumb_shiftable_const ();
   
 #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)
 
-#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)
+extern struct rtx_def * legitimize_pic_address ();
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)                         \
+  if (flag_pic)                                                                \
+    (X) = legitimize_pic_address (OLDX, MODE, NULL_RTX);
 
 #define LEGITIMATE_CONSTANT_P(X)       \
  (GET_CODE (X) == CONST_INT            \
@@ -1078,6 +1141,28 @@ int thumb_shiftable_const ();
 \f
 /* Position Independent Code */
 
+extern const char * thumb_pic_register_string;
+extern int thumb_pic_register;
+
+/* The register number of the register used to address a table of static
+   data addresses in memory.  */
+#define PIC_OFFSET_TABLE_REGNUM thumb_pic_register
+
+#define FINALIZE_PIC thumb_finalize_pic ()
+
+/* We can't directly access anything that contains a symbol,
+   nor can we indirect via the constant pool.  */
+#define LEGITIMATE_PIC_OPERAND_P(X)                            \
+       (! symbol_mentioned_p (X)                               \
+        && (! CONSTANT_POOL_ADDRESS_P (X)                      \
+            || ! symbol_mentioned_p (get_pool_constant (X))))
+/* We need to know when we are making a constant pool; this determines
+   whether data needs to be in the GOT or can be referenced via a GOT
+   offset.  */
+extern int making_const_table;
+
+\f
 #define PRINT_OPERAND(STREAM,X,CODE) \
   thumb_print_operand((STREAM), (X), (CODE))
 
@@ -1102,7 +1187,33 @@ int thumb_shiftable_const ();
     output_addr_const ((STREAM), (X));                         \
 }
 
-#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_'))
+/* Handles PIC addr specially */
+#define OUTPUT_INT_ADDR_CONST(STREAM,X) \
+  {                                                                    \
+    if (flag_pic && GET_CODE(X) == CONST && is_pic(X))                 \
+      {                                                                        \
+       output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 0), 0));     \
+       fputs(" - (", STREAM);                                          \
+       output_addr_const(STREAM, XEXP (XEXP (XEXP (X, 0), 1), 0));     \
+       fputs(")", STREAM);                                             \
+      }                                                                        \
+    else output_addr_const(STREAM, X);                                 \
+                                                                       \
+    /* Mark symbols as position independent.  We only do this in the   \
+      .text segment, not in the .data segment. */                      \
+    if (NEED_GOT_RELOC && flag_pic && making_const_table &&            \
+       (GET_CODE(X) == SYMBOL_REF || GET_CODE(X) == LABEL_REF))        \
+     {                                                                 \
+        if (GET_CODE(X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(X))   \
+          fprintf(STREAM, "(GOTOFF)");                                 \
+        else if (GET_CODE (X) == LABEL_REF)                            \
+          fprintf(STREAM, "(GOTOFF)");                                 \
+        else                                                           \
+          fprintf(STREAM, "(GOT)");                                    \
+     }                                                                 \
+  }
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '@' || ((CODE) == '_') || ((CODE) == '|'))
 
 /* Emit a special directive when defining a function name.
    This is used by the assembler to assit with interworking.  */
index 93d0c05..d655c47 100644 (file)
       if (GET_CODE (operands[0]) != REG)
        operands[1] = force_reg (SImode, operands[1]);
     }
+  if (CONSTANT_P (operands[1]) && flag_pic)
+    operands[1] = legitimize_pic_address (operands[1], SImode,
+                                         ((reload_in_progress
+                                           || reload_completed)
+                                          ? operands[0] : 0));
 ")
 
 (define_insn "*movsi_insn"
 
 
 (define_insn "*call_insn"
-  [(call (mem:SI (match_operand:SI 0 "" "i"))
+  [(call (mem:SI (match_operand:SI 0 "" "X"))
         (match_operand:SI 1 "" ""))]
   "GET_CODE (operands[0]) == SYMBOL_REF"
   "bl\\t%a0"
 
 (define_insn "*call_value_insn"
   [(set (match_operand 0 "register_operand" "=l")
-       (call (mem:SI (match_operand 1 "" "i"))
+       (call (mem:SI (match_operand 1 "" "X"))
              (match_operand 2 "" "")))]
   "GET_CODE (operands[1]) == SYMBOL_REF"
   "bl\\t%a1"
  ""
  "*
 {
+  making_const_table = TRUE;
   switch (GET_MODE_CLASS (GET_MODE (operands[0])))
     {
     case MODE_FLOAT:
  ""
  "*
 {
+  making_const_table = TRUE;
   switch (GET_MODE_CLASS (GET_MODE (operands[0])))
     {
     case MODE_FLOAT:
   [(unspec_volatile [(const_int 0)] 4)]
   ""
   "*
-  /* Nothing to do (currently).  */
+  making_const_table = FALSE;
   return \"\";
 ")
 
    assemble_align (32);
    return \"\";
 ")
+
+/* When generating pic, we need to load the symbol offset into a register.
+   So that the optimizer does not confuse this with a normal symbol load
+   we use an unspec.  The offset will be loaded from a constant pool entry,
+   since that is the only type of relocation we can use.  */
+
+(define_insn "pic_load_addr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(match_operand 1 "" "")] 3))]
+  "flag_pic"
+  "ldr\\t%0, %a1")
+
+(define_insn "pic_add_dot_plus_four"
+  [(set (match_operand 0 "register_operand" "+r")
+       (plus:SI (match_dup 0) (const (plus:SI (pc) (const_int 4)))))
+   (use (label_ref (match_operand 1 "" "")))]
+  "flag_pic"
+  "*
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+                            CODE_LABEL_NUMBER (operands[1]));
+  return \"add\\t%0, %|pc\";
+")
+
index 4648143..06ce6bf 100644 (file)
@@ -276,6 +276,8 @@ in the following sections.
 -mnop-fun-dllimport -mno-nop-fun-dllimport
 -mcallee-super-interworking -mno-callee-super-interworking
 -mcaller-super-interworking -mno-caller-super-interworking
+-msingle-pic-base -mno-single-pic-base
+-mpic-register=
 
 @emph{MN10200 Options}
 -mrelax
@@ -4395,7 +4397,7 @@ Generate code for a processor running in big-endian mode.
 @item -mstructure-size-boundary=<n>
 @kindex -mstructure-size-boundary
 The size of all structures and unions will be rounded up to a multiple
-of the number of bits set by this option.  Permissable values are 8 and
+of the number of bits set by this option.  Permissible values are 8 and
 32.  The default value varies for different toolchains.  For the COFF
 targeted toolchain the default value is 8.  Specifying the larger number
 can produced faster, more efficient code, but can also increase the size
@@ -4421,7 +4423,18 @@ non-interworking code.
 Allows calls via function pointers (including virtual functions) to
 execute correctly regardless of whether the target code has been
 compiled for interworking or not.  There is a small overhead in the cost
-of executing a funciton pointer if this option is enabled.
+of executing a function pointer if this option is enabled.
+
+@item -msingle-pic-base
+@kindex -msingle-pic-base
+Treat the register used for PIC addressing as read-only, rather than
+loading it in the prologue for each function.  The run-time system is
+responsible for initialising this register with an appropriate value
+before execution begins.
+
+@item -mpic-register=<reg>
+@kindex -mpic-register=
+Specify the register to be used for PIC addressing.  The default is R10.
 
 @end table