Commit 020a4035 by Richard Earnshaw Committed by Richard Earnshaw

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
parent a5a97921
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> 2006-01-18 Ben Elliston <bje@au.ibm.com>
* config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Reject * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Reject
......
/* Output routines for GCC for ARM. /* Output routines for GCC for ARM.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 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) Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
and Martin Simmons (@harleqn.co.uk). and Martin Simmons (@harleqn.co.uk).
More major hacks by Richard Earnshaw (rearnsha@arm.com). More major hacks by Richard Earnshaw (rearnsha@arm.com).
...@@ -524,7 +524,7 @@ int arm_cpp_interwork = 0; ...@@ -524,7 +524,7 @@ int arm_cpp_interwork = 0;
enum machine_mode output_memory_reference_mode; enum machine_mode output_memory_reference_mode;
/* The register number to be used for the PIC offset register. */ /* 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 /* Set to 1 when a return insn is output, this means that the epilogue
is not needed. */ is not needed. */
...@@ -1096,7 +1096,7 @@ arm_override_options (void) ...@@ -1096,7 +1096,7 @@ arm_override_options (void)
/* If stack checking is disabled, we can use r10 as the PIC register, /* If stack checking is disabled, we can use r10 as the PIC register,
which keeps r9 available. */ which keeps r9 available. */
if (flag_pic) if (flag_pic && TARGET_SINGLE_PIC_BASE)
arm_pic_register = TARGET_APCS_STACK ? 9 : 10; arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
if (TARGET_APCS_FLOAT) if (TARGET_APCS_FLOAT)
...@@ -1547,7 +1547,9 @@ use_return_insn (int iscond, rtx sibling) ...@@ -1547,7 +1547,9 @@ use_return_insn (int iscond, rtx sibling)
if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM)) if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
return 0; 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; return 0;
} }
...@@ -3171,16 +3173,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) ...@@ -3171,16 +3173,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
/* Addressing mode support functions. */ /* Addressing mode support functions. */
/* Return nonzero if X is a legitimate immediate operand when compiling /* 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 int
legitimate_pic_operand_p (rtx x) legitimate_pic_operand_p (rtx x)
{ {
if (CONSTANT_P (x) if (GET_CODE (x) == SYMBOL_REF
&& flag_pic || (GET_CODE (x) == CONST
&& (GET_CODE (x) == SYMBOL_REF && GET_CODE (XEXP (x, 0)) == PLUS
|| (GET_CODE (x) == CONST && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
&& GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)))
return 0; return 0;
return 1; return 1;
...@@ -3198,6 +3198,49 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg) ...@@ -3198,6 +3198,49 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
rtx insn; rtx insn;
int subregs = 0; 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) if (reg == 0)
{ {
gcc_assert (!no_new_pseudos); gcc_assert (!no_new_pseudos);
...@@ -3225,17 +3268,16 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg) ...@@ -3225,17 +3268,16 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
|| (GET_CODE (orig) == SYMBOL_REF && || (GET_CODE (orig) == SYMBOL_REF &&
SYMBOL_REF_LOCAL_P (orig))) SYMBOL_REF_LOCAL_P (orig)))
&& NEED_GOT_RELOC) && 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 else
{ {
pic_ref = gen_const_mem (Pmode, pic_ref = gen_const_mem (Pmode,
gen_rtx_PLUS (Pmode, pic_offset_table_rtx, gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
address)); address));
} }
insn = emit_move_insn (reg, pic_ref); insn = emit_move_insn (reg, pic_ref);
#endif #endif
current_function_uses_pic_offset_table = 1;
/* Put a REG_EQUAL note on this insn, so that it can be optimized /* Put a REG_EQUAL note on this insn, so that it can be optimized
by loop. */ by loop. */
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, 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) ...@@ -3247,7 +3289,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
rtx base, offset; rtx base, offset;
if (GET_CODE (XEXP (orig, 0)) == PLUS 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; return orig;
if (GET_CODE (XEXP (orig, 0)) == UNSPEC if (GET_CODE (XEXP (orig, 0)) == UNSPEC
...@@ -3387,13 +3429,14 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED) ...@@ -3387,13 +3429,14 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
if (TARGET_ARM) if (TARGET_ARM)
{ {
emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx)); emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
pic_offset_table_rtx, labelno)); cfun->machine->pic_reg, labelno));
} }
else 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 /* We will have pushed the pic register, so we should always be
able to find a work register. */ able to find a work register. */
...@@ -3403,14 +3446,14 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED) ...@@ -3403,14 +3446,14 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp)); emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
} }
else else
emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx)); emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
pic_offset_table_rtx, labelno)); cfun->machine->pic_reg, labelno));
} }
/* Need to emit this whether or not we obey regdecls, /* Need to emit this whether or not we obey regdecls,
since setjmp/longjmp can cause life info to screw up. */ 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 */ #endif /* AOF_ASSEMBLER */
} }
...@@ -3690,7 +3733,7 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p) ...@@ -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. */ /* This is PC relative data before arm_reorg runs. */
else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x) else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
&& GET_CODE (x) == SYMBOL_REF && GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x) && ! flag_pic) && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
return 1; return 1;
/* This is PC relative data after arm_reorg runs. */ /* This is PC relative data after arm_reorg runs. */
...@@ -9173,6 +9216,7 @@ arm_compute_save_reg0_reg12_mask (void) ...@@ -9173,6 +9216,7 @@ arm_compute_save_reg0_reg12_mask (void)
/* Also save the pic base register if necessary. */ /* Also save the pic base register if necessary. */
if (flag_pic if (flag_pic
&& !TARGET_SINGLE_PIC_BASE && !TARGET_SINGLE_PIC_BASE
&& arm_pic_register != INVALID_REGNUM
&& current_function_uses_pic_offset_table) && current_function_uses_pic_offset_table)
save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM; save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
} }
...@@ -9195,6 +9239,7 @@ arm_compute_save_reg0_reg12_mask (void) ...@@ -9195,6 +9239,7 @@ arm_compute_save_reg0_reg12_mask (void)
don't stack it even though it may be live. */ don't stack it even though it may be live. */
if (flag_pic if (flag_pic
&& !TARGET_SINGLE_PIC_BASE && !TARGET_SINGLE_PIC_BASE
&& arm_pic_register != INVALID_REGNUM
&& (regs_ever_live[PIC_OFFSET_TABLE_REGNUM] && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
|| current_function_uses_pic_offset_table)) || current_function_uses_pic_offset_table))
save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM; save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
...@@ -9312,6 +9357,7 @@ thumb_compute_save_reg_mask (void) ...@@ -9312,6 +9357,7 @@ thumb_compute_save_reg_mask (void)
if (flag_pic if (flag_pic
&& !TARGET_SINGLE_PIC_BASE && !TARGET_SINGLE_PIC_BASE
&& arm_pic_register != INVALID_REGNUM
&& current_function_uses_pic_offset_table) && current_function_uses_pic_offset_table)
mask |= 1 << PIC_OFFSET_TABLE_REGNUM; mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
...@@ -10822,7 +10868,7 @@ arm_expand_prologue (void) ...@@ -10822,7 +10868,7 @@ arm_expand_prologue (void)
} }
if (flag_pic) if (flag_pic && arm_pic_register != INVALID_REGNUM)
arm_load_pic_register (0UL); arm_load_pic_register (0UL);
/* If we are profiling, make sure no instructions are scheduled before /* If we are profiling, make sure no instructions are scheduled before
...@@ -13584,7 +13630,7 @@ thumb_expand_prologue (void) ...@@ -13584,7 +13630,7 @@ thumb_expand_prologue (void)
live_regs_mask = thumb_compute_save_reg_mask (); live_regs_mask = thumb_compute_save_reg_mask ();
/* Load the pic register before setting the frame pointer, /* Load the pic register before setting the frame pointer,
so we can use r7 as a temporary work register. */ 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); arm_load_pic_register (live_regs_mask);
if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0) if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
......
/* Definitions of target machine for GNU compiler, for ARM. /* Definitions of target machine for GNU compiler, for ARM.
Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 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) Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
and Martin Simmons (@harleqn.co.uk). and Martin Simmons (@harleqn.co.uk).
More major hacks by Richard Earnshaw (rearnsha@arm.com) More major hacks by Richard Earnshaw (rearnsha@arm.com)
...@@ -1519,6 +1519,8 @@ typedef struct machine_function GTY(()) ...@@ -1519,6 +1519,8 @@ typedef struct machine_function GTY(())
/* Records if sibcalls are blocked because an argument /* Records if sibcalls are blocked because an argument
register is needed to preserve stack alignment. */ register is needed to preserve stack alignment. */
int sibcall_blocked; 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 /* 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 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. */ trampoline happens to be on the top of the stack. */
...@@ -2206,7 +2208,7 @@ do { \ ...@@ -2206,7 +2208,7 @@ do { \
/* We decide which register to use based on the compilation options and /* 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 the assembler in use; this is more general than the APCS restriction of
using sb (r9) all the time. */ 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 /* The register number of the register used to address a table of static
data addresses in memory. */ data addresses in memory. */
......
;;- Machine description for ARM for GNU compiler ;;- Machine description for ARM for GNU compiler
;; Copyright 1991, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999, 2000, ;; 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) ;; Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
;; and Martin Simmons (@harleqn.co.uk). ;; and Martin Simmons (@harleqn.co.uk).
;; More major hacks by Richard Earnshaw (rearnsha@arm.com). ;; More major hacks by Richard Earnshaw (rearnsha@arm.com).
...@@ -4448,7 +4448,7 @@ ...@@ -4448,7 +4448,7 @@
[(set (match_operand:SI 0 "s_register_operand" "") [(set (match_operand:SI 0 "s_register_operand" "")
(unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))] (unspec:SI [(match_operand 1 "" "") (match_dup 2)] UNSPEC_PIC_SYM))]
"TARGET_ARM && flag_pic" "TARGET_ARM && flag_pic"
"operands[2] = pic_offset_table_rtx;" "operands[2] = cfun->machine->pic_reg;"
) )
(define_insn "*pic_load_addr_based_insn" (define_insn "*pic_load_addr_based_insn"
...@@ -4456,7 +4456,7 @@ ...@@ -4456,7 +4456,7 @@
(unspec:SI [(match_operand 1 "" "") (unspec:SI [(match_operand 1 "" "")
(match_operand 2 "s_register_operand" "r")] (match_operand 2 "s_register_operand" "r")]
UNSPEC_PIC_SYM))] 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 #ifdef AOF_ASSEMBLER
operands[1] = aof_pic_entry (operands[1]); operands[1] = aof_pic_entry (operands[1]);
...@@ -4547,7 +4547,8 @@ ...@@ -4547,7 +4547,8 @@
{ {
/* r3 is clobbered by set/longjmp, so we can use it as a scratch /* r3 is clobbered by set/longjmp, so we can use it as a scratch
register. */ register. */
arm_load_pic_register (3); if (arm_pic_register != INVALID_REGNUM)
arm_load_pic_register (1UL << 3);
DONE; DONE;
}") }")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment