/* 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).
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. */
/* 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)
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;
}
/* 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;
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);
|| (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,
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
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. */
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 */
}
/* 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. */
/* 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;
}
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;
if (flag_pic
&& !TARGET_SINGLE_PIC_BASE
+ && arm_pic_register != INVALID_REGNUM
&& current_function_uses_pic_offset_table)
mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
}
- 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
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)
/* 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)
/* 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. */
/* 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. */
;;- 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).
[(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"
(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]);
{
/* 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;
}")