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