+2007-05-30 Richard Sandiford <richard@codesourcery.com>
+
+ * config.gcc (arm-wrs-vxworks): Remove dbxelf.h from tm_file.
+ Add vx-common.h. Include vxworks.h between vx-common.h and
+ arm/vxworks.h.
+ * config/vx-common.h (DWARF2_UNWIND_INFO): Undefine before
+ redefining.
+ * config/vxworks.h (TARGET_ASM_CONSTRUCTOR): Likewise.
+ (TARGET_ASM_DESTRUCTOR): Likewise.
+ * config/arm/vxworks.h (TARGET_OS_CPP_BUILTINS): Check arm_arch_xscale
+ instead of arm_is_xscale. Use VXWORKS_OS_CPP_BUILTINS.
+ (OVERRIDE_OPTIONS, SUBTARGET_CPP_SPEC): Define.
+ (CC1_SPEC): Add -tstrongarm. Line up backslashes.
+ (VXWORKS_ENDIAN_SPEC): Define.
+ (ASM_SPEC): Add VXWORKS_ENDIAN_SPEC.
+ (LIB_SPEC, STARTFILE_SPEC, ENDFILE_SPEC): Redefine to their
+ VXWORKS_* equivalents.
+ (LINK_SPEC): Likewise, but add VXWORKS_ENDIAN_SPEC.
+ (ASM_FILE_START): Delete.
+ (TARGET_VERSION): Reformat.
+ (FPUTYPE_DEFAULT, FUNCTION_PROFILER): Define.
+ (DEFAULT_STRUCTURE_SIZE_BOUNDARY): Define.
+ * config/arm/t-vxworks (LIB1ASMSRC, LIB1ASMFUNCS): Define.
+ (FPBIT, DPBIT): Define.
+ (fp-bit.c, dp-bit.c): New rules.
+ (MULTILIB_OPTIONS): Add strongarm, -mrtp and -mrtp/-fPIC multilibs.
+ (MULTILIB_MATCHES, MULTILIB_EXCEPTIONS): Define.
+ * config/arm/arm-protos.h (arm_emit_call_insn): Declare.
+ * config/arm/arm.h: Include vxworks-dummy.h.
+ * config/arm/arm.c (arm_elf_asm_constructor, arm_elf_asm_destructor):
+ Mark with ATTRIBUTE_UNUSED.
+ (arm_override_options): Do not allow VxWorks RTP PIC to be used
+ for Thumb. Force r9 to be the PIC register for VxWorks RTPs and
+ make it incompatible with -msingle-pic-base.
+ (arm_function_ok_for_sibcall): Return false for calls that might
+ go through a VxWorks PIC PLT entry.
+ (require_pic_register): New function, split out from...
+ (legitimize_pic_address): ...here. Do not use GOTOFF accesses
+ for VxWorks RTPs.
+ (arm_load_pic_register): Handle the VxWorks RTP initialization
+ sequence. Use pic_reg as a shorthand for cfun->machine->pic_reg.
+ (arm_emit_call_insn): New function.
+ (arm_assemble_integer): Do not use GOTOFF accesses for VxWorks RTP.
+ * config/arm/arm.md (UNSPEC_PIC_OFFSET): New unspec number.
+ (pic_offset_arm): New pattern.
+ (call, call_value): Use arm_emit_call_insn.
+ (call_internal, call_value_internal): New expanders.
+ * config/arm/lib1funcs.asm (__PLT__): Define to empty for
+ VxWorks unless __PIC__.
+
2007-05-30 Eric Christopher <echristo@gmail.com>
* genrecog.c: Include regs.h in generated file.
tree, bool);
#ifdef OBJECT_FORMAT_ELF
-static void arm_elf_asm_constructor (rtx, int);
-static void arm_elf_asm_destructor (rtx, int);
+static void arm_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
+static void arm_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
#endif
#ifndef ARM_PE
static void arm_encode_section_info (tree, rtx, int);
ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
}
+ if (!TARGET_ARM && TARGET_VXWORKS_RTP && flag_pic)
+ {
+ error ("RTP PIC is incompatible with Thumb");
+ flag_pic = 0;
+ }
+
/* If stack checking is disabled, we can use r10 as the PIC register,
which keeps r9 available. The EABI specifies r9 as the PIC register. */
if (flag_pic && TARGET_SINGLE_PIC_BASE)
- arm_pic_register = (TARGET_APCS_STACK || TARGET_AAPCS_BASED) ? 9 : 10;
+ {
+ if (TARGET_VXWORKS_RTP)
+ warning (0, "RTP PIC is incompatible with -msingle-pic-base");
+ arm_pic_register = (TARGET_APCS_STACK || TARGET_AAPCS_BASED) ? 9 : 10;
+ }
+
+ if (flag_pic && TARGET_VXWORKS_RTP)
+ arm_pic_register = 9;
if (arm_pic_register_string != NULL)
{
else if (pic_register < 0 || call_used_regs[pic_register]
|| pic_register == HARD_FRAME_POINTER_REGNUM
|| pic_register == STACK_POINTER_REGNUM
- || pic_register >= PC_REGNUM)
+ || pic_register >= PC_REGNUM
+ || (TARGET_VXWORKS_RTP
+ && (unsigned int) pic_register != arm_pic_register))
error ("unable to use '%s' for PIC register", arm_pic_register_string);
else
arm_pic_register = pic_register;
if (decl == NULL || TARGET_THUMB)
return false;
+ /* The PIC register is live on entry to VxWorks PLT entries, so we
+ must make the call before restoring the PIC register. */
+ if (TARGET_VXWORKS_RTP && flag_pic && !targetm.binds_local_p (decl))
+ return false;
+
/* Cannot tail-call to long calls, since these are out of range of
a branch instruction. */
if (arm_is_long_call_p (decl))
return 1;
}
+/* Record that the current function needs a PIC register. Initialize
+ cfun->machine->pic_reg if we have not already done so. */
+
+static void
+require_pic_register (void)
+{
+ /* 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 (current_ir_type () != IR_GIMPLE)
+ 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 (current_ir_type () != IR_GIMPLE)
+ {
+ 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 ());
+ }
+ }
+ }
+}
+
rtx
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 (current_ir_type () != IR_GIMPLE)
- 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 (current_ir_type () != IR_GIMPLE)
- {
- 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 this function doesn't have a pic register, create one now. */
+ require_pic_register ();
if (reg == 0)
{
else /* TARGET_THUMB1 */
emit_insn (gen_pic_load_addr_thumb1 (address, orig));
+ /* VxWorks does not impose a fixed gap between segments; the run-time
+ gap can be different from the object-file gap. We therefore can't
+ use GOTOFF unless we are absolutely sure that the symbol is in the
+ same segment as the GOT. Unfortunately, the flexibility of linker
+ scripts means that we can't be sure of that in general, so assume
+ that GOTOFF is never valid on VxWorks. */
if ((GET_CODE (orig) == LABEL_REF
|| (GET_CODE (orig) == SYMBOL_REF &&
SYMBOL_REF_LOCAL_P (orig)))
- && NEED_GOT_RELOC)
+ && NEED_GOT_RELOC
+ && !TARGET_VXWORKS_RTP)
pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
else
{
arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
{
#ifndef AOF_ASSEMBLER
- rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx;
+ rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx, pic_reg;
rtx global_offset_table;
if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
gcc_assert (flag_pic);
- /* We use an UNSPEC rather than a LABEL_REF because this label never appears
- in the code stream. */
-
- labelno = GEN_INT (pic_labelno++);
- l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
- l1 = gen_rtx_CONST (VOIDmode, l1);
-
- global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
- /* On the ARM the PC register contains 'dot + 8' at the time of the
- addition, on the Thumb it is 'dot + 4'. */
- pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 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_reg = cfun->machine->pic_reg;
+ if (TARGET_VXWORKS_RTP)
+ {
+ pic_rtx = gen_rtx_SYMBOL_REF (Pmode, VXWORKS_GOTT_BASE);
+ pic_rtx = gen_rtx_CONST (Pmode, pic_rtx);
+ emit_insn (gen_pic_load_addr_arm (pic_reg, pic_rtx));
- pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
+ emit_insn (gen_rtx_SET (Pmode, pic_reg, gen_rtx_MEM (Pmode, pic_reg)));
- if (TARGET_ARM)
- {
- 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));
+ pic_tmp = gen_rtx_SYMBOL_REF (Pmode, VXWORKS_GOTT_INDEX);
+ emit_insn (gen_pic_offset_arm (pic_reg, pic_reg, pic_tmp));
}
- else if (TARGET_THUMB2)
+ else
{
- /* Thumb-2 only allows very limited access to the PC. Calculate the
- address in a temporary register. */
- if (arm_pic_register != INVALID_REGNUM)
+ /* We use an UNSPEC rather than a LABEL_REF because this label
+ never appears in the code stream. */
+
+ labelno = GEN_INT (pic_labelno++);
+ l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
+ l1 = gen_rtx_CONST (VOIDmode, l1);
+
+ global_offset_table
+ = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+ /* On the ARM the PC register contains 'dot + 8' at the time of the
+ addition, on the Thumb it is 'dot + 4'. */
+ pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 4);
+ if (GOT_PCREL)
{
- pic_tmp = gen_rtx_REG (SImode,
- thumb_find_work_register (saved_regs));
+ pic_tmp2 = gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx);
+ pic_tmp2 = gen_rtx_CONST (VOIDmode, pic_tmp2);
}
else
+ pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
+
+ pic_rtx = gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp);
+ pic_rtx = gen_rtx_CONST (Pmode, pic_rtx);
+
+ if (TARGET_ARM)
{
- gcc_assert (!no_new_pseudos);
- pic_tmp = gen_reg_rtx (Pmode);
+ emit_insn (gen_pic_load_addr_arm (pic_reg, pic_rtx));
+ emit_insn (gen_pic_add_dot_plus_eight (pic_reg, pic_reg, labelno));
}
+ else if (TARGET_THUMB2)
+ {
+ /* Thumb-2 only allows very limited access to the PC. Calculate the
+ address in a temporary register. */
+ if (arm_pic_register != INVALID_REGNUM)
+ {
+ pic_tmp = gen_rtx_REG (SImode,
+ thumb_find_work_register (saved_regs));
+ }
+ else
+ {
+ gcc_assert (!no_new_pseudos);
+ pic_tmp = gen_reg_rtx (Pmode);
+ }
- emit_insn (gen_pic_load_addr_thumb2 (cfun->machine->pic_reg, pic_rtx));
- emit_insn (gen_pic_load_dot_plus_four (pic_tmp, labelno));
- emit_insn (gen_addsi3(cfun->machine->pic_reg, cfun->machine->pic_reg,
- pic_tmp));
- }
- else /* TARGET_THUMB1 */
- {
- if (arm_pic_register != INVALID_REGNUM
- && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
+ emit_insn (gen_pic_load_addr_thumb2 (pic_reg, pic_rtx));
+ emit_insn (gen_pic_load_dot_plus_four (pic_tmp, labelno));
+ emit_insn (gen_addsi3 (pic_reg, pic_reg, pic_tmp));
+ }
+ else /* TARGET_THUMB1 */
{
- /* We will have pushed the pic register, so we should always be
- able to find a work register. */
- pic_tmp = gen_rtx_REG (SImode,
- thumb_find_work_register (saved_regs));
- emit_insn (gen_pic_load_addr_thumb1 (pic_tmp, pic_rtx));
- emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
+ if (arm_pic_register != INVALID_REGNUM
+ && REGNO (pic_reg) > LAST_LO_REGNUM)
+ {
+ /* We will have pushed the pic register, so we should always be
+ able to find a work register. */
+ pic_tmp = gen_rtx_REG (SImode,
+ thumb_find_work_register (saved_regs));
+ emit_insn (gen_pic_load_addr_thumb1 (pic_tmp, pic_rtx));
+ emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
+ }
+ else
+ emit_insn (gen_pic_load_addr_thumb1 (pic_reg, pic_rtx));
+ emit_insn (gen_pic_add_dot_plus_four (pic_reg, pic_reg, labelno));
}
- else
- emit_insn (gen_pic_load_addr_thumb1 (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, cfun->machine->pic_reg));
+ emit_insn (gen_rtx_USE (VOIDmode, pic_reg));
#endif /* AOF_ASSEMBLER */
}
return count * 8;
}
+/* Emit a call instruction with pattern PAT. ADDR is the address of
+ the call target. */
+
+void
+arm_emit_call_insn (rtx pat, rtx addr)
+{
+ rtx insn;
+
+ insn = emit_call_insn (pat);
+
+ /* The PIC register is live on entry to VxWorks PIC PLT entries.
+ If the call might use such an entry, add a use of the PIC register
+ to the instruction's CALL_INSN_FUNCTION_USAGE. */
+ if (TARGET_VXWORKS_RTP
+ && flag_pic
+ && GET_CODE (addr) == SYMBOL_REF
+ && (SYMBOL_REF_DECL (addr)
+ ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
+ : !SYMBOL_REF_LOCAL_P (addr)))
+ {
+ require_pic_register ();
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), cfun->machine->pic_reg);
+ }
+}
/* Output a 'call' insn. */
const char *
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)
- || SYMBOL_REF_LOCAL_P (x)))
- fputs ("(GOTOFF)", asm_out_file);
- else if (GET_CODE (x) == LABEL_REF)
- fputs ("(GOTOFF)", asm_out_file);
- else
+ /* See legitimize_pic_address for an explanation of the
+ TARGET_VXWORKS_RTP check. */
+ if (TARGET_VXWORKS_RTP
+ || (GET_CODE (x) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (x)))
fputs ("(GOT)", asm_out_file);
+ else
+ fputs ("(GOTOFF)", asm_out_file);
}
fputc ('\n', asm_out_file);
return true;
#define TARGET_OS_CPP_BUILTINS() \
do { \
- builtin_define ("__vxworks"); \
if (TARGET_BIG_END) \
builtin_define ("ARMEB"); \
else \
builtin_define ("ARMEL"); \
\
- if (arm_is_xscale) \
+ if (arm_arch_xscale) \
builtin_define ("CPU=XSCALE"); \
else if (arm_arch5) \
builtin_define ("CPU=ARMARCH5"); \
else \
builtin_define ("CPU=ARMARCH4"); \
} \
+ VXWORKS_OS_CPP_BUILTINS (); \
} while (0)
+#undef OVERRIDE_OPTIONS
+#define OVERRIDE_OPTIONS \
+ do \
+ { \
+ VXWORKS_OVERRIDE_OPTIONS; \
+ arm_override_options (); \
+ } \
+ while (0)
+
+/* Subsume the arm/elf.h definition, and add RTP hooks. */
+#undef SUBTARGET_CPP_SPEC
+#define SUBTARGET_CPP_SPEC "-D__ELF__" VXWORKS_ADDITIONAL_CPP_SPEC
+
#undef CC1_SPEC
#define CC1_SPEC \
-"%{t4: -mlittle-endian -march=armv4 ; \
- t4be: -mbig-endian -march=armv4 ; \
+"%{tstrongarm:-mlittle-endian -mcpu=strongarm ; \
+ t4: -mlittle-endian -march=armv4 ; \
+ t4be: -mbig-endian -march=armv4 ; \
t4t: -mthumb -mthumb-interwork -mlittle-endian -march=armv4t ; \
t4tbe: -mthumb -mthumb-interwork -mbig-endian -march=armv4t ; \
- t5: -mlittle-endian -march=armv5 ; \
- t5be: -mbig-endian -march=armv5 ; \
+ t5: -mlittle-endian -march=armv5 ; \
+ t5be: -mbig-endian -march=armv5 ; \
t5t: -mthumb -mthumb-interwork -mlittle-endian -march=armv5 ; \
t5tbe: -mthumb -mthumb-interwork -mbig-endian -march=armv5 ; \
- txscale: -mlittle-endian -mcpu=xscale ; \
- txscalebe: -mbig-endian -mcpu=xscale ; \
+ txscale: -mlittle-endian -mcpu=xscale ; \
+ txscalebe: -mbig-endian -mcpu=xscale ; \
: -march=armv4}"
+/* Pass -EB for big-endian targets. */
+#define VXWORKS_ENDIAN_SPEC \
+ "%{mbig-endian|t4be|t4tbe|t5be|t5tbe|txscalebe:-EB}"
+
/* The -Q options from svr4.h aren't understood and must be removed. */
#undef ASM_SPEC
#define ASM_SPEC \
- "%{v:-V} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}"
+ "%{v:-V} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} " VXWORKS_ENDIAN_SPEC
-/* VxWorks does all the library stuff itself. */
-#undef LIB_SPEC
-#define LIB_SPEC ""
+#undef LINK_SPEC
+#define LINK_SPEC VXWORKS_LINK_SPEC " " VXWORKS_ENDIAN_SPEC
-/* VxWorks uses object files, not loadable images. make linker just
- combine objects. */
-#undef LINK_SPEC
-#define LINK_SPEC "-r"
+#undef LIB_SPEC
+#define LIB_SPEC VXWORKS_LIB_SPEC
-/* VxWorks provides the functionality of crt0.o and friends itself. */
-#undef STARTFILE_SPEC
-#define STARTFILE_SPEC ""
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC VXWORKS_STARTFILE_SPEC
-#undef ENDFILE_SPEC
-#define ENDFILE_SPEC ""
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC VXWORKS_ENDFILE_SPEC
-#undef TARGET_VERSION
-#define TARGET_VERSION fputs (" (ARM/VxWorks)", stderr);
+#undef TARGET_VERSION
+#define TARGET_VERSION fputs (" (ARM/VxWorks)", stderr);
/* There is no default multilib. */
#undef MULTILIB_DEFAULTS
-#undef ASM_FILE_START
-#define ASM_FILE_START(STREAM) \
- do \
- { \
- fprintf (STREAM, "%s Generated by GCC %s for ARM/VxWorks\n", \
- ASM_COMMENT_START, version_string); \
- } \
- while (0)
+#define FPUTYPE_DEFAULT FPUTYPE_VFP
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER VXWORKS_FUNCTION_PROFILER
+
+/* We want to be compatible with a version of "2.96" at one point in
+ the past before this macro was changed. */
+#undef DEFAULT_STRUCTURE_SIZE_BOUNDARY
+#define DEFAULT_STRUCTURE_SIZE_BOUNDARY 8