summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>1999-07-26 16:35:08 +0000
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>1999-07-26 16:35:08 +0000
commitf13e5c9e11ac0059a66ee6ffb3bf3bb847842ea8 (patch)
tree1ddb82df982660cc8ea0cd8ab442c44cda11c6d0 /gcc/config
parent196a6b5f1ae5d4e5cca5b274dfd3d1369addd920 (diff)
downloadgcc-f13e5c9e11ac0059a66ee6ffb3bf3bb847842ea8.tar.gz
Apply Philip Blundell <pb@nexus.co.uk>'s patch to add PIC support to the Thumb.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28268 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/arm/thumb.c291
-rw-r--r--gcc/config/arm/thumb.h121
-rw-r--r--gcc/config/arm/thumb.md36
3 files changed, 425 insertions, 23 deletions
diff --git a/gcc/config/arm/thumb.c b/gcc/config/arm/thumb.c
index 122cb2442b4..fa09524eea3 100644
--- a/gcc/config/arm/thumb.c
+++ b/gcc/config/arm/thumb.c
@@ -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"
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;
+
/* 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 ()
}
+/* 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 +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;
}
}
diff --git a/gcc/config/arm/thumb.h b/gcc/config/arm/thumb.h
index be2a0e4d5a9..434bd5ee220 100644
--- a/gcc/config/arm/thumb.h
+++ b/gcc/config/arm/thumb.h
@@ -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 ();
}
+/* 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 +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 ();
/* 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))
@@ -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. */
diff --git a/gcc/config/arm/thumb.md b/gcc/config/arm/thumb.md
index 93d0c050314..d655c47584e 100644
--- a/gcc/config/arm/thumb.md
+++ b/gcc/config/arm/thumb.md
@@ -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 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\";
+")
+