diff options
author | nickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-07-26 16:35:08 +0000 |
---|---|---|
committer | nickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-07-26 16:35:08 +0000 |
commit | f13e5c9e11ac0059a66ee6ffb3bf3bb847842ea8 (patch) | |
tree | 1ddb82df982660cc8ea0cd8ab442c44cda11c6d0 /gcc/config | |
parent | 196a6b5f1ae5d4e5cca5b274dfd3d1369addd920 (diff) | |
download | gcc-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.c | 291 | ||||
-rw-r--r-- | gcc/config/arm/thumb.h | 121 | ||||
-rw-r--r-- | gcc/config/arm/thumb.md | 36 |
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\"; +") + |