Thumb PIC

Philip Blundell pb@nexus.co.uk
Fri Jul 23 07:39:00 GMT 1999


This patch adds support for PIC on Thumb.  I cribbed most of the code from the 
ARM port.

p.

Fri Jul 23 15:17:59 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.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=.
	
Index: gnu/egcs/gcc/invoke.texi
diff -u gnu/egcs/gcc/invoke.texi:1.1.1.5 gnu/egcs/gcc/invoke.texi:1.3
--- gnu/egcs/gcc/invoke.texi:1.1.1.5	Fri Jul 23 14:57:15 1999
+++ gnu/egcs/gcc/invoke.texi	Fri Jul 23 15:20:59 1999
@@ -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
 @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
 
Index: gnu/egcs/gcc/config/arm/thumb.c
diff -u gnu/egcs/gcc/config/arm/thumb.c:1.1.1.2 gnu/egcs/gcc/config/arm/thumb.c:1.3
--- gnu/egcs/gcc/config/arm/thumb.c:1.1.1.2	Thu Jul 22 13:48:15 1999
+++ gnu/egcs/gcc/config/arm/thumb.c	Fri Jul 23 15:21:02 1999
@@ -40,6 +40,13 @@ 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;
+
 
 /* Predicates */
 int
@@ -106,6 +113,221 @@ thumb_trivial_epilogue ()
 }
 
 
+/* 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 */
+}
+
+
 /* Routines for handling the constant pool */
 /* This is unashamedly hacked from the version in sh.c, since the problem is
    extremely similar.  */
@@ -194,6 +416,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 +498,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 +1234,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 +1351,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 +1446,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 +1459,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 +1487,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 +1525,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 +1636,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 +1694,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 +1723,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 +2030,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,11 +2288,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;
 }
 
 #ifdef THUMB_PE
Index: gnu/egcs/gcc/config/arm/thumb.h
diff -u gnu/egcs/gcc/config/arm/thumb.h:1.1.1.3 gnu/egcs/gcc/config/arm/thumb.h:1.4
--- gnu/egcs/gcc/config/arm/thumb.h:1.1.1.3	Wed Jun 30 16:01:46 1999
+++ gnu/egcs/gcc/config/arm/thumb.h	Fri Jul 23 15:21:02 1999
@@ -59,6 +61,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 +74,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)
+
+#ifndef GOT_PCREL
+#define GOT_PCREL		0
+#endif
+
+#ifndef NEED_GOT_RELOC
+#define NEED_GOT_RELOC		1
+#endif
 
-/* Set if externally visable functions should assume that they
+/* 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 +113,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 +123,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 +187,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 +573,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)
@@ -798,6 +818,39 @@ int thumb_shiftable_const ();
 }
 
 
+/* 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;	\
+    }							\
+}
+
+
 /* Implicit Calls to Library Routines */
 
 #define TARGET_MEM_FUNCTIONS 1
@@ -884,7 +937,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 +1008,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 +1044,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 +1140,28 @@ int thumb_shiftable_const ();
 
 /* 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;
+
+
 #define PRINT_OPERAND(STREAM,X,CODE) \
   thumb_print_operand((STREAM), (X), (CODE))
 
@@ -1101,8 +1185,34 @@ int thumb_shiftable_const ();
   else								\
     output_addr_const ((STREAM), (X));				\
 }
+
+/* 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) == '_'))
+#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: gnu/egcs/gcc/config/arm/thumb.md
diff -u gnu/egcs/gcc/config/arm/thumb.md:1.1.1.1 gnu/egcs/gcc/config/arm/thumb.md:1.2
--- gnu/egcs/gcc/config/arm/thumb.md:1.1.1.1	Thu May  6 10:47:25 1999
+++ gnu/egcs/gcc/config/arm/thumb.md	Thu Jul 22 15:09:49 1999
@@ -43,6 +43,11 @@
       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"
@@ -1051,7 +1056,7 @@
 
 
 (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"
@@ -1059,7 +1064,7 @@
 
 (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"
@@ -1110,6 +1115,7 @@
  ""
  "*
 {
+  making_const_table = TRUE;
   switch (GET_MODE_CLASS (GET_MODE (operands[0])))
     {
     case MODE_FLOAT:
@@ -1132,6 +1138,7 @@
  ""
  "*
 {
+  making_const_table = TRUE;
   switch (GET_MODE_CLASS (GET_MODE (operands[0])))
     {
     case MODE_FLOAT:
@@ -1153,7 +1160,7 @@
   [(unspec_volatile [(const_int 0)] 4)]
   ""
   "*
-  /* Nothing to do (currently).  */
+  making_const_table = FALSE;
   return \"\";
 ")
 
@@ -1164,3 +1171,26 @@
    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 8)))))
+   (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\";
+")
+




More information about the Gcc-patches mailing list