aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog412
-rw-r--r--gcc/config.gcc21
-rw-r--r--gcc/config/frv/frv-abi.h5
-rw-r--r--gcc/config/frv/frv-protos.h8
-rw-r--r--gcc/config/frv/frv.c941
-rw-r--r--gcc/config/frv/frv.h194
-rw-r--r--gcc/config/frv/frv.md379
-rw-r--r--gcc/config/frv/frvbegin.c3
-rw-r--r--gcc/config/frv/frvend.c3
-rw-r--r--gcc/config/frv/libgcc-frv.ver55
-rw-r--r--gcc/config/frv/linux.h74
-rw-r--r--gcc/config/frv/t-frv6
-rw-r--r--gcc/config/frv/t-linux12
-rw-r--r--gcc/doc/invoke.texi50
-rw-r--r--gcc/reload.c24
-rw-r--r--gcc/unwind-dw2-fde-glibc.c18
16 files changed, 1835 insertions, 370 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 24ba4c4..afbb525 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,415 @@
+2004-02-24 Alexandre Oliva <aoliva@redhat.com>
+
+ Implement FR-V FDPIC ABI support for frv-uclinux and frv-linux.
+ 2004-02-05 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_emit_movsi): Use GOT relocations for
+ symbols in sections named by the user.
+ 2004-01-30 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/linux.h (TARGET_OS_CPP_BUILTINS): New.
+ 2004-01-27 Alexandre Oliva <aoliva@redhat.com>
+ * config.gcc (frv-*-*linux*): Handle like *-*-linux*.
+ * config/frv/t-linux (EXTRA_MULTILIB_PARTS): Remove, obviated by
+ the above.
+ 2004-01-20 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.md (symGOT2reg_hilo, symGOTOFF2reg_hilo): Add
+ one more pseudo to further improve code generation.
+ 2004-01-19 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.md (movdi_ldd): Introduce explicit indirection
+ inside UNSPEC.
+ 2004-01-16 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_legitimate_address_p): Added
+ allow_double_reg_p argument. Adjust all callers. Use it to
+ decide whether to enable double-register indirect addressing.
+ (frv_funcdesc_alias_set): Remove.
+ (frv_expand_fdpic_call): Force non-SYMBOL_REF operand into
+ register. Emit movdi_ldd.
+ (ldd_address_operand): New.
+ * config/frv/frv-protos.h (frv_legitimate_address_p): Adjust.
+ * config/frv/frv.h (GO_IF_LEGITIMATE_ADDRESS): Likewise.
+ (PREDICATE_CODES): Add ldd_address_operand.
+ * config/frv/frv.md (movdi_ldd): New.
+ (symGOT2reg_hilo, symGOTOFF2reg_hilo): Use separate pseudo for
+ intermediate computations if possible.
+ (symGOTOFF2reg_i): Fix harmless typo.
+ 2003-12-18 Alexandre Oliva <aoliva@redhat.com>
+ * unwind-dw2-fde-glibc.c (_Unwind_IteratePhdrCallback): Cast
+ relocated p_vaddr to vaddr type.
+ * config/frv/frv-protos.h (frv_expand_fdpic_call): Return void.
+ * config/frv/frv.c (frv_get_funcdesc_alias_set): New.
+ (frv_expand_fdpic_call): Propagate incoming MEM's expr to funcdesc
+ MEM, or use a funcdesc alias set. Use regular move instead of
+ ldd.
+ (dbl_memory_one_insn_operand): Recognize function descriptors by
+ type or by alias set, and don't split them.
+ * config/frv/frv.md (call, call_value): Never use call_internal
+ for fdpic.
+ (call_internal, call_value_internal): Never match for FDPIC.
+ (call_fdpicdi, call_fdpicsi, call_value_fdpicdi,
+ call_value_fdpicsi): Require FDPIC.
+ (ldd): Removed.
+ 2003-12-17 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.h (CRT_GET_RFIB_DATA): Define for __FRV_FDPIC__.
+ * unwind-dw2-fde-glibc.c: Don't include elf-fdpic.h any more.
+ (_Unwind_IteratePhdrCallback): Adjust type of load_base for FRV
+ FDPIC. Compute data base address.
+ * config/frv/linux.h (SUBTARGET_DRIVER_SELF_SPECS): Enable -mfdpic
+ before the other self-specs are processed.
+ * config/frv/t-linux (CRTSTUFF_T_CFLAGS, TARGET_LIBGCC2_CFLAGS):
+ Build with -fPIC.
+ 2003-12-15 Alexandre Oliva <aoliva@redhat.com>
+ * unwind-dw2-fde-glibc.c: Don't include bits/elf-fdpic.h if
+ inhibit_libc is defined.
+ 2003-12-12 Alexandre Oliva <aoliva@redhat.com>
+ * unwind-dw2-fde-glibc.c: Include bits/elf-fdpic.h for
+ __FRV_FDPIC__.
+ (__RELOC_POINTER): Define.
+ (_Unwind_IteratePhdrCallback): Use it.
+ * config/frv/frv.h (Twrite): Define.
+ (TRANSFER_FROM_TRAMPOLINE): Use it.
+ * config/frv/linux.h (INVOKE__main): Undefine.
+ (Twrite): Override.
+ 2003-12-05 Richard Sandiford <rsandifo@redhat.com>
+ * doc/invoke.texi (-mlong-calls, -mlinked-fp): Document FRV options.
+ (-mlibrary-pic): Emphasize that this option generates EABI code.
+ (-mcpu): Add fr550.
+ (-mpack): Remove.
+ 2003-11-30 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (int_2word_operand): Reject LABELs, SYMBOL_REFs
+ and CONSTs in FDPIC mode.
+ * gcc/config.gcc (with_cpu): Default to fr400 on frv-*-*linux*.
+ 2003-11-29 Richard Sandiford <rsandifo@redhat.com>
+ * config/frv/frv.c (move_source_operand): Don't accept symbolic
+ constants.
+ * config/frv/frv.md (*movhi_internal, *movsi_internal): Use an 'n'
+ rather than 'i' constraint for the 2-instruction alternative.
+ (*movsi_2word): New, incorporating existing int_2word_operand splitter.
+ 2003-11-29 Richard Sandiford <rsandifo@redhat.com>
+ * config/frv/frv.h (EXTRA_CONSTRAINT_FOR_Q): Renamed from
+ EXTRA_CONSTRAINT_FOR_Y.
+ (EXTRA_CONSTRAINT): Remove handling of 'Y'.
+ * config/frv/frv.md (*movsi_internal): Remove 'Q' constraint.
+ (addsi3): Change 'Y' constraint to 'Q'.
+ 2003-11-27 Richard Sandiford <rsandifo@redhat.com>
+ * reload.c (CONST_POOL_OK_P): New macro.
+ (find_reloads): Use it to decide whether a constant can be forced
+ into memory.
+ * config/frv/frv.h (LEGITIMATE_PIC_OPERAND_P): Return true if the
+ constant satisfies got12_operand.
+ (frv_cannot_force_const_mem): Always return true for TARGET_FDPIC.
+ (frv_legitimate_address_p): Check for valid unspec offsets using
+ got12_operand rather than frv_legitimate_fdpic_operand_p.
+ (frv_legitimate_fdpic_operand_p): Delete.
+ (frv_emit_movsi): Abort if we try to use the FDPIC register during
+ or after reload.
+ (frv_legitimate_constant_p): Return LEGITIMATE_PIC_OPERAND_P if
+ TARGET_FDPIC.
+ * config/frv/frv.md (*movdf_double): Add alternatives for CONST_DOUBLE.
+ 2003-11-19 Richard Sandiford <rsandifo@redhat.com>
+ * config/frv/frv-protos.h (fdpic_operand, fdpic_got12_operand)
+ (frv_fdpic_fptr_operand): Don't declare here.
+ * config/frv/frv.h (EXTRA_CONSTRAINT_FOR_Y): Call got12_operand
+ rather than fdpic_got12_operand.
+ (PREDICATE_CODES): Remove symbolic_operand entry. Add entries for
+ got12_operand and const_unspec_operand.
+ * config/frv/frv.c (got12_operand): Renamed from fdpic_got12_operand.
+ (gpr_or_int12_operand, dbl_memory_one_insn_operand): Update calls.
+ (symbolic_operand): Remove.
+ (const_unspec_operand): New predicate.
+ * config/frv/frv.md (*movsi_got): Use got12_operand.
+ (*movsi_high_got, *movsi_lo_sum_got): Use const_unspec_operand.
+ 2003-11-18 Richard Sandiford <rsandifo@redhat.com>
+ * config/frv/frv-protos.h (frv_output_addr_const_extra): Remove.
+ * config/frv/frv.h (OUTPUT_ADDR_CONST_EXTRA): Remove definition.
+ * config/frv/frv.c (frv_unspec): New structure.
+ (frv_small_data_reloc_p, frv_const_unspec_p): New functions.
+ (frv_print_operand_memory_reference): Use frv_const_unspec_p to
+ validate CONST indices. Use frv_output_const_unspec to print them.
+ (frv_print_operand): Update call to unspec_got_name. Use
+ frv_output_const_unspec to print constant unspecs.
+ (frv_legitimate_fdpic_operand_p): Return true if frv_const_unspec_p.
+ Reject UNSPECs otherwise.
+ (unspec_got_name): Take the relocation number as argument, not an
+ rtx containing it.
+ (frv_output_addr_const_extra): Remove, replacing with...
+ (frv_output_const_unspec): ...this new function.
+ (frv_find_base_term): Use frv_const_unspec_p & frv_small_data_reloc_p.
+ (gpr_or_int12_operand): Use fdpic_got12_operand.
+ (dbl_memory_one_insn_operand): Likewise.
+ (fdpic_got12_operand): Use frv_const_unspec_p.
+ (frv_emit_movsi): Use frv_const_unspec_p to check for CONSTs that
+ are already legitimate. Use frv_small_data_reloc_p when deciding
+ whether to use HIGH/LO_SUM for R_FRV_GOTOFF12 and R_FRV_GPREL12.
+ 2003-11-18 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/t-linux (SHLIB_MAPFILES): Override so as to export...
+ * config/frv/libgcc-frv.ver: ... frv-specific symbols. New file.
+ * config/frv/frv-abi.h (CREATE_DOUBLE_SHIFT): Use branch to local
+ label, for real this time.
+ * config/frv/frv.c (frv_local_funcdesc_p): Update to new
+ representation of visibility.
+ (fdpic_got12_operand, symbolic_operand): Mark unused arguments as
+ such.
+ 2003-11-17 Richard Sandiford <rsandifo@redhat.com>
+ * config/frv/frv.h (MASK_LINKED_FP, TARGET_LINKED_FP): New macros.
+ (TARGET_SWITCHES): Add -mlinked-fp and -mno-linked-fp.
+ * config/frv/frv.c (frv_override_options): Set MASK_LINKED_FP unless
+ it was explicitly disabled.
+ (frv_stack_info): There is no need to save the link register in every
+ frame unless TARGET_LINKED_FP is true.
+ (frv_frame_pointer_required): If !TARGET_LINKED_FP, only require a
+ frame pointer if the stack pointer might change value.
+ (frv_return_addr_rtx): Check and process "count" argument.
+ 2003-11-14 Richard Sandiford <rsandifo@redhat.com>
+ * config/frv/frv-protos.h (frv_legitimize_address): Remove.
+ (frv_find_base_term): Declare.
+ * config/frv/frv.h (LEGITIMIZE_ADDRESS): Do nothing.
+ (FIND_BASE_TERM): Define.
+ (PREDICATE_CODES): Remove pic_register_operand, pic_symbolic_operand,
+ small_data_register_operand, small_data_symbolic_operand. Add
+ symbolic_operand.
+ * config/frv/frv.c (const_small_data_p, plus_small_data_p): Delete.
+ (frv_print_operand_memory_reference, output_move_single): Remove
+ special handling for unlegitimized sdata addresses.
+ (frv_legitimate_address_p): Don't allow sums of SDA_BASE_REG
+ and symbolic addresses.
+ (frv_legitimize_address, frv_legitimize_fdpic_address): Delete.
+ (frv_find_base_term): New function.
+ (int_2word_operand): Check specifically for symbolic address constants.
+ (pic_register_operand, pic_symbolic_operand): Delete.
+ (small_data_register_operand, small_data_symbolic_operand): Delete.
+ (dbl_memory_one_insn_operand): Don't call plus_small_data_p.
+ Allow UNSPEC_GOT constants if !TARGET_FDPIC.
+ (move_source_operand): Only accept CONSTs if they're a two-insn
+ symbolic constant.
+ (fdpic_got12_operand): Don't require TARGET_FDPIC.
+ (frv_emit_movsi): Legitimize sdata and -mlibrary-pic addresses
+ using gen_symGOTOFF2reg*.
+ (frv_ifcvt_rewrite_mem): Remove (plus gr16 ...) special cases.
+ (frv_rtx_costs): Give all MEM addresses a cost of 0. Give MEMs
+ themselves a cost of 3 insns.
+ * config/mips/mips.md (*movsi_got): Allow for !TARGET_FDPIC too.
+ Change predicate to symbolic_operand.
+ (*movsi_high_got, *movsi_lo_sum_got): Likewise.
+ (*movsi_lda_sdata): Delete.
+ (*movsi_pic, movsi_high_pic, movsi_lo_sum_pic): Delete.
+ 2003-11-05 Alexandre Oliva <aoliva@redhat.com>
+ * config.gcc: Add t-slibgcc-elf-ver and support --with-cpu for
+ frv-*-*linux*.
+ * config/frv/frv-abi.h (CREATE_DOUBLE_SHIFT): Use branch to local
+ label.
+ * config/frv/frv.h (DRIVER_SELF_SPECS): Add blank before
+ -multilib-library-pic.
+ (LINK_SPEC): Add -z text for -mfdpic.
+ * config/frv/frvbegin.c (__ROFIXUP_LIST__): Don't define on FDPIC.
+ * config/frv/frvend.c (__ROFIXUP_END__): Likewise.
+ * config/frv/linux.h (STARTFILE_SPEC, ENDFILE_SPEC, LINK_SPEC):
+ Override.
+ (OPTION_DEFAULT_SPECS, HAS_INIT_SECTION, INIT_SECTION_ASM_OP,
+ FINI_SECTION_ASM_OP, CRT_CALL_STATIC_FUNCTION): Define.
+ * config/frv/t-linux (EXTRA_MULTILIB_PARTS): Use
+ crtstuff-generated files.
+ 2003-10-31 Alexandre Oliva <aoliva@redhat.com>
+ * config.gcc: Add frv-*-*linux*.
+ * config/frv/linux.h, config/frv/t-linux: New.
+ 2003-10-06 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.h (LINK_SPEC): Pass -melf32frvfd to the linker
+ when -mfdpic even if a linker script is explicitly listed.
+ 2003-10-02 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_override_options): Clear asm_out
+ unaligned_op for SImode on FDPIC.
+ (frv_emit_movsi): Use compute_reloc_for_constant to compute the
+ argument passed to decl_readonly_section.
+ (frv_assemble_integer): Revert 2003-09-30's change, but make the
+ whole block run with FDPIC even with -fno-PIC.
+ 2003-10-02 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_cannot_force_const_mem): Don't force
+ symbol or label plus offset to memory.
+ (frv_emit_movsi): Emit GPREL only if -mgprel-ro. Emit 32-bit
+ GOTOFF and GPREL for LABEL_REF.
+ * config/frv/frv.h (DRIVER_SELF_SPECS): Add -mgprel-ro with
+ -mfdpic unless -mno-gprel-ro, -fpic or -fpie.
+ (MASK_GPREL_RO, TARGET_GPREL_RO): New.
+ (TARGET_SWITCHES): Added gprel-ro and no-gprel-ro.
+ * doc/invoke.texi: Document them.
+ 2003-09-30 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv-protos.h (frv_gen_GPsym2reg): Declare.
+ (frv_splittable_got_operand): Removed.
+ * config/frv/frv.c (frv_cannot_force_const_mem): Reject HIGH and
+ LO_SUM. Add comments.
+ (frv_override_options): Moved enabling of FDPIC to
+ DRIVER_SELF_SPECS. Don't enable MASK_DWORD.
+ (frv_local_funcdesc_p): Remove unnecessary heck for flag_pie.
+ (frv_legitimize_fdpic_address): Don't duplicate logic in
+ frv_emit_movsi.
+ (frv_gen_GPsym2reg): New.
+ (unspec_got_name): Added gprel.
+ (frv_expand_fdpic_call): Add support for inlining PLTs.
+ (fdpic_fptr_operand): Renamed from frv_fdpic_fptr_operand.
+ (gpr_or_int12_operand): Added GPREL12.
+ (pic_symbolic_operand): Match even if !flag_pic for FDPIC.
+ (small_data_symbolic_operand): Fail if FDPIC.
+ (fdpic_splittable_got_operand): Removed.
+ (fdpic_got12_operand): Added GPREL12.
+ (frv_emit_movsi): Reorganize to avoid duplication. Emit GPREL
+ when appropriate. Fix sdata GOTOFF.
+ (frv_legitimate_constant_p): Require legitimate PIC operand for
+ FDPIC with pic, but only a legitimate fdpic operand for non-pic.
+ (frv_assemble_integer): Move FDPIC funcdesc handling out of
+ flag_pic case.
+ (frv_asm_out_constructor, frv_asm_out_destructor): Abort if
+ frv_assemble_integer fails.
+ * config/frv/frv.h (DRIVER_SELF_SPECS): New.
+ (SUBTARGET_DRIVER_SELF_SPECS): New.
+ (ASM_SPEC): Don't pass -mno-fdpic.
+ (LINK_SPEC): Pass -melf32frvfd for FDPIC.
+ (MASK_INLINE_PLT, TARGET_INLINE_PLT): New.
+ (TARGET_SWITCHES): Add -minline-plt, -mno-inline-plt and
+ -multilib-library-pic.
+ (PREDICATE_CODES): Added fdpic_operand, fdpic_fptr_operand,
+ condexec_si_media_operator, condexec_sf_add_operator and
+ condexec_sf_conv_operator. Removed condexec_sf_binary_operator
+ and condexec_sf_unary_operator.
+ * config/frv/frv.md (R_FRV_GPREL12, R_FRV_GPRELHI, R_FRV_GPRELLO):
+ New.
+ (movsi_got, movsi_high_got, movsi_lo_sum_got): Move before
+ movsi_internal. Give them internal names. movsi_got has type
+ int.
+ (fdpic got splitters): Remove.
+ (symGPREL2reg, symGPREL2reg_hilo): New.
+ * config/frv/t-frv (MULTILIB_MATCHES): Don't map -fpic and -fPIC
+ to -mlibrary-pic. Map -multilib-library-pic to it.
+ * doc/invoke.texi: -mfdpic, -minline-plt, -multilib-library-pic:
+ Document.
+ 2003-09-28 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_function_symbol_referenced_p): Declare.
+ (TARGET_CANNOT_FORCE_CONST_MEM): Define to...
+ (frv_cannot_force_const_mem): New function.
+ (const_small_data_p, plus_small_data_p): Update comments on sdata
+ on FDPIC.
+ (frv_override_options): Set flag_pie for FDPIC too.
+ (frv_conditional_register_usage): Mark gr16 and gr17 as non-fixed,
+ call-saved registers on FDPIC.
+ (frv_stack_info): Don't preserve the PIC register on FDPIC, and
+ don't force LR to be preserved.
+ (frv_expand_prologue): Likewise.
+ (frv_asm_output_mi_thunk): Use 12-bit funcdesc gotoff for -fpic.
+ (frv_frame_pointer_required): Don't force it just because the
+ FDPIC register is used.
+ (frv_legitimate_address_p) <CONST>: Accept a legitimate FDPIC
+ operand only if !condexec_p.
+ (frv_legitimize_address): Return the FDPIC-legitimized address.
+ Don't match small data here on FDPIC.
+ (frv_legitimate_fdpic_operand_p): Don't accept unadorned function
+ symbols. Use TRUE/FALSE instead of 1/0.
+ (frv_local_funcdesc_p): New.
+ (frv_legitimize_fdpic_address): Rewrite to use GOTOFF and 12-bit
+ immediates when possible.
+ (pic_symbolic_operand): Accept SYMBOL_REFs and CONSTs in FDPIC.
+ (dbl_memory_one_insn_operand): Accept addresses that add a REG and
+ an UNSPEC_GOT.
+ (frv_emit_movsi): Handle FDPIC before small data. Use GOTOFF and
+ 12-bit immediates when possible.
+ (frv_legitimate_constant_p): In FDPIC, reject SImode operands that
+ are not legitimate pic operands.
+ (frv_in_small_data_p): Re-enable for FDPIC.
+ * config/frv/frv.h (SDA_BASE_REG): Remove comment about FDPIC.
+ (FRV_GLOBAL_P): Removed.
+ * config/frv/frv.md: Add modes to CONSTs.
+ (movsi_got): New.
+ (movsi_lo_sum_got): Use separate matches instead of match_dup.
+ (movsi_high_pic, movsi_lo_sum_pic): Match on non-FDPIC only.
+ (fdpic splittable operations): Match on flag_pic != 1.
+ 2003-09-22 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_asm_out_constructor,
+ frv_asm_out_destructor): Pass to frv_assemble_integer the size in
+ bytes, not bits.
+ 2003-09-19 Alexandre Oliva <aoliva@redhat.com>
+ * config/frv/frv.c (frv_assemble_integer): Reject complex
+ expressions referencing function SYMBOL_REFs.
+ * config/frv/frv.c (frv_function_symbol_referenced_p): New.
+ (move_source_operand): Reject CONSTs that reference function
+ SYMBOL_REFs on FDPIC.
+ (frv_emit_movsi): If we get such a CONST, break it up.
+ * config/frv/frv.h (CPP_SPEC): Define __FRV_FDPIC__ for -mfdpic.
+ (TRANSFER_FROM_TRAMPOLINE): Use different definitions for FDPIC.
+ * config/frv/frv.c (frv_print_operand) <I>: Recognize PLUS without
+ MEM.
+ (frv_assemble_integer): Don't use funcdesc for LABEL_REFs.
+ (frv_trampoline_size): Increase for FDPIC.
+ * config/frv/frv.h (TRAMPOLINE_ALIGNMENT): Bump to 64 for FDPIC.
+ (TRANSFER_FROM_TRAMPOLINE): Handle FDPIC trampolines.
+ * config/frv/frv.c (frv_legitimize_fdpic_address, frv_emit_movsi):
+ Disable use of GOTOFF for now.
+ (const_small_data_p, plus_small_data_p, frv_in_small_data_p):
+ Disable use of small data in FDPIC for now.
+ (frv_asm_output_mi_thunk): Implement for FDPIC.
+ * config/frv/frv.h (SDA_BASE_REG): Set to -1 with FDPIC.
+ * config/frv/frv.c (frv_asm_out_constructor): Use
+ frv_assemble_integer for FDPIC pointers.
+ (frv_asm_out_destructor): Likewise.
+ * config/frv/frv.md (ldd): Fix order of operands. Use
+ address_operand for input.
+ 2003-09-18 DJ Delorie <dj@redhat.com>
+ * config/frv/frv.c (frv_legitimate_fdpic_operand_p): Remove UNSPEC_PIC.
+ (unspec_got_name): Correct typo.
+ (frv_emit_movsi): Pre-expand splittable GOTs.
+ (frv_expand_fdpic_call): Rename gen_lddi to gen_ldd.
+ * config/frv/frv.md (lddi): Fix syntax error, rename to ldd.
+ (symGOT2reg_hilo, symGOTOFF2reg_hilo): New.
+ * config/frv/t-frv: Add -mfdpic multilibs.
+ * config/frv/frv.h (ASM_SPEC): Pass -mfdpic/-mno-fdpic.
+ (TARGET_SWITCHES): Add -mno-fdpic, fix documentation.
+ * config/frv/frv.c (frv_override_options): -mfdpic assumes
+ flag_pic, default to 32-bit pics, require DWORD ops.
+ (frv_override_options): Add W and Z constraints.
+ (frv_expand_prologue): No pic prologue for -mfdpic.
+ (frv_asm_output_mi_thunk): Support -mfdpic (soon).
+ (frv_print_operand_memory_reference): Handle GOT constants.
+ (frv_legitimate_address_p): Allow GOT constants.
+ (frv_legitimize_address): Handle GOT addresses too.
+ (frv_legitimate_fdpic_operand_p): New.
+ (frv_legitimize_fdpic_address): New.
+ (unspec_got_name): New.
+ (frv_output_addr_const_extra): New.
+ (frv_expand_fdpic_call): New.
+ (frv_fdpic_fptr_operand): New.
+ (gpr_or_int12_operand): Handle GOT operands.
+ (int_2word_operand): Handle GOT operands.
+ (fdpic_operand): New.
+ (fdpic_splittable_got_operand): New.
+ (fdpic_got12_operand): New.
+ (frv_emit_movsi): Handle GOT operands.
+ (frv_assemble_integer): -mfdpic doesn't use rofixups.
+ (frv_print_operand): Support 'g' code for GOT operands.
+ * config/frv/frv-protos.h: Add prototypes as needed.
+ * config/frv/frv.md (R_FRV_GOT12, R_FRV_GOTHI, R_FRV_GOTLO,
+ R_FRV_FUNCDESC, R_FRV_FUNCDESC_GOT12, R_FRV_FUNCDESC_GOTHI,
+ R_FRV_FUNCDESC_GOTLO, R_FRV_FUNCDESC_VALUE,
+ R_FRV_FUNCDESC_GOTOFF12, R_FRV_FUNCDESC_GOTOFFHI,
+ R_FRV_FUNCDESC_GOTOFFLO, R_FRV_GOTOFF12, R_FRV_GOTOFFHI,
+ R_FRV_GOTOFFLO): New.
+ (movsi_high_got, movsi_lo_sum_got): New.
+ (*movsi_pic): Don't use this splitter for -mfdpic.
+ (addsi3): Allow GOT references also.
+ (call, call_value): Handle -mfdpic separately.
+ (call_fdpicdi, call_fdpicsi, lddi, call_value_fdpicdi,
+ call_value_fdpicsi): New.
+ (symGOT2reg, symGOT2reg_i, got splitters, symGOTOFF2reg,
+ symGOTOFF2reg_i): New.
+ * config/frv/frv.h (MASK_FDPIC): New.
+ (TARGET_FDPIC): New.
+ (TARGET_SWITCHES): Add -mfdpic.
+ (FDPIC_FPTR_REGNO): New.
+ (FDPIC_REGNO): New.
+ (OUR_FDPIC_REG): New.
+ (enum reg_class): Add FDPIC_REGS, FDPIC_FPTR_REGS, and
+ FDPIC_CALL_REGS.
+ (REG_CLASS_NAMES): Likewise.
+ (REG_CLASS_CONTENTS): Likewise.
+ (EXTRA_CONSTRAINT_FOR_Y): New, for 12-bit GOTs.
+ (EXTRA_CONSTRAINT): Add it here.
+ (FRV_GLOBAL_P): New.
+ (OUTPUT_ADDR_CONST_EXTRA): New.
+
2004-02-24 Kazu Hirata <kazu@cs.umass.edu>
* config/sparc/sparc.h: Remove commented-out definitions of
diff --git a/gcc/config.gcc b/gcc/config.gcc
index b8b118f..e090d88 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -420,7 +420,7 @@ case ${target} in
*-*-linux*libc1* | *-*-linux*aout*)
# Avoid the generic linux case.
;;
-*-*-linux*)
+*-*-linux* | frv-*-*linux*)
# Must come before *-*-gnu* (because of *-*-linux-gnu* systems).
extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
gas=yes
@@ -718,6 +718,11 @@ frv-*-elf)
tmake_file=frv/t-frv
use_fixproto=yes
;;
+frv-*-*linux*)
+ tm_file="dbxelf.h elfos.h svr4.h ${tm_file} \
+ linux.h frv/linux.h frv/frv-abi.h"
+ tmake_file="t-slibgcc-elf-ver t-linux frv/t-frv frv/t-linux"
+ ;;
h8300-*-rtems*)
tmake_file="h8300/t-h8300 t-rtems"
tm_file="h8300/h8300.h dbxcoff.h h8300/coff.h h8300/rtems.h rtems.h"
@@ -2159,6 +2164,9 @@ if test x$with_cpu = x ; then
alphaev5*-*-*)
with_cpu=ev5
;;
+ frv-*-*linux*)
+ with_cpu=fr400
+ ;;
sparc*-*-*)
with_cpu="`echo ${target} | sed 's/-.*$//'`"
if [ x$with_cpu = xsparc64 ]; then
@@ -2269,6 +2277,17 @@ fi
fi
;;
+ fr*-*-*linux*)
+ supported_defaults=cpu
+ case "$with_cpu" in
+ fr400) ;;
+ *)
+ echo "Unknown cpu used in --with-cpu=$with_cpu" 1>&2
+ exit 1
+ ;;
+ esac
+ ;;
+
hppa*-*-* | parisc*-*-*)
supported_defaults="arch schedule"
diff --git a/gcc/config/frv/frv-abi.h b/gcc/config/frv/frv-abi.h
index a38dd16..7a53775 100644
--- a/gcc/config/frv/frv-abi.h
+++ b/gcc/config/frv/frv-abi.h
@@ -1,5 +1,5 @@
/* Frv map GCC names to FR-V ABI.
- Copyright (C) 2000 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2003 Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
This file is part of GCC.
@@ -43,7 +43,8 @@ __asm__ (".text\n" \
"\t.type\t" #NEW ",@function\n" \
#NEW ":\n" \
"\tor\tgr11, gr0, gr10\n" \
- "\tbra\t" #OLD "\n");
+ ".L" #OLD " = " #OLD "\n" \
+ "\tbra\t.L" #OLD "\n");
#ifdef L_sf_to_df
#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY(__extendsfdf2,__ftod)
diff --git a/gcc/config/frv/frv-protos.h b/gcc/config/frv/frv-protos.h
index af35ca8..6426350 100644
--- a/gcc/config/frv/frv-protos.h
+++ b/gcc/config/frv/frv-protos.h
@@ -63,9 +63,9 @@ extern int frv_frame_pointer_required (void);
extern int frv_initial_elimination_offset (int, int);
#ifdef RTX_CODE
-extern int frv_legitimate_address_p (enum machine_mode, rtx,
- int, int);
-extern rtx frv_legitimize_address (rtx, rtx, enum machine_mode);
+extern int frv_legitimate_address_p (enum machine_mode, rtx,
+ int, int, int);
+extern rtx frv_find_base_term (rtx);
#ifdef TREE_CODE
extern void frv_init_cumulative_args (CUMULATIVE_ARGS *, tree,
@@ -225,5 +225,7 @@ extern int even_acc_operand (rtx, enum machine_mode);
extern int quad_acc_operand (rtx, enum machine_mode);
extern int accg_operand (rtx, enum machine_mode);
extern rtx frv_matching_accg_for_acc (rtx);
+extern void frv_expand_fdpic_call (rtx *, int);
+extern rtx frv_gen_GPsym2reg (rtx, rtx);
#endif
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index 1773a82..92daeaa 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2004
+/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004
Free Software Foundation, Inc.
Contributed by Red Hat, Inc.
@@ -48,11 +48,21 @@ Boston, MA 02111-1307, USA. */
#include <ctype.h>
#include "target.h"
#include "target-def.h"
+#include "integrate.h"
#ifndef FRV_INLINE
#define FRV_INLINE inline
#endif
+/* Information about a relocation unspec. SYMBOL is the relocation symbol
+ (a SYMBOL_REF or LABEL_REF), RELOC is the type of relocation and OFFSET
+ is the constant addend. */
+struct frv_unspec {
+ rtx symbol;
+ int reloc;
+ HOST_WIDE_INT offset;
+};
+
/* Temporary register allocation support structure. */
typedef struct frv_tmp_reg_struct
{
@@ -199,8 +209,8 @@ int frv_sched_lookahead = 4; /* -msched-lookahead=n */
/* Forward references */
static int frv_default_flags_for_cpu (void);
static int frv_string_begins_with (tree, const char *);
-static FRV_INLINE int const_small_data_p (rtx);
-static FRV_INLINE int plus_small_data_p (rtx, rtx);
+static FRV_INLINE bool frv_small_data_reloc_p (rtx, int);
+static FRV_INLINE bool frv_const_unspec_p (rtx, struct frv_unspec *);
static void frv_print_operand_memory_reference_reg
(FILE *, rtx);
static void frv_print_operand_memory_reference (FILE *, rtx, int);
@@ -270,6 +280,11 @@ static rtx frv_expand_builtin_saveregs (void);
static bool frv_rtx_costs (rtx, int, int, int*);
static void frv_asm_out_constructor (rtx, int);
static void frv_asm_out_destructor (rtx, int);
+static bool frv_function_symbol_referenced_p (rtx);
+static bool frv_cannot_force_const_mem (rtx);
+static const char *unspec_got_name (int);
+static void frv_output_const_unspec (FILE *,
+ const struct frv_unspec *);
static rtx frv_struct_value_rtx (tree, int);
/* Initialize the GCC target structure. */
@@ -304,6 +319,9 @@ static rtx frv_struct_value_rtx (tree, int);
#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE frv_use_dfa_pipeline_interface
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem
+
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX frv_struct_value_rtx
@@ -314,47 +332,74 @@ static rtx frv_struct_value_rtx (tree, int);
struct gcc_target targetm = TARGET_INITIALIZER;
-/* Given a CONST, return true if the symbol_ref points to small data. */
+/* Return true if SYMBOL is a small data symbol and relocation RELOC
+ can be used to access it directly in a load or store. */
-static FRV_INLINE int
-const_small_data_p (rtx x)
+static FRV_INLINE bool
+frv_small_data_reloc_p (rtx symbol, int reloc)
{
- rtx x0, x1;
+ return (GET_CODE (symbol) == SYMBOL_REF
+ && SYMBOL_REF_SMALL_P (symbol)
+ && (!TARGET_FDPIC || flag_pic == 1)
+ && (reloc == R_FRV_GOTOFF12 || reloc == R_FRV_GPREL12));
+}
- if (GET_CODE (XEXP (x, 0)) != PLUS)
- return FALSE;
+/* Return true if X is a valid relocation unspec. If it is, fill in UNSPEC
+ appropriately. */
- x0 = XEXP (XEXP (x, 0), 0);
- if (GET_CODE (x0) != SYMBOL_REF || !SYMBOL_REF_SMALL_P (x0))
- return FALSE;
+static FRV_INLINE bool
+frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
+{
+ if (GET_CODE (x) == CONST)
+ {
+ unspec->offset = 0;
+ x = XEXP (x, 0);
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ unspec->offset += INTVAL (XEXP (x, 1));
+ x = XEXP (x, 0);
+ }
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_GOT)
+ {
+ unspec->symbol = XVECEXP (x, 0, 0);
+ unspec->reloc = INTVAL (XVECEXP (x, 0, 1));
- x1 = XEXP (XEXP (x, 0), 1);
- if (GET_CODE (x1) != CONST_INT
- || !IN_RANGE_P (INTVAL (x1), -2048, 2047))
- return FALSE;
+ if (unspec->offset == 0)
+ return true;
- return TRUE;
+ if (frv_small_data_reloc_p (unspec->symbol, unspec->reloc)
+ && unspec->offset > 0
+ && (unsigned HOST_WIDE_INT) unspec->offset < g_switch_value)
+ return true;
+ }
+ }
+ return false;
}
-/* Given a PLUS, return true if this is a small data reference. */
+/* Decide whether we can force certain constants to memory. If we
+ decide we can't, the caller should be able to cope with it in
+ another way.
-static FRV_INLINE int
-plus_small_data_p (rtx op0, rtx op1)
-{
- if (GET_MODE (op0) == SImode
- && GET_CODE (op0) == REG
- && REGNO (op0) == SDA_BASE_REG)
- {
- if (GET_CODE (op1) == SYMBOL_REF)
- return SYMBOL_REF_SMALL_P (op1);
+ We never allow constants to be forced into memory for TARGET_FDPIC.
+ This is necessary for several reasons:
- if (GET_CODE (op1) == CONST)
- return const_small_data_p (op1);
- }
+ 1. Since LEGITIMATE_CONSTANT_P rejects constant pool addresses, the
+ target-independent code will try to force them into the constant
+ pool, thus leading to infinite recursion.
- return FALSE;
-}
+ 2. We can never introduce new constant pool references during reload.
+ Any such reference would require use of the pseudo FDPIC register.
+ 3. We can't represent a constant added to a function pointer (which is
+ not the same as a pointer to a function+constant).
+
+ 4. In many cases, it's more efficient to calculate the constant in-line. */
+
+static bool
+frv_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
+{
+ return TARGET_FDPIC;
+}
static int
frv_default_flags_for_cpu (void)
@@ -577,13 +622,18 @@ frv_override_options (void)
reg_class_from_letter['A'] = QUAD_ACC_REGS;
reg_class_from_letter['B'] = ACCG_REGS;
reg_class_from_letter['C'] = CR_REGS;
+ reg_class_from_letter['W'] = FDPIC_CALL_REGS; /* gp14+15 */
+ reg_class_from_letter['Z'] = FDPIC_REGS; /* gp15 */
/* There is no single unaligned SI op for PIC code. Sometimes we
need to use ".4byte" and sometimes we need to use ".picptr".
See frv_assemble_integer for details. */
- if (flag_pic)
+ if (flag_pic || TARGET_FDPIC)
targetm.asm_out.unaligned_op.si = 0;
+ if ((target_flags_explicit & MASK_LINKED_FP) == 0)
+ target_flags |= MASK_LINKED_FP;
+
init_machine_status = frv_init_machine_status;
}
@@ -686,6 +736,10 @@ frv_conditional_register_usage (void)
fixed_regs[FCR_FIRST] = call_used_regs[FCR_FIRST] = 1;
}
+ if (TARGET_FDPIC)
+ fixed_regs[GPR_FIRST + 16] = fixed_regs[GPR_FIRST + 17] =
+ call_used_regs[GPR_FIRST + 16] = call_used_regs[GPR_FIRST + 17] = 0;
+
#if 0
/* If -fpic, SDA_BASE_REG is the PIC register. */
if (g_switch_value == 0 && !flag_pic)
@@ -966,7 +1020,8 @@ frv_stack_info (void)
if ((regs_ever_live[regno] && !call_used_regs[regno])
|| (current_function_calls_eh_return
&& (regno >= FIRST_EH_REGNUM && regno <= LAST_EH_REGNUM))
- || (flag_pic && cfun->uses_pic_offset_table && regno == PIC_REGNO))
+ || (!TARGET_FDPIC && flag_pic
+ && cfun->uses_pic_offset_table && regno == PIC_REGNO))
{
info_ptr->save_p[regno] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
@@ -982,8 +1037,11 @@ frv_stack_info (void)
case STACK_REGS_LR:
if (regs_ever_live[LR_REGNO]
|| profile_flag
- || frame_pointer_needed
- || (flag_pic && cfun->uses_pic_offset_table))
+ /* This is set for __builtin_return_address, etc. */
+ || cfun->machine->frame_needed
+ || (TARGET_LINKED_FP && frame_pointer_needed)
+ || (!TARGET_FDPIC && flag_pic
+ && cfun->uses_pic_offset_table))
{
info_ptr->save_p[LR_REGNO] = REG_SAVE_1WORD;
size_1word += UNITS_PER_WORD;
@@ -1077,6 +1135,7 @@ frv_stack_info (void)
/* See if we need to create a frame at all, if so add header area. */
if (info_ptr->total_size > 0
+ || frame_pointer_needed
|| info_ptr->regs[STACK_REGS_LR].size_1word > 0
|| info_ptr->regs[STACK_REGS_STRUCT].size_1word > 0)
{
@@ -1652,7 +1711,7 @@ frv_expand_prologue (void)
emit_insn (gen_blockage ());
/* Set up pic register/small data register for this function. */
- if (flag_pic && cfun->uses_pic_offset_table)
+ if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
emit_insn (gen_pic_prologue (gen_rtx_REG (Pmode, PIC_REGNO),
gen_rtx_REG (Pmode, LR_REGNO),
gen_rtx_REG (SImode, OFFSET_REGNO)));
@@ -1787,7 +1846,31 @@ frv_asm_output_mi_thunk (FILE *file,
fprintf (file, "\tadd %s,%s,%s\n", name_add, name_arg0, name_arg0);
}
- if (!flag_pic)
+ if (TARGET_FDPIC)
+ {
+ const char *name_pic = reg_names[FDPIC_REGNO];
+ name_jmp = reg_names[FDPIC_FPTR_REGNO];
+
+ if (flag_pic != 1)
+ {
+ fprintf (file, "\tsethi%s #gotofffuncdeschi(", parallel);
+ assemble_name (file, name_func);
+ fprintf (file, "),%s\n", name_jmp);
+
+ fprintf (file, "\tsetlo #gotofffuncdesclo(");
+ assemble_name (file, name_func);
+ fprintf (file, "),%s\n", name_jmp);
+
+ fprintf (file, "\tldd @(%s,%s), %s\n", name_jmp, name_pic, name_jmp);
+ }
+ else
+ {
+ fprintf (file, "\tlddo @(%s,#gotofffuncdesc12(", name_pic);
+ assemble_name (file, name_func);
+ fprintf (file, "\t)), %s\n", name_jmp);
+ }
+ }
+ else if (!flag_pic)
{
fprintf (file, "\tsethi%s #hi(", parallel);
assemble_name (file, name_func);
@@ -1852,6 +1935,11 @@ frv_asm_output_mi_thunk (FILE *file,
int
frv_frame_pointer_required (void)
{
+ /* If we forgoing the usual linkage requirements, we only need
+ a frame pointer if the stack pointer might change. */
+ if (!TARGET_LINKED_FP)
+ return !current_function_sp_is_unchanging;
+
if (! current_function_is_leaf)
return TRUE;
@@ -1864,7 +1952,7 @@ frv_frame_pointer_required (void)
if (!current_function_sp_is_unchanging)
return TRUE;
- if (flag_pic && cfun->uses_pic_offset_table)
+ if (!TARGET_FDPIC && flag_pic && cfun->uses_pic_offset_table)
return TRUE;
if (profile_flag)
@@ -2292,8 +2380,10 @@ frv_dynamic_chain_address (rtx frame)
address of other frames. */
rtx
-frv_return_addr_rtx (int count ATTRIBUTE_UNUSED, rtx frame)
+frv_return_addr_rtx (int count, rtx frame)
{
+ if (count != 0)
+ return const0_rtx;
cfun->machine->frame_needed = 1;
return gen_rtx_MEM (Pmode, plus_constant (frame, 8));
}
@@ -2366,6 +2456,7 @@ frv_print_operand_memory_reference_reg (FILE * stream, rtx x)
static void
frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
{
+ struct frv_unspec unspec;
rtx x0 = NULL_RTX;
rtx x1 = NULL_RTX;
@@ -2434,29 +2525,10 @@ frv_print_operand_memory_reference (FILE * stream, rtx x, int addr_offset)
fprintf (stream, "%ld", (long) (INTVAL (x1) + addr_offset));
break;
- case SYMBOL_REF:
- if (x0 && GET_CODE (x0) == REG && REGNO (x0) == SDA_BASE_REG
- && SYMBOL_REF_SMALL_P (x1))
- {
- fputs ("#gprel12(", stream);
- assemble_name (stream, XSTR (x1, 0));
- fputs (")", stream);
- }
- else
- fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
- break;
-
case CONST:
- if (x0 && GET_CODE (x0) == REG && REGNO (x0) == SDA_BASE_REG
- && const_small_data_p (x1))
- {
- fputs ("#gprel12(", stream);
- assemble_name (stream, XSTR (XEXP (XEXP (x1, 0), 0), 0));
- fprintf (stream, "+"HOST_WIDE_INT_PRINT_DEC")",
- INTVAL (XEXP (XEXP (x1, 0), 1)));
- }
- else
- fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x);
+ if (!frv_const_unspec_p (x1, &unspec))
+ fatal_insn ("Bad insn to frv_print_operand_memory_reference:", x1);
+ frv_output_const_unspec (stream, &unspec);
break;
default:
@@ -2573,6 +2645,7 @@ frv_print_operand_jump_hint (rtx insn)
void
frv_print_operand (FILE * file, rtx x, int code)
{
+ struct frv_unspec unspec;
HOST_WIDE_INT value;
int offset;
@@ -2726,6 +2799,13 @@ frv_print_operand (FILE * file, rtx x, int code)
}
break;
+ case 'g':
+ /* Print appropriate GOT function. */
+ if (GET_CODE (x) != CONST_INT)
+ fatal_insn ("Bad insn to frv_print_operand, 'g' modifier:", x);
+ fputs (unspec_got_name (INTVAL (x)), file);
+ break;
+
case 'I':
/* Print 'i' if the operand is a constant, or is a memory reference that
adds a constant. */
@@ -2733,6 +2813,8 @@ frv_print_operand (FILE * file, rtx x, int code)
x = ((GET_CODE (XEXP (x, 0)) == PLUS)
? XEXP (XEXP (x, 0), 1)
: XEXP (x, 0));
+ else if (GET_CODE (x) == PLUS)
+ x = XEXP (x, 1);
switch (GET_CODE (x))
{
@@ -2861,6 +2943,9 @@ frv_print_operand (FILE * file, rtx x, int code)
|| GET_CODE (x) == CONST_DOUBLE)
fprintf (file, "%s%ld", IMMEDIATE_PREFIX, (long) value);
+ else if (frv_const_unspec_p (x, &unspec))
+ frv_output_const_unspec (file, &unspec);
+
else if (GET_CODE (x) == MEM)
frv_print_operand_address (file, XEXP (x, 0));
@@ -3202,7 +3287,8 @@ int
frv_legitimate_address_p (enum machine_mode mode,
rtx x,
int strict_p,
- int condexec_p)
+ int condexec_p,
+ int allow_double_reg_p)
{
rtx x0, x1;
int ret = 0;
@@ -3284,7 +3370,7 @@ frv_legitimate_address_p (enum machine_mode mode,
case REG:
/* Do not allow reg+reg addressing for modes > 1 word if we
can't depend on having move double instructions. */
- if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ if (!allow_double_reg_p && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
ret = FALSE;
else
ret = frv_regno_ok_for_base_p (REGNO (x1), strict_p);
@@ -3306,15 +3392,8 @@ frv_legitimate_address_p (enum machine_mode mode,
}
break;
- case SYMBOL_REF:
- if (!condexec_p
- && regno0 == SDA_BASE_REG
- && SYMBOL_REF_SMALL_P (x1))
- ret = TRUE;
- break;
-
case CONST:
- if (!condexec_p && regno0 == SDA_BASE_REG && const_small_data_p (x1))
+ if (!condexec_p && got12_operand (x1, VOIDmode))
ret = TRUE;
break;
@@ -3334,54 +3413,107 @@ frv_legitimate_address_p (enum machine_mode mode,
}
-/* A C compound statement that attempts to replace X with a valid memory
- address for an operand of mode MODE. WIN will be a C statement label
- elsewhere in the code; the macro definition may use
+/* Test whether a local function descriptor is canonical, i.e.,
+ whether we can use FUNCDESC_GOTOFF to compute the address of the
+ function. */
+
+static bool
+frv_local_funcdesc_p (rtx fnx)
+{
+ tree fn;
+ enum symbol_visibility vis;
+ bool ret;
- GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
+ if (! SYMBOL_REF_LOCAL_P (fnx))
+ return FALSE;
+
+ fn = SYMBOL_REF_DECL (fnx);
+
+ if (! fn)
+ return FALSE;
- to avoid further processing if the address has become legitimate.
+ vis = DECL_VISIBILITY (fn);
- X will always be the result of a call to `break_out_memory_refs', and OLDX
- will be the operand that was given to that function to produce X.
+ if (vis == VISIBILITY_PROTECTED)
+ /* Private function descriptors for protected functions are not
+ canonical. Temporarily change the visibility to global. */
+ vis = VISIBILITY_DEFAULT;
+ else if (flag_shlib)
+ /* If we're already compiling for a shared library (that, unlike
+ executables, can't assume that the existence of a definition
+ implies local binding), we can skip the re-testing. */
+ return TRUE;
- The code generated by this macro should not alter the substructure of X. If
- it transforms X into a more legitimate form, it should assign X (which will
- always be a C variable) a new value.
+ ret = default_binds_local_p_1 (fn, flag_pic);
- It is not necessary for this macro to come up with a legitimate address.
- The compiler has standard ways of doing so in all cases. In fact, it is
- safe for this macro to do nothing. But often a machine-dependent strategy
- can generate better code. */
+ DECL_VISIBILITY (fn) = vis;
+
+ return ret;
+}
+
+/* Load the _gp symbol into DEST. SRC is supposed to be the FDPIC
+ register. */
rtx
-frv_legitimize_address (rtx x,
- rtx oldx ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- rtx ret = NULL_RTX;
-
- /* Don't try to legitimize addresses if we are not optimizing, since the
- address we generate is not a general operand, and will horribly mess
- things up when force_reg is called to try and put it in a register because
- we aren't optimizing. */
- if (optimize
- && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_SMALL_P (x))
- || (GET_CODE (x) == CONST && const_small_data_p (x))))
- {
- ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, SDA_BASE_REG), x);
- if (flag_pic)
- cfun->uses_pic_offset_table = TRUE;
- }
+frv_gen_GPsym2reg (rtx dest, rtx src)
+{
+ tree gp = get_identifier ("_gp");
+ rtx gp_sym = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (gp));
- if (TARGET_DEBUG_ADDR && ret != NULL_RTX)
+ return gen_symGOT2reg (dest, gp_sym, src, GEN_INT (R_FRV_GOT12));
+}
+
+static const char *
+unspec_got_name (int i)
+{
+ switch (i)
{
- fprintf (stderr, "\n========== LEGITIMIZE_ADDRESS, mode = %s, modified address\n",
- GET_MODE_NAME (mode));
- debug_rtx (ret);
+ case R_FRV_GOT12: return "got12";
+ case R_FRV_GOTHI: return "gothi";
+ case R_FRV_GOTLO: return "gotlo";
+ case R_FRV_FUNCDESC: return "funcdesc";
+ case R_FRV_FUNCDESC_GOT12: return "gotfuncdesc12";
+ case R_FRV_FUNCDESC_GOTHI: return "gotfuncdeschi";
+ case R_FRV_FUNCDESC_GOTLO: return "gotfuncdesclo";
+ case R_FRV_FUNCDESC_VALUE: return "funcdescvalue";
+ case R_FRV_FUNCDESC_GOTOFF12: return "gotofffuncdesc12";
+ case R_FRV_FUNCDESC_GOTOFFHI: return "gotofffuncdeschi";
+ case R_FRV_FUNCDESC_GOTOFFLO: return "gotofffuncdesclo";
+ case R_FRV_GOTOFF12: return "gotoff12";
+ case R_FRV_GOTOFFHI: return "gotoffhi";
+ case R_FRV_GOTOFFLO: return "gotofflo";
+ case R_FRV_GPREL12: return "gprel12";
+ case R_FRV_GPRELHI: return "gprelhi";
+ case R_FRV_GPRELLO: return "gprello";
+ default: abort ();
}
+}
- return ret;
+/* Write the assembler syntax for UNSPEC to STREAM. Note that any offset
+ is added inside the relocation operator. */
+
+static void
+frv_output_const_unspec (FILE *stream, const struct frv_unspec *unspec)
+{
+ fprintf (stream, "#%s(", unspec_got_name (unspec->reloc));
+ output_addr_const (stream, plus_constant (unspec->symbol, unspec->offset));
+ fputs (")", stream);
+}
+
+/* Implement FIND_BASE_TERM. See whether ORIG_X represents #gprel12(foo)
+ or #gotoff12(foo) for some small data symbol foo. If so, return foo,
+ otherwise return ORIG_X. */
+
+rtx
+frv_find_base_term (rtx x)
+{
+ struct frv_unspec unspec;
+
+ if (frv_const_unspec_p (x, &unspec)
+ && frv_small_data_reloc_p (unspec.symbol, unspec.reloc))
+ return plus_constant (unspec.symbol, unspec.offset);
+
+ return x;
}
/* Return 1 if operand is a valid FRV address. CONDEXEC_P is true if
@@ -3393,9 +3525,109 @@ frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
return ((GET_MODE (op) == mode || mode == VOIDmode)
&& GET_CODE (op) == MEM
&& frv_legitimate_address_p (mode, XEXP (op, 0),
- reload_completed, condexec_p));
+ reload_completed, condexec_p, FALSE));
+}
+
+void
+frv_expand_fdpic_call (rtx *operands, int ret_value)
+{
+ rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
+ rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REG);
+ rtx c, rvrtx=0;
+ rtx addr;
+
+ if (ret_value)
+ {
+ rvrtx = operands[0];
+ operands ++;
+ }
+
+ addr = XEXP (operands[0], 0);
+
+ /* Inline PLTs if we're optimizing for speed. We'd like to inline
+ any calls that would involve a PLT, but can't tell, since we
+ don't know whether an extern function is going to be provided by
+ a separate translation unit or imported from a separate module.
+ When compiling for shared libraries, if the function has default
+ visibility, we assume it's overridable, so we inline the PLT, but
+ for executables, we don't really have a way to make a good
+ decision: a function is as likely to be imported from a shared
+ library as it is to be defined in the executable itself. We
+ assume executables will get global functions defined locally,
+ whereas shared libraries will have them potentially overridden,
+ so we only inline PLTs when compiling for shared libraries.
+
+ In order to mark a function as local to a shared library, any
+ non-default visibility attribute suffices. Unfortunately,
+ there's no simple way to tag a function declaration as ``in a
+ different module'', which we could then use to trigger PLT
+ inlining on executables. There's -minline-plt, but it affects
+ all external functions, so one would have to also mark function
+ declarations available in the same module with non-default
+ visibility, which is advantageous in itself. */
+ if (GET_CODE (addr) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (addr)
+ && TARGET_INLINE_PLT)
+ {
+ rtx x, dest;
+ dest = gen_reg_rtx (SImode);
+ if (flag_pic != 1)
+ x = gen_symGOTOFF2reg_hilo (dest, addr, OUR_FDPIC_REG,
+ GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
+ else
+ x = gen_symGOTOFF2reg (dest, addr, OUR_FDPIC_REG,
+ GEN_INT (R_FRV_FUNCDESC_GOTOFF12));
+ emit_insn (x);
+ cfun->uses_pic_offset_table = TRUE;
+ addr = dest;
+ }
+ else if (GET_CODE (addr) == SYMBOL_REF)
+ {
+ /* These are always either local, or handled through a local
+ PLT. */
+ if (ret_value)
+ c = gen_call_value_fdpicsi (rvrtx, addr, operands[1],
+ operands[2], picreg, lr);
+ else
+ c = gen_call_fdpicsi (addr, operands[1], operands[2], picreg, lr);
+ emit_call_insn (c);
+ return;
+ }
+ else if (! ldd_address_operand (addr, Pmode))
+ addr = force_reg (Pmode, addr);
+
+ picreg = gen_reg_rtx (DImode);
+ emit_insn (gen_movdi_ldd (picreg, addr));
+
+ if (ret_value)
+ c = gen_call_value_fdpicdi (rvrtx, picreg, const0_rtx, lr);
+ else
+ c = gen_call_fdpicdi (picreg, const0_rtx, lr);
+ emit_call_insn (c);
}
+/* An address operand that may use a pair of registers, an addressing
+ mode that we reject in general. */
+
+int
+ldd_address_operand (rtx x, enum machine_mode mode)
+{
+ if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)
+ return FALSE;
+
+ return frv_legitimate_address_p (DImode, x, reload_completed, FALSE, TRUE);
+}
+
+int
+fdpic_fptr_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return FALSE;
+ if (GET_CODE (op) != REG)
+ return FALSE;
+ if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
+ return FALSE;
+ return TRUE;
+}
/* Return 1 is OP is a memory operand, or will be turned into one by
reload. */
@@ -3456,6 +3688,9 @@ gpr_or_int12_operand (rtx op, enum machine_mode mode)
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
+ if (got12_operand (op, mode))
+ return true;
+
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
@@ -3638,7 +3873,7 @@ uint1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
to load up and can be split into sethi/setlo instructions.. */
int
-int_2word_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+int_2word_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT value;
REAL_VALUE_TYPE rv;
@@ -3650,13 +3885,24 @@ int_2word_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
break;
case LABEL_REF:
+ if (TARGET_FDPIC)
+ return FALSE;
+
return (flag_pic == 0);
case CONST:
- /* small data references are already 1 word */
- return (flag_pic == 0) && (! const_small_data_p (op));
+ if (flag_pic || TARGET_FDPIC)
+ return FALSE;
+
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
+ op = XEXP (op, 0);
+ return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
case SYMBOL_REF:
+ if (TARGET_FDPIC)
+ return FALSE;
+
/* small data references are already 1 word */
return (flag_pic == 0) && (! SYMBOL_REF_SMALL_P (op));
@@ -3682,85 +3928,6 @@ int_2word_operand(rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
return FALSE;
}
-/* Return 1 if operand is the pic address register. */
-int
-pic_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (! flag_pic)
- return FALSE;
-
- if (GET_CODE (op) != REG)
- return FALSE;
-
- if (REGNO (op) != PIC_REGNO)
- return FALSE;
-
- return TRUE;
-}
-
-/* Return 1 if operand is a symbolic reference when a PIC option is specified
- that takes 3 separate instructions to form. */
-
-int
-pic_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (! flag_pic)
- return FALSE;
-
- switch (GET_CODE (op))
- {
- default:
- break;
-
- case LABEL_REF:
- return TRUE;
-
- case SYMBOL_REF:
- /* small data references are already 1 word */
- return ! SYMBOL_REF_SMALL_P (op);
-
- case CONST:
- /* small data references are already 1 word */
- return ! const_small_data_p (op);
- }
-
- return FALSE;
-}
-
-/* Return 1 if operand is the small data register. */
-int
-small_data_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != REG)
- return FALSE;
-
- if (REGNO (op) != SDA_BASE_REG)
- return FALSE;
-
- return TRUE;
-}
-
-/* Return 1 if operand is a symbolic reference to a small data area static or
- global object. */
-
-int
-small_data_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- switch (GET_CODE (op))
- {
- default:
- break;
-
- case CONST:
- return const_small_data_p (op);
-
- case SYMBOL_REF:
- return SYMBOL_REF_SMALL_P (op);
- }
-
- return FALSE;
-}
-
/* Return 1 if operand is a 16 bit unsigned immediate. */
int
@@ -4103,7 +4270,7 @@ dbl_memory_one_insn_operand (rtx op, enum machine_mode mode)
if (GET_CODE (addr0) != REG)
return FALSE;
- if (plus_small_data_p (addr0, addr1))
+ if (got12_operand (addr1, VOIDmode))
return TRUE;
if (GET_CODE (addr1) != CONST_INT)
@@ -4164,7 +4331,7 @@ move_destination_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, FALSE);
+ reload_completed, FALSE, FALSE);
return (code == REG);
@@ -4184,6 +4351,53 @@ move_destination_operand (rtx op, enum machine_mode mode)
return FALSE;
}
+/* Look for a SYMBOL_REF of a function in an rtx. We always want to
+ process these separately from any offsets, such that we add any
+ offsets to the function descriptor (the actual pointer), not to the
+ function address. */
+
+static bool
+frv_function_symbol_referenced_p (rtx x)
+{
+ const char *format;
+ int length;
+ int j;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ return SYMBOL_REF_FUNCTION_P (x);
+
+ length = GET_RTX_LENGTH (GET_CODE (x));
+ format = GET_RTX_FORMAT (GET_CODE (x));
+
+ for (j = 0; j < length; ++j)
+ {
+ switch (format[j])
+ {
+ case 'e':
+ if (frv_function_symbol_referenced_p (XEXP (x, j)))
+ return TRUE;
+ break;
+
+ case 'V':
+ case 'E':
+ if (XVEC (x, j) != 0)
+ {
+ int k;
+ for (k = 0; k < XVECLEN (x, j); ++k)
+ if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
+ return TRUE;
+ }
+ break;
+
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
/* Return true if operand is something that can be an input for a move
operation. */
@@ -4200,9 +4414,6 @@ move_source_operand (rtx op, enum machine_mode mode)
case CONST_INT:
case CONST_DOUBLE:
- case SYMBOL_REF:
- case LABEL_REF:
- case CONST:
return immediate_operand (op, mode);
case SUBREG:
@@ -4213,7 +4424,7 @@ move_source_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, FALSE);
+ reload_completed, FALSE, FALSE);
return (code == REG);
@@ -4255,7 +4466,7 @@ condexec_dest_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, TRUE);
+ reload_completed, TRUE, FALSE);
return (code == REG);
@@ -4301,7 +4512,7 @@ condexec_source_operand (rtx op, enum machine_mode mode)
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
- reload_completed, TRUE);
+ reload_completed, TRUE, FALSE);
return (code == REG);
@@ -4364,6 +4575,53 @@ lr_operand (rtx op, enum machine_mode mode)
return TRUE;
}
+/* Return true if operand is the uClinux PIC register. */
+
+int
+fdpic_operand (rtx op, enum machine_mode mode)
+{
+ if (!TARGET_FDPIC)
+ return FALSE;
+
+ if (GET_CODE (op) != REG)
+ return FALSE;
+
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return FALSE;
+
+ if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
+ return FALSE;
+
+ return TRUE;
+}
+
+int
+got12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ struct frv_unspec unspec;
+
+ if (frv_const_unspec_p (op, &unspec))
+ switch (unspec.reloc)
+ {
+ case R_FRV_GOT12:
+ case R_FRV_GOTOFF12:
+ case R_FRV_FUNCDESC_GOT12:
+ case R_FRV_FUNCDESC_GOTOFF12:
+ case R_FRV_GPREL12:
+ return true;
+ }
+ return false;
+}
+
+/* Return true if OP is a valid const-unspec expression. */
+
+int
+const_unspec_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ struct frv_unspec unspec;
+
+ return frv_const_unspec_p (op, &unspec);
+}
/* Return true if operand is a gpr register or a valid memory operation. */
int
@@ -4939,7 +5197,7 @@ condexec_memory_operand (rtx op, enum machine_mode mode)
if (GET_CODE (addr) == ADDRESSOF)
return TRUE;
- return frv_legitimate_address_p (mode, addr, reload_completed, TRUE);
+ return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
}
/* Return true if operator is an integer binary operator that can be combined
@@ -5133,6 +5391,9 @@ int
frv_emit_movsi (rtx dest, rtx src)
{
int base_regno = -1;
+ int unspec = 0;
+ rtx sym = src;
+ struct frv_unspec old_unspec;
if (!reload_in_progress
&& !reload_completed
@@ -5157,22 +5418,142 @@ frv_emit_movsi (rtx dest, rtx src)
break;
case LABEL_REF:
- if (flag_pic)
+ handle_label:
+ if (TARGET_FDPIC)
+ {
+ /* Using GPREL12, we use a single GOT entry for all symbols
+ in read-only sections, but trade sequences such as:
+
+ sethi #gothi(label), gr#
+ setlo #gotlo(label), gr#
+ ld @(gr15,gr#), gr#
+
+ for
+
+ ld @(gr15,#got12(_gp)), gr#
+ sethi #gprelhi(label), gr##
+ setlo #gprello(label), gr##
+ add gr#, gr##, gr##
+
+ We may often be able to share gr# for multiple
+ computations of GPREL addresses, and we may often fold
+ the final add into the pair of registers of a load or
+ store instruction, so it's often profitable. Even when
+ optimizing for size, we're trading a GOT entry for an
+ additional instruction, which trades GOT space
+ (read-write) for code size (read-only, shareable), as
+ long as the symbol is not used in more than two different
+ locations.
+
+ With -fpie/-fpic, we'd be trading a single load for a
+ sequence of 4 instructions, because the offset of the
+ label can't be assumed to be addressible with 12 bits, so
+ we don't do this. */
+ if (TARGET_GPREL_RO)
+ unspec = R_FRV_GPREL12;
+ else
+ unspec = R_FRV_GOT12;
+ }
+ else if (flag_pic)
base_regno = PIC_REGNO;
break;
case CONST:
- if (const_small_data_p (src))
- base_regno = SDA_BASE_REG;
-
- else if (flag_pic)
- base_regno = PIC_REGNO;
+ if (frv_const_unspec_p (src, &old_unspec))
+ break;
+ if (TARGET_FDPIC && frv_function_symbol_referenced_p (XEXP (src, 0)))
+ {
+ handle_whatever:
+ src = force_reg (GET_MODE (XEXP (src, 0)), XEXP (src, 0));
+ emit_move_insn (dest, src);
+ return TRUE;
+ }
+ else
+ {
+ sym = XEXP (sym, 0);
+ if (GET_CODE (sym) == PLUS
+ && GET_CODE (XEXP (sym, 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (sym, 1)) == CONST_INT)
+ sym = XEXP (sym, 0);
+ if (GET_CODE (sym) == SYMBOL_REF)
+ goto handle_sym;
+ else if (GET_CODE (sym) == LABEL_REF)
+ goto handle_label;
+ else
+ goto handle_whatever;
+ }
break;
case SYMBOL_REF:
- if (SYMBOL_REF_SMALL_P (src))
+ handle_sym:
+ if (TARGET_FDPIC)
+ {
+ if (SYMBOL_REF_FUNCTION_P (sym))
+ {
+ if (frv_local_funcdesc_p (sym))
+ unspec = R_FRV_FUNCDESC_GOTOFF12;
+ else
+ unspec = R_FRV_FUNCDESC_GOT12;
+ }
+ else
+ {
+ if (CONSTANT_POOL_ADDRESS_P (sym))
+ switch (GET_CODE (get_pool_constant (sym)))
+ {
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (flag_pic)
+ {
+ unspec = R_FRV_GOTOFF12;
+ break;
+ }
+ /* Fall through. */
+ default:
+ if (TARGET_GPREL_RO)
+ unspec = R_FRV_GPREL12;
+ else
+ unspec = R_FRV_GOT12;
+ break;
+ }
+ else if (SYMBOL_REF_LOCAL_P (sym)
+ && !SYMBOL_REF_EXTERNAL_P (sym)
+ && SYMBOL_REF_DECL (sym)
+ && (!DECL_P (SYMBOL_REF_DECL (sym))
+ || !DECL_COMMON (SYMBOL_REF_DECL (sym))))
+ {
+ tree decl = SYMBOL_REF_DECL (sym);
+ tree init = TREE_CODE (decl) == VAR_DECL
+ ? DECL_INITIAL (decl)
+ : TREE_CODE (decl) == CONSTRUCTOR
+ ? decl : 0;
+ int reloc = 0;
+ bool named_section, readonly;
+
+ if (init && init != error_mark_node)
+ reloc = compute_reloc_for_constant (init);
+
+ named_section = TREE_CODE (decl) == VAR_DECL
+ && lookup_attribute ("section", DECL_ATTRIBUTES (decl));
+ readonly = decl_readonly_section (decl, reloc);
+
+ if (named_section)
+ unspec = R_FRV_GOT12;
+ else if (!readonly)
+ unspec = R_FRV_GOTOFF12;
+ else if (readonly && TARGET_GPREL_RO)
+ unspec = R_FRV_GPREL12;
+ else
+ unspec = R_FRV_GOT12;
+ }
+ else
+ unspec = R_FRV_GOT12;
+ }
+ }
+
+ else if (SYMBOL_REF_SMALL_P (sym))
base_regno = SDA_BASE_REG;
else if (flag_pic)
@@ -5183,17 +5564,65 @@ frv_emit_movsi (rtx dest, rtx src)
if (base_regno >= 0)
{
- emit_insn (gen_rtx_SET (VOIDmode, dest,
- gen_rtx_PLUS (Pmode,
- gen_rtx_REG (Pmode, base_regno),
- src)));
-
+ if (GET_CODE (sym) == SYMBOL_REF && SYMBOL_REF_SMALL_P (sym))
+ emit_insn (gen_symGOTOFF2reg (dest, src,
+ gen_rtx_REG (Pmode, base_regno),
+ GEN_INT (R_FRV_GPREL12)));
+ else
+ emit_insn (gen_symGOTOFF2reg_hilo (dest, src,
+ gen_rtx_REG (Pmode, base_regno),
+ GEN_INT (R_FRV_GPREL12)));
if (base_regno == PIC_REGNO)
cfun->uses_pic_offset_table = TRUE;
+ return TRUE;
+ }
+ if (unspec)
+ {
+ rtx x;
+
+ /* Since OUR_FDPIC_REG is a pseudo register, we can't safely introduce
+ new uses of it once reload has begun. */
+ if (reload_in_progress || reload_completed)
+ abort ();
+
+ switch (unspec)
+ {
+ case R_FRV_GOTOFF12:
+ if (!frv_small_data_reloc_p (sym, unspec))
+ x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ case R_FRV_GPREL12:
+ if (!frv_small_data_reloc_p (sym, unspec))
+ x = gen_symGPREL2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGPREL2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ case R_FRV_FUNCDESC_GOTOFF12:
+ if (flag_pic != 1)
+ x = gen_symGOTOFF2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGOTOFF2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ default:
+ if (flag_pic != 1)
+ x = gen_symGOT2reg_hilo (dest, src, OUR_FDPIC_REG,
+ GEN_INT (unspec));
+ else
+ x = gen_symGOT2reg (dest, src, OUR_FDPIC_REG, GEN_INT (unspec));
+ break;
+ }
+ emit_insn (x);
+ cfun->uses_pic_offset_table = TRUE;
return TRUE;
}
+
return FALSE;
}
@@ -5280,11 +5709,6 @@ output_move_single (rtx operands[], rtx insn)
|| GET_CODE (src) == LABEL_REF
|| GET_CODE (src) == CONST)
{
- /* Silently fix up instances where the small data pointer is not
- used in the address. */
- if (small_data_symbolic_operand (src, GET_MODE (src)))
- return "addi %@, #gprel12(%1), %0";
-
return "#";
}
}
@@ -6794,17 +7218,14 @@ frv_ifcvt_rewrite_mem (rtx mem, enum machine_mode mode, rtx insn)
{
rtx addr = XEXP (mem, 0);
- if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE))
+ if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE))
{
if (GET_CODE (addr) == PLUS)
{
rtx addr_op0 = XEXP (addr, 0);
rtx addr_op1 = XEXP (addr, 1);
- if (plus_small_data_p (addr_op0, addr_op1))
- addr = frv_ifcvt_load_value (addr, insn);
-
- else if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
+ if (GET_CODE (addr_op0) == REG && CONSTANT_P (addr_op1))
{
rtx reg = frv_ifcvt_load_value (addr_op1, insn);
if (!reg)
@@ -6957,18 +7378,7 @@ frv_ifcvt_modify_insn (ce_if_block_t *ce_info,
op0 = XEXP (src, 0);
op1 = XEXP (src, 1);
- /* Special case load of small data address which looks like:
- r16+symbol_ref */
- if (GET_CODE (src) == PLUS && plus_small_data_p (op0, op1))
- {
- src = frv_ifcvt_load_value (src, insn);
- if (src)
- COND_EXEC_CODE (pattern) = gen_rtx_SET (VOIDmode, dest, src);
- else
- goto fail;
- }
-
- else if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
+ if (integer_register_operand (op0, SImode) && CONSTANT_P (op1))
{
op1 = frv_ifcvt_load_value (op1, insn);
if (op1)
@@ -7241,7 +7651,11 @@ frv_ifcvt_modify_cancel (ce_if_block_t *ce_info ATTRIBUTE_UNUSED)
int
frv_trampoline_size (void)
{
- return 5 /* instructions */ * 4 /* instruction size */;
+ if (TARGET_FDPIC)
+ /* Allocate room for the function descriptor and the lddi
+ instruction. */
+ return 8 + 6 * 4;
+ return 5 /* instructions */ * 4 /* instruction size. */;
}
@@ -7697,6 +8111,22 @@ frv_legitimate_constant_p (rtx x)
{
enum machine_mode mode = GET_MODE (x);
+ /* frv_cannot_force_const_mem always returns true for FDPIC. This
+ means that the move expanders will be expected to deal with most
+ kinds of constant, regardless of what we return here.
+
+ However, among its other duties, LEGITIMATE_CONSTANT_P decides whether
+ a constant can be entered into reg_equiv_constant[]. If we return true,
+ reload can create new instances of the constant whenever it likes.
+
+ The idea is therefore to accept as many constants as possible (to give
+ reload more freedom) while rejecting constants that can only be created
+ at certain times. In particular, anything with a symbolic component will
+ require use of the pseudo FDPIC register, which is only available before
+ reload. */
+ if (TARGET_FDPIC)
+ return LEGITIMATE_PIC_OPERAND_P (x);
+
/* All of the integer constants are ok. */
if (GET_CODE (x) != CONST_DOUBLE)
return TRUE;
@@ -7833,13 +8263,24 @@ frv_register_move_cost (enum reg_class from, enum reg_class to)
static bool
frv_assemble_integer (rtx value, unsigned int size, int aligned_p)
{
- if (flag_pic && size == UNITS_PER_WORD)
+ if ((flag_pic || TARGET_FDPIC) && size == UNITS_PER_WORD)
{
if (GET_CODE (value) == CONST
|| GET_CODE (value) == SYMBOL_REF
|| GET_CODE (value) == LABEL_REF)
{
- if (aligned_p)
+ if (TARGET_FDPIC && GET_CODE (value) == SYMBOL_REF
+ && SYMBOL_REF_FUNCTION_P (value))
+ {
+ fputs ("\t.picptr\tfuncdesc(", asm_out_file);
+ output_addr_const (asm_out_file, value);
+ fputs (")\n", asm_out_file);
+ return true;
+ }
+ else if (TARGET_FDPIC && GET_CODE (value) == CONST
+ && frv_function_symbol_referenced_p (value))
+ return false;
+ if (aligned_p && !TARGET_FDPIC)
{
static int label_num = 0;
char buf[256];
@@ -9433,6 +9874,14 @@ frv_rtx_costs (rtx x,
int outer_code ATTRIBUTE_UNUSED,
int *total)
{
+ if (outer_code == MEM)
+ {
+ /* Don't differentiate between memory addresses. All the ones
+ we accept have equal cost. */
+ *total = COSTS_N_INSNS (0);
+ return true;
+ }
+
switch (code)
{
case CONST_INT:
@@ -9484,6 +9933,10 @@ frv_rtx_costs (rtx x,
*total = COSTS_N_INSNS (18);
return true;
+ case MEM:
+ *total = COSTS_N_INSNS (3);
+ return true;
+
default:
return false;
}
@@ -9494,6 +9947,12 @@ frv_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
ctors_section ();
assemble_align (POINTER_SIZE);
+ if (TARGET_FDPIC)
+ {
+ if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
+ abort ();
+ return;
+ }
assemble_integer_with_op ("\t.picptr\t", symbol);
}
@@ -9502,6 +9961,12 @@ frv_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
{
dtors_section ();
assemble_align (POINTER_SIZE);
+ if (TARGET_FDPIC)
+ {
+ if (!frv_assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, 1))
+ abort ();
+ return;
+ }
assemble_integer_with_op ("\t.picptr\t", symbol);
}
diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h
index 021740c..cfcab0e 100644
--- a/gcc/config/frv/frv.h
+++ b/gcc/config/frv/frv.h
@@ -62,6 +62,32 @@
Defined in svr4.h. */
#undef WORD_SWITCH_TAKES_ARG
+/* -fpic and -fPIC used to imply the -mlibrary-pic multilib, but with
+ FDPIC which multilib to use depends on whether FDPIC is in use or
+ not. The trick we use is to introduce -multilib-library-pic as a
+ pseudo-flag that selects the library-pic multilib, and map fpic
+ and fPIC to it only if fdpic is not selected. Also, if fdpic is
+ selected and no PIC/PIE options are present, we imply -fPIE.
+ Otherwise, if -fpic or -fPIC are enabled and we're optimizing for
+ speed, or if we have -On with n>=3, enable inlining of PLTs. As
+ for -mgprel-ro, we want to enable it by default, but not for -fpic or
+ -fpie. */
+
+#define DRIVER_SELF_SPECS SUBTARGET_DRIVER_SELF_SPECS \
+"%{mno-pack:\
+ %{!mhard-float:-msoft-float}\
+ %{!mmedia:-mno-media}}\
+ %{!mfdpic:%{fpic|fPIC: -multilib-library-pic}}\
+ %{mfdpic:%{!fpic:%{!fpie:%{!fPIC:%{!fPIE:\
+ %{!fno-pic:%{!fno-pie:%{!fno-PIC:%{!fno-PIE:-fPIE}}}}}}}} \
+ %{!mno-inline-plt:%{O*:%{!O0:%{!Os:%{fpic|fPIC:-minline-plt} \
+ %{!fpic:%{!fPIC:%{!O:%{!O1:%{!O2:-minline-plt}}}}}}}}} \
+ %{!mno-gprel-ro:%{!fpic:%{!fpie:-mgprel-ro}}}} \
+"
+#ifndef SUBTARGET_DRIVER_SELF_SPECS
+# define SUBTARGET_DRIVER_SELF_SPECS
+#endif
+
/* A C string constant that tells the GCC driver program options to pass to
the assembler. It can also specify how to translate options you give to GNU
CC into options for GCC to pass to the assembler. See the file `sun3.h'
@@ -83,6 +109,7 @@
%{mmedia} %{mno-media} \
%{mmuladd} %{mno-muladd} \
%{mpack} %{mno-pack} \
+ %{mfdpic} \
%{fpic|fpie: -mpic} %{fPIC|fPIE: -mPIC} %{mlibrary-pic}}"
/* Another C string constant used much like `LINK_SPEC'. The difference
@@ -222,6 +249,7 @@
#define LINK_SPEC "\
%{h*} %{v:-V} \
%{b} %{Wl,*:%*} \
+%{mfdpic:-melf32frvfd -z text} \
%{static:-dn -Bstatic} \
%{shared:-Bdynamic} \
%{symbolic:-Bsymbolic} \
@@ -282,6 +310,9 @@
{ \
builtin_define ("__frv__"); \
builtin_assert ("machine=frv"); \
+ \
+ if (TARGET_FDPIC) \
+ builtin_define ("__FRV_FDPIC__"); \
} \
while (0)
@@ -317,6 +348,7 @@ extern int target_flags;
#define MASK_LIBPIC 0x00000100 /* -fpic that can be linked w/o pic */
#define MASK_ACC_4 0x00000200 /* Only use four media accumulators */
#define MASK_PACK 0x00000400 /* Set to enable packed output */
+#define MASK_LINKED_FP 0x00002000 /* Follow ABI linkage requirements. */
/* put debug masks up high */
#define MASK_DEBUG_ARG 0x40000000 /* debug argument handling */
@@ -331,6 +363,9 @@ extern int target_flags;
#define MASK_NO_VLIW_BRANCH 0x00200000 /* disable repacking branches */
#define MASK_NO_MULTI_CE 0x00100000 /* disable multi-level cond exec */
#define MASK_NO_NESTED_CE 0x00080000 /* disable nested cond exec */
+#define MASK_FDPIC 0x00040000 /* Follow the new uClinux ABI. */
+#define MASK_INLINE_PLT 0x00020000 /* Inline FDPIC PLTs. */
+#define MASK_GPREL_RO 0x00010000 /* Use GPREL for read-only data. */
#define MASK_DEFAULT MASK_DEFAULT_ALLOC_CC
@@ -356,7 +391,11 @@ extern int target_flags;
#define TARGET_NO_VLIW_BRANCH ((target_flags & MASK_NO_VLIW_BRANCH) != 0)
#define TARGET_NO_MULTI_CE ((target_flags & MASK_NO_MULTI_CE) != 0)
#define TARGET_NO_NESTED_CE ((target_flags & MASK_NO_NESTED_CE) != 0)
+#define TARGET_FDPIC ((target_flags & MASK_FDPIC) != 0)
+#define TARGET_INLINE_PLT ((target_flags & MASK_INLINE_PLT) != 0)
+#define TARGET_GPREL_RO ((target_flags & MASK_GPREL_RO) != 0)
#define TARGET_PACK ((target_flags & MASK_PACK) != 0)
+#define TARGET_LINKED_FP ((target_flags & MASK_LINKED_FP) != 0)
#define TARGET_GPR_64 (! TARGET_GPR_32)
#define TARGET_FPR_64 (! TARGET_FPR_32)
@@ -436,6 +475,7 @@ extern int target_flags;
{ "no-media", -MASK_MEDIA, "Do not use media insns" }, \
{ "muladd", MASK_MULADD, "Use multiply add/subtract instructions" }, \
{ "no-muladd", -MASK_MULADD, "Do not use multiply add/subtract insns" }, \
+ { "ultilib-library-pic", 0, "Link with the library-pic libraries" }, \
{ "library-pic", MASK_LIBPIC, "PIC support for building libraries" }, \
{ "acc-4", MASK_ACC_4, "Use 4 media accumulators" }, \
{ "acc-8", -MASK_ACC_4, "Use 8 media accumulators" }, \
@@ -460,6 +500,14 @@ extern int target_flags;
{ "no-multi-cond-exec", MASK_NO_MULTI_CE, "Enable optimizing &&/|| in conditional execution" }, \
{ "nested-cond-exec", -MASK_NO_NESTED_CE, "Enable nested conditional execution optimizations" }, \
{ "no-nested-cond-exec" ,MASK_NO_NESTED_CE, "Disable nested conditional execution optimizations" }, \
+ { "linked-fp", MASK_LINKED_FP, "Follow the EABI linkage requirements" }, \
+ { "no-linked-fp", -MASK_LINKED_FP, "Don't follow the EABI linkage requirements" }, \
+ { "fdpic", MASK_FDPIC, "Enable file descriptor PIC mode" }, \
+ { "no-fdpic", -MASK_FDPIC, "Disable file descriptor PIC mode" }, \
+ { "inline-plt", MASK_INLINE_PLT, "Enable inlining of PLT in function calls" }, \
+ { "no-inline-plt", -MASK_INLINE_PLT, "Disable inlining of PLT in function calls" }, \
+ { "gprel-ro", MASK_GPREL_RO, "Enable use of GPREL for read-only data in FDPIC" }, \
+ { "no-gprel-ro", -MASK_GPREL_RO, "Disable use of GPREL for read-only data in FDPIC" }, \
{ "tomcat-stats", 0, "Cause gas to print tomcat statistics" }, \
{ "", MASK_DEFAULT, "" }} \
@@ -764,8 +812,12 @@ extern int target_flags;
#define GPR_FP (GPR_FIRST + 2) /* Frame pointer */
#define GPR_SP (GPR_FIRST + 1) /* Stack pointer */
/* small data register */
-#define SDA_BASE_REG ((unsigned)(flag_pic ? PIC_REGNO : (GPR_FIRST+16)))
-#define PIC_REGNO (GPR_FIRST + 17) /* PIC register */
+#define SDA_BASE_REG ((unsigned)(TARGET_FDPIC ? -1 : flag_pic ? PIC_REGNO : (GPR_FIRST + 16)))
+#define PIC_REGNO (GPR_FIRST + (TARGET_FDPIC?15:17)) /* PIC register. */
+#define FDPIC_FPTR_REGNO (GPR_FIRST + 14) /* uClinux PIC function pointer register. */
+#define FDPIC_REGNO (GPR_FIRST + 15) /* uClinux PIC register. */
+
+#define OUR_FDPIC_REG get_hard_reg_initial_val (SImode, FDPIC_REGNO)
#define FPR_FIRST 64 /* First FP reg */
#define FPR_LAST 127 /* Last FP reg */
@@ -1213,6 +1265,9 @@ enum reg_class
CR_REGS,
LCR_REG,
LR_REG,
+ FDPIC_REGS,
+ FDPIC_FPTR_REGS,
+ FDPIC_CALL_REGS,
SPR_REGS,
QUAD_ACC_REGS,
EVEN_ACC_REGS,
@@ -1247,6 +1302,9 @@ enum reg_class
"CR_REGS", \
"LCR_REG", \
"LR_REG", \
+ "FDPIC_REGS", \
+ "FDPIC_FPTR_REGS", \
+ "FDPIC_CALL_REGS", \
"SPR_REGS", \
"QUAD_ACC_REGS", \
"EVEN_ACC_REGS", \
@@ -1282,6 +1340,9 @@ enum reg_class
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x0000ff00,0x0}, /* CR_REGS */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x4}, /* LCR_REGS */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x2}, /* LR_REGS */\
+ { 0x00008000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* FDPIC_REGS */\
+ { 0x00004000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* FDPIC_FPTR_REGS */\
+ { 0x0000c000,0x00000000,0x00000000,0x00000000,0x00000000,0x0}, /* FDPIC_CALL_REGS */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x6}, /* SPR_REGS */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* QUAD_ACC */\
{ 0x00000000,0x00000000,0x00000000,0x00000000,0x00ff0000,0x0}, /* EVEN_ACC */\
@@ -1490,9 +1551,9 @@ extern enum reg_class reg_class_from_letter[];
input and `r' on the output. The next alternative specifies `m' on the
input and a register class that does not include r0 on the output. */
-/* Small data references */
+/* 12-bit relocations. */
#define EXTRA_CONSTRAINT_FOR_Q(VALUE) \
- (small_data_symbolic_operand (VALUE, GET_MODE (VALUE)))
+ (got12_operand (VALUE, GET_MODE (VALUE)))
/* Double word memory ops that take one instruction. */
#define EXTRA_CONSTRAINT_FOR_R(VALUE) \
@@ -2102,7 +2163,7 @@ struct machine_function GTY(())
If you don't define this macro, the value of `BIGGEST_ALIGNMENT' is used for
aligning trampolines. */
-#define TRAMPOLINE_ALIGNMENT 32
+#define TRAMPOLINE_ALIGNMENT (TARGET_FDPIC ? 64 : 32)
/* A C statement to initialize the variable parts of a trampoline. ADDR is an
RTX for the address of the trampoline; FNADDR is an RTX for the address of
@@ -2129,8 +2190,11 @@ struct machine_function GTY(())
#define TRAMPOLINE_TEMPLATE_NAME "__trampoline_template"
#endif
+#define Twrite _write
+
+#if ! __FRV_FDPIC__
#define TRANSFER_FROM_TRAMPOLINE \
-extern int _write (int, const void *, unsigned); \
+extern int Twrite (int, const void *, unsigned); \
\
void \
__trampoline_setup (short * addr, int size, int fnaddr, int sc) \
@@ -2142,7 +2206,7 @@ __trampoline_setup (short * addr, int size, int fnaddr, int sc) \
\
if (size < 20) \
{ \
- _write (2, "__trampoline_setup bad size\n", \
+ Twrite (2, "__trampoline_setup bad size\n", \
sizeof ("__trampoline_setup bad size\n") - 1); \
exit (-1); \
} \
@@ -2171,6 +2235,67 @@ __asm__("\n" \
"\tsethi #0, gr6\n" \
"\tsethi #0, gr7\n" \
"\tjmpl @(gr0,gr6)\n");
+#else
+#define TRANSFER_FROM_TRAMPOLINE \
+extern int Twrite (int, const void *, unsigned); \
+ \
+void \
+__trampoline_setup (addr, size, fnaddr, sc) \
+ short * addr; \
+ int size; \
+ int fnaddr; \
+ int sc; \
+{ \
+ extern short __trampoline_template[]; \
+ short * from = &__trampoline_template[0]; \
+ int i; \
+ short **desc = (short **)addr; \
+ short * to = addr + 4; \
+ \
+ if (size != 32) \
+ { \
+ Twrite (2, "__trampoline_setup bad size\n", \
+ sizeof ("__trampoline_setup bad size\n") - 1); \
+ exit (-1); \
+ } \
+ \
+ /* Create a function descriptor with the address of the code below
+ and NULL as the FDPIC value. We don't need the real GOT value
+ here, since we don't use it, so we use NULL, that is just as
+ good. */ \
+ desc[0] = to; \
+ desc[1] = NULL; \
+ size -= 8; \
+ \
+ to[0] = from[0]; \
+ to[1] = (short)(fnaddr); \
+ to[2] = from[2]; \
+ to[3] = (short)(sc); \
+ to[4] = from[4]; \
+ to[5] = (short)(fnaddr >> 16); \
+ to[6] = from[6]; \
+ to[7] = (short)(sc >> 16); \
+ to[8] = from[8]; \
+ to[9] = from[9]; \
+ to[10] = from[10]; \
+ to[11] = from[11]; \
+ \
+ for (i = 0; i < size; i++) \
+ __asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (to), "r" (i)); \
+} \
+ \
+__asm__("\n" \
+ "\t.globl " TRAMPOLINE_TEMPLATE_NAME "\n" \
+ "\t.text\n" \
+ TRAMPOLINE_TEMPLATE_NAME ":\n" \
+ "\tsetlos #0, gr6\n" /* Jump register. */ \
+ "\tsetlos #0, gr7\n" /* Static chain. */ \
+ "\tsethi #0, gr6\n" \
+ "\tsethi #0, gr7\n" \
+ "\tldd @(gr6,gr0),gr14\n" \
+ "\tjmpl @(gr14,gr0)\n" \
+ );
+#endif
/* Addressing Modes. */
@@ -2255,7 +2380,8 @@ __asm__("\n" \
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \
do \
{ \
- if (frv_legitimate_address_p (MODE, X, REG_OK_STRICT_P, FALSE)) \
+ if (frv_legitimate_address_p (MODE, X, REG_OK_STRICT_P, \
+ FALSE, FALSE)) \
goto LABEL; \
} \
while (0)
@@ -2284,40 +2410,9 @@ __asm__("\n" \
will reload one or both registers only if neither labeling works. */
#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
-/* A C compound statement that attempts to replace X with a valid memory
- address for an operand of mode MODE. WIN will be a C statement label
- elsewhere in the code; the macro definition may use
-
- GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN);
-
- to avoid further processing if the address has become legitimate.
-
- X will always be the result of a call to `break_out_memory_refs', and OLDX
- will be the operand that was given to that function to produce X.
-
- The code generated by this macro should not alter the substructure of X. If
- it transforms X into a more legitimate form, it should assign X (which will
- always be a C variable) a new value.
-
- It is not necessary for this macro to come up with a legitimate address.
- The compiler has standard ways of doing so in all cases. In fact, it is
- safe for this macro to do nothing. But often a machine-dependent strategy
- can generate better code. */
-
-/* On the FRV, we use it to convert small data and pic references into using
- the appropriate pointer in the address. */
-#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
- do \
- { \
- rtx newx = frv_legitimize_address (X, OLDX, MODE); \
- \
- if (newx) \
- { \
- (X) = newx; \
- goto WIN; \
- } \
- } \
- while (0)
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)
+
+#define FIND_BASE_TERM frv_find_base_term
/* A C statement or compound statement with a conditional `goto LABEL;'
executed if memory address X (an RTX) can have different meanings depending
@@ -2546,6 +2641,7 @@ fixup_section (void) \
( GET_CODE (X) == CONST_INT \
|| GET_CODE (X) == CONST_DOUBLE \
|| (GET_CODE (X) == HIGH && GET_CODE (XEXP (X, 0)) == CONST_INT) \
+ || got12_operand (X, VOIDmode) \
|| GET_CODE (X) == CONSTANT_P_RTX)
@@ -2996,10 +3092,11 @@ do { \
{ "int12_operand", { CONST_INT }}, \
{ "int_2word_operand", { CONST_INT, CONST_DOUBLE, \
SYMBOL_REF, LABEL_REF, CONST }}, \
- { "pic_register_operand", { REG }}, \
- { "pic_symbolic_operand", { SYMBOL_REF, LABEL_REF, CONST }}, \
- { "small_data_register_operand", { REG }}, \
- { "small_data_symbolic_operand", { SYMBOL_REF, CONST }}, \
+ { "fdpic_operand", { REG }}, \
+ { "fdpic_fptr_operand", { REG }}, \
+ { "ldd_address_operand", { REG, SUBREG, PLUS }}, \
+ { "got12_operand", { CONST }}, \
+ { "const_unspec_operand", { CONST }}, \
{ "icc_operand", { REG }}, \
{ "fcc_operand", { REG }}, \
{ "cc_operand", { REG }}, \
@@ -3302,4 +3399,9 @@ enum frv_builtins
extern GTY(()) rtx frv_compare_op0; /* operand save for */
extern GTY(()) rtx frv_compare_op1; /* comparison generation */
+#ifdef __FRV_FDPIC__
+#define CRT_GET_RFIB_DATA(dbase) \
+ ({ extern void *_GLOBAL_OFFSET_TABLE_; (dbase) = &_GLOBAL_OFFSET_TABLE_; })
+#endif
+
#endif /* __FRV_H__ */
diff --git a/gcc/config/frv/frv.md b/gcc/config/frv/frv.md
index a5fae61..ef2b49d 100644
--- a/gcc/config/frv/frv.md
+++ b/gcc/config/frv/frv.md
@@ -1,5 +1,5 @@
;; Frv Machine Description
-;; Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
;; Contributed by Red Hat, Inc.
;; This file is part of GCC.
@@ -28,6 +28,8 @@
;; ::
;; ::::::::::::::::::::
+;; GOT constants must go 12/HI/LO for the splitter to work
+
(define_constants
[(UNSPEC_BLOCKAGE 0)
(UNSPEC_CC_TO_GPR 1)
@@ -35,7 +37,30 @@
(UNSPEC_PIC_PROLOGUE 3)
(UNSPEC_CR_LOGIC 4)
(UNSPEC_STACK_ADJUST 5)
- (UNSPEC_EH_RETURN_EPILOGUE 6)])
+ (UNSPEC_EH_RETURN_EPILOGUE 6)
+ (UNSPEC_GOT 7)
+ (UNSPEC_LDD 8)
+
+ (R_FRV_GOT12 11)
+ (R_FRV_GOTHI 12)
+ (R_FRV_GOTLO 13)
+ (R_FRV_FUNCDESC 14)
+ (R_FRV_FUNCDESC_GOT12 15)
+ (R_FRV_FUNCDESC_GOTHI 16)
+ (R_FRV_FUNCDESC_GOTLO 17)
+ (R_FRV_FUNCDESC_VALUE 18)
+ (R_FRV_FUNCDESC_GOTOFF12 19)
+ (R_FRV_FUNCDESC_GOTOFFHI 20)
+ (R_FRV_FUNCDESC_GOTOFFLO 21)
+ (R_FRV_GOTOFF12 22)
+ (R_FRV_GOTOFFHI 23)
+ (R_FRV_GOTOFFLO 24)
+ (R_FRV_GPREL12 25)
+ (R_FRV_GPRELHI 26)
+ (R_FRV_GPRELLO 27)
+
+ (FDPIC_REG 15)
+ ])
@@ -1317,7 +1342,7 @@
(define_insn "*movhi_internal"
[(set (match_operand:HI 0 "move_destination_operand" "=d,d,d,m,m,?f,?f,?d,?m,f")
- (match_operand:HI 1 "move_source_operand" "L,i,d,d,O, d, f, f, f,GO"))]
+ (match_operand:HI 1 "move_source_operand" "L,n,d,d,O, d, f, f, f,GO"))]
"register_operand(operands[0], HImode) || reg_or_0_operand (operands[1], HImode)"
"* return output_move_single (operands, insn);"
[(set_attr "length" "4,8,4,4,4,4,4,4,4,4")
@@ -1385,86 +1410,69 @@
[(set_attr "length" "4")
(set_attr "type" "gload,fload")])
-(define_insn "*movsi_internal"
- [(set (match_operand:SI 0 "move_destination_operand" "=d,d,d,m,m,z,d,d,f,f,m,?f,?z")
- (match_operand:SI 1 "move_source_operand" "LQ,i,d,d,O,d,z,f,d,f,f,GO,GO"))]
- "register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode)"
- "* return output_move_single (operands, insn);"
- [(set_attr "length" "4,8,4,4,4,4,4,4,4,4,4,4,4")
- (set_attr "type" "int,multi,int,gstore,gstore,spr,spr,movfg,movgf,fsconv,fstore,movgf,spr")])
-
-(define_insn "*movsi_lda_sdata"
+(define_insn "*movsi_got"
[(set (match_operand:SI 0 "integer_register_operand" "=d")
- (plus:SI (match_operand:SI 1 "small_data_register_operand" "d")
- (match_operand:SI 2 "small_data_symbolic_operand" "Q")))]
+ (match_operand:SI 1 "got12_operand" ""))]
""
- "addi %1, #gprel12(%2), %0"
+ "addi gr0, %1, %0"
[(set_attr "type" "int")
(set_attr "length" "4")])
-;; Split 2 word load of constants into sethi/setlo instructions
-(define_split
- [(set (match_operand:SI 0 "integer_register_operand" "")
- (match_operand:SI 1 "int_2word_operand" ""))]
- "reload_completed"
- [(set (match_dup 0)
- (high:SI (match_dup 1)))
- (set (match_dup 0)
- (lo_sum:SI (match_dup 0)
- (match_dup 1)))]
- "")
-
-(define_insn "movsi_high"
+(define_insn "*movsi_high_got"
[(set (match_operand:SI 0 "integer_register_operand" "=d")
- (high:SI (match_operand:SI 1 "int_2word_operand" "i")))]
+ (high:SI (match_operand:SI 1 "const_unspec_operand" "")))]
""
- "sethi #hi(%1), %0"
+ "sethi %1, %0"
[(set_attr "type" "sethi")
(set_attr "length" "4")])
-(define_insn "movsi_lo_sum"
- [(set (match_operand:SI 0 "integer_register_operand" "+d")
- (lo_sum:SI (match_dup 0)
- (match_operand:SI 1 "int_2word_operand" "i")))]
+(define_insn "*movsi_lo_sum_got"
+ [(set (match_operand:SI 0 "integer_register_operand" "=d")
+ (lo_sum:SI (match_operand:SI 1 "integer_register_operand" "0")
+ (match_operand:SI 2 "const_unspec_operand" "")))]
""
- "setlo #lo(%1), %0"
+ "setlo %2, %0"
[(set_attr "type" "setlo")
(set_attr "length" "4")])
-;; Split loads of addresses with PIC specified into 3 separate instructions
-(define_insn_and_split "*movsi_pic"
+(define_insn "*movsi_internal"
+ [(set (match_operand:SI 0 "move_destination_operand" "=d,d,d,m,m,z,d,d,f,f,m,?f,?z")
+ (match_operand:SI 1 "move_source_operand" "L,n,d,d,O,d,z,f,d,f,f,GO,GO"))]
+ "register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode)"
+ "* return output_move_single (operands, insn);"
+ [(set_attr "length" "4,8,4,4,4,4,4,4,4,4,4,4,4")
+ (set_attr "type" "int,multi,int,gstore,gstore,spr,spr,movfg,movgf,fsconv,fstore,movgf,spr")])
+
+;; Split 2 word load of constants into sethi/setlo instructions
+(define_insn_and_split "*movsi_2word"
[(set (match_operand:SI 0 "integer_register_operand" "=d")
- (plus:SI (match_operand:SI 1 "pic_register_operand" "d")
- (match_operand:SI 2 "pic_symbolic_operand" "")))]
+ (match_operand:SI 1 "int_2word_operand" "i"))]
""
"#"
"reload_completed"
[(set (match_dup 0)
- (high:SI (match_dup 2)))
+ (high:SI (match_dup 1)))
(set (match_dup 0)
(lo_sum:SI (match_dup 0)
- (match_dup 2)))
- (set (match_dup 0)
- (plus:SI (match_dup 0) (match_dup 1)))]
-
+ (match_dup 1)))]
""
- [(set_attr "type" "multi")
- (set_attr "length" "12")])
+ [(set_attr "length" "8")
+ (set_attr "type" "multi")])
-(define_insn "movsi_high_pic"
+(define_insn "movsi_high"
[(set (match_operand:SI 0 "integer_register_operand" "=d")
- (high:SI (match_operand:SI 1 "pic_symbolic_operand" "")))]
+ (high:SI (match_operand:SI 1 "int_2word_operand" "i")))]
""
- "sethi #gprelhi(%1), %0"
+ "sethi #hi(%1), %0"
[(set_attr "type" "sethi")
(set_attr "length" "4")])
-(define_insn "movsi_lo_sum_pic"
+(define_insn "movsi_lo_sum"
[(set (match_operand:SI 0 "integer_register_operand" "+d")
(lo_sum:SI (match_dup 0)
- (match_operand:SI 1 "pic_symbolic_operand" "")))]
+ (match_operand:SI 1 "int_2word_operand" "i")))]
""
- "setlo #gprello(%1), %0"
+ "setlo #lo(%1), %0"
[(set_attr "type" "setlo")
(set_attr "length" "4")])
@@ -1692,14 +1700,14 @@
}")
(define_insn "*movdf_double"
- [(set (match_operand:DF 0 "move_destination_operand" "=h,?e,??f,??d,R,?R,??m,??m,h,?e,??f,??d,?h,??f,?e,??d,R,m,h,??f,e,??d")
- (match_operand:DF 1 "move_source_operand" " h,e,f,d,h,e,f,d,R,R,m,m,e,d,h,f,GO,GO,GO,GO,GO,GO"))]
+ [(set (match_operand:DF 0 "move_destination_operand" "=h,?e,??f,??d,R,?R,??m,??m,h,?e,??f,??d,?h,??f,?e,??d,R,m,h,??f,e,??d,e,??d")
+ (match_operand:DF 1 "move_source_operand" " h,e,f,d,h,e,f,d,R,R,m,m,e,d,h,f,GO,GO,GO,GO,GO,GO,F,F"))]
"TARGET_DOUBLE
&& (register_operand (operands[0], DFmode)
|| reg_or_0_operand (operands[1], DFmode))"
"* return output_move_double (operands, insn);"
- [(set_attr "length" "4,8,8,8,4,4,8,8,4,4,8,8,4,8,4,8,4,8,8,8,8,8")
- (set_attr "type" "fdconv,multi,multi,multi,fstore,gstore,fstore,gstore,fload,gload,fload,gload,movgf,movgf,movfg,movfg,gstore,gstore,movgf,movgf,multi,multi")])
+ [(set_attr "length" "4,8,8,8,4,4,8,8,4,4,8,8,4,8,4,8,4,8,8,8,8,8,16,16")
+ (set_attr "type" "fdconv,multi,multi,multi,fstore,gstore,fstore,gstore,fload,gload,fload,gload,movgf,movgf,movfg,movfg,gstore,gstore,movgf,movgf,multi,multi,multi,multi")])
;; If we don't support the double instructions, prefer gprs over fprs, since it
;; will all be emulated
@@ -2565,7 +2573,7 @@
(define_insn "addsi3"
[(set (match_operand:SI 0 "integer_register_operand" "=d")
(plus:SI (match_operand:SI 1 "integer_register_operand" "%d")
- (match_operand:SI 2 "gpr_or_int12_operand" "dNOP")))]
+ (match_operand:SI 2 "gpr_or_int12_operand" "dNOPQ")))]
""
"add%I2 %1,%2,%0"
[(set_attr "length" "4")
@@ -5251,7 +5259,11 @@
if (! operands[2])
operands[2] = const0_rtx;
- emit_call_insn (gen_call_internal (addr, operands[1], operands[2], lr));
+ if (TARGET_FDPIC)
+ frv_expand_fdpic_call (operands, 0);
+ else
+ emit_call_insn (gen_call_internal (addr, operands[1], operands[2], lr));
+
DONE;
}")
@@ -5260,7 +5272,53 @@
(match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(clobber (match_operand:SI 3 "lr_operand" "=l,l"))]
+ "! TARGET_FDPIC"
+ "@
+ call %0
+ call%i0l %M0"
+ [(set_attr "length" "4")
+ (set_attr "type" "call,jumpl")])
+
+;; The odd use of GR0 within the UNSPEC below prevents cseing or
+;; hoisting function descriptor loads out of loops. This is almost
+;; never desirable, since if we preserve the function descriptor in a
+;; pair of registers, it takes two insns to move it to gr14/gr15, and
+;; if it's in the stack, we just waste space with the store, since
+;; we'll have to load back from memory anyway. And, in the worst
+;; case, we may end up reusing a function descriptor still pointing at
+;; a PLT entry, instead of to the resolved function, which means going
+;; through the resolver for every call that uses the outdated value.
+;; Bad!
+
+;; The explicit MEM inside the SPEC prevents the compiler from moving
+;; the load before a branch after a NULL test, or before a store that
+;; initializes a function descriptor.
+
+(define_insn "movdi_ldd"
+ [(set (match_operand:DI 0 "fdpic_fptr_operand" "=e")
+ (unspec:DI [(mem:DI (match_operand:SI 1 "ldd_address_operand" "p"))
+ (reg:SI 0)] UNSPEC_LDD))]
""
+ "ldd%I1 %M1, %0"
+ [(set_attr "length" "4")
+ (set_attr "type" "gload")])
+
+(define_insn "call_fdpicdi"
+ [(call (mem:QI (match_operand:DI 0 "fdpic_fptr_operand" "W"))
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "lr_operand" "=l"))]
+ "TARGET_FDPIC"
+ "calll %M0"
+ [(set_attr "length" "4")
+ (set_attr "type" "jumpl")])
+
+(define_insn "call_fdpicsi"
+ [(call (mem:QI (match_operand:SI 0 "call_operand" "S,dNOP"))
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand:SI 3 "fdpic_operand" "Z,Z"))
+ (clobber (match_operand:SI 4 "lr_operand" "=l,l"))]
+ "TARGET_FDPIC"
"@
call %0
call%i0l %M0"
@@ -5296,8 +5354,12 @@
if (! operands[3])
operands[3] = const0_rtx;
- emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
- operands[3], lr));
+ if (TARGET_FDPIC)
+ frv_expand_fdpic_call (operands, 1);
+ else
+ emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2],
+ operands[3], lr));
+
DONE;
}")
@@ -5307,7 +5369,31 @@
(match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(clobber (match_operand:SI 4 "lr_operand" "=l,l"))]
- ""
+ "! TARGET_FDPIC"
+ "@
+ call %1
+ call%i1l %M1"
+ [(set_attr "length" "4")
+ (set_attr "type" "call,jumpl")])
+
+(define_insn "call_value_fdpicdi"
+ [(set (match_operand 0 "register_operand" "=d")
+ (call (mem:QI (match_operand:DI 1 "fdpic_fptr_operand" "W"))
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "lr_operand" "=l"))]
+ "TARGET_FDPIC"
+ "calll %M1"
+ [(set_attr "length" "4")
+ (set_attr "type" "jumpl")])
+
+(define_insn "call_value_fdpicsi"
+ [(set (match_operand 0 "register_operand" "=d,d")
+ (call (mem:QI (match_operand:SI 1 "call_operand" "S,dNOP"))
+ (match_operand 2 "" "")))
+ (use (match_operand 3 "" ""))
+ (use (match_operand:SI 4 "fdpic_operand" "Z,Z"))
+ (clobber (match_operand:SI 5 "lr_operand" "=l,l"))]
+ "TARGET_FDPIC"
"@
call %1
call%i1l %M1"
@@ -7453,3 +7539,174 @@
"mhdseth %2, %0"
[(set_attr "length" "4")
(set_attr "type" "mset")])
+
+;;-----------------------------------------------------------------------------
+
+(define_expand "symGOT2reg"
+ [(match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" "")
+ (match_operand:SI 2 "" "")
+ (match_operand:SI 3 "" "")]
+ ""
+ "
+{
+ rtx insn;
+
+ insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1], operands[2], operands[3]));
+
+ RTX_UNCHANGING_P (SET_SRC (PATTERN (insn))) = 1;
+
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+ REG_NOTES (insn));
+
+ DONE;
+}")
+
+(define_expand "symGOT2reg_i"
+ [(set (match_operand:SI 0 "" "")
+ (mem:SI (plus:SI (match_operand:SI 2 "" "")
+ (const:SI (unspec:SI [(match_operand:SI 1 "" "")
+ (match_operand:SI 3 "" "")]
+ UNSPEC_GOT)))))]
+ ""
+ "")
+
+(define_expand "symGOT2reg_hilo"
+ [(set (match_dup 6)
+ (high:SI (const:SI (unspec:SI [(match_operand:SI 1 "" "")
+ (match_dup 4)] UNSPEC_GOT))))
+ (set (match_dup 5)
+ (lo_sum:SI (match_dup 6)
+ (const:SI (unspec:SI [(match_dup 1)
+ (match_operand:SI 3 "" "")]
+ UNSPEC_GOT))))
+ (set (match_operand:SI 0 "" "")
+ (mem:SI (plus:SI (match_dup 5)
+ (match_operand:SI 2 "" ""))))
+ ]
+ ""
+ "
+{
+ if (no_new_pseudos)
+ operands[6] = operands[5] = operands[0];
+ else
+ {
+ operands[6] = gen_reg_rtx (SImode);
+ operands[5] = gen_reg_rtx (SImode);
+ }
+
+ operands[4] = GEN_INT (INTVAL (operands[3]) + 1);
+ operands[3] = GEN_INT (INTVAL (operands[3]) + 2);
+}")
+
+(define_expand "symGOTOFF2reg_hilo"
+ [(set (match_dup 6)
+ (high:SI (const:SI (unspec:SI [(match_operand:SI 1 "" "")
+ (match_dup 4)] UNSPEC_GOT))))
+ (set (match_dup 5)
+ (lo_sum:SI (match_dup 6)
+ (const:SI (unspec:SI [(match_dup 1)
+ (match_operand:SI 3 "" "")]
+ UNSPEC_GOT))))
+ (set (match_operand:SI 0 "" "")
+ (plus:SI (match_dup 5)
+ (match_operand:SI 2 "" "")))
+ ]
+ ""
+ "
+{
+ if (no_new_pseudos)
+ operands[6] = operands[5] = operands[0];
+ else
+ {
+ operands[6] = gen_reg_rtx (SImode);
+ operands[5] = gen_reg_rtx (SImode);
+ }
+
+ operands[4] = GEN_INT (INTVAL (operands[3]) + 1);
+ operands[3] = GEN_INT (INTVAL (operands[3]) + 2);
+}")
+
+(define_expand "symGOTOFF2reg"
+ [(match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" "")
+ (match_operand:SI 2 "" "")
+ (match_operand:SI 3 "" "")]
+ ""
+ "
+{
+ rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1], operands[2], operands[3]));
+
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+ REG_NOTES (insn));
+
+ DONE;
+}")
+
+(define_expand "symGOTOFF2reg_i"
+ [(set (match_operand:SI 0 "" "")
+ (plus:SI (match_operand:SI 2 "" "")
+ (const:SI
+ (unspec:SI [(match_operand:SI 1 "" "")
+ (match_operand:SI 3 "" "")]
+ UNSPEC_GOT))))]
+ ""
+ "")
+
+(define_expand "symGPREL2reg"
+ [(match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" "")
+ (match_operand:SI 2 "" "")
+ (match_operand:SI 3 "" "")
+ (match_dup 4)]
+ ""
+ "
+{
+ rtx insn;
+
+ if (no_new_pseudos)
+ operands[4] = operands[0];
+ else
+ operands[4] = gen_reg_rtx (SImode);
+
+ emit_insn (frv_gen_GPsym2reg (operands[4], operands[2]));
+
+ insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1],
+ operands[4], operands[3]));
+
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+ REG_NOTES (insn));
+
+ DONE;
+}")
+
+(define_expand "symGPREL2reg_hilo"
+ [(match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" "")
+ (match_operand:SI 2 "" "")
+ (match_operand:SI 3 "" "")
+ (match_dup 4)]
+ ""
+ "
+{
+ rtx insn;
+
+ if (no_new_pseudos)
+ {
+ emit_insn (gen_symGOT2reg (operands[0], operands[1], operands[2],
+ GEN_INT (R_FRV_GOT12)));
+ DONE;
+ }
+
+ operands[4] = gen_reg_rtx (SImode);
+
+ emit_insn (frv_gen_GPsym2reg (operands[4], operands[2]));
+
+ insn = emit_insn (gen_symGOTOFF2reg_hilo (operands[0], operands[1],
+ operands[4], operands[3]));
+
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+ REG_NOTES (insn));
+
+ DONE;
+}")
diff --git a/gcc/config/frv/frvbegin.c b/gcc/config/frv/frvbegin.c
index d021b35..f888a48 100644
--- a/gcc/config/frv/frvbegin.c
+++ b/gcc/config/frv/frvbegin.c
@@ -71,10 +71,13 @@ INIT_SECTION_NEG_ONE (".dtors", "\"aw\"", "__DTOR_LIST__");
INIT_SECTION (".eh_frame", "\"aw\"", "__EH_FRAME_BEGIN__");
+#if ! __FRV_FDPIC__
+/* In FDPIC, the linker itself generates this. */
/* Beginning of .rofixup section that provides a list of pointers that we
need to adjust. */
INIT_SECTION (".rofixup", "\"a\"", "__ROFIXUP_LIST__");
+#endif /* __FRV_FDPIC__ */
extern void __frv_register_eh(void) __attribute__((__constructor__));
extern void __frv_deregister_eh(void) __attribute__((__destructor__));
diff --git a/gcc/config/frv/frvend.c b/gcc/config/frv/frvend.c
index 6709cdb..f8080c6 100644
--- a/gcc/config/frv/frvend.c
+++ b/gcc/config/frv/frvend.c
@@ -64,7 +64,10 @@ FINI_SECTION_ZERO (".dtors", "\"aw\"", "__DTOR_END__");
FINI_SECTION_ZERO (".eh_frame", "\"aw\"", "__FRAME_END__");
+#if ! __FRV_FDPIC__
+/* In FDPIC, the linker itself generates this. */
/* End of .rofixup section that provides a list of pointers that we
need to adjust. */
FINI_SECTION (".rofixup", "\"a\"", "__ROFIXUP_END__");
+#endif /* __FRV_FDPIC__ */
diff --git a/gcc/config/frv/libgcc-frv.ver b/gcc/config/frv/libgcc-frv.ver
new file mode 100644
index 0000000..2aae3db
--- /dev/null
+++ b/gcc/config/frv/libgcc-frv.ver
@@ -0,0 +1,55 @@
+GCC_3.4 {
+ # frv abi symbol names
+ __ftod
+ __ftoi
+ __ftoui
+ __dtoi
+ __ftoui
+ __dtoui
+ __ftoll
+ __dtoll
+ __ftoull
+ __dtoull
+ __itof
+ __lltof
+ __dtof
+ __itod
+ __lltof
+ __lltod
+ __addd
+ __subd
+ __muld
+ __divd
+ __addf
+ __subf
+ __mulf
+ __divf
+ __sllll
+ __srlll
+ __srall
+ __addll
+ __subll
+ __mulll
+ __umulll
+ __divll
+ __udivll
+ __modll
+ __umodll
+ __cmpll
+ __cmpf
+ __cmpd
+ __andll
+ __orll
+ __xorll
+ __notll
+ __cmov
+ __cmovd
+ __cmovh
+ __cmovw
+ __modi
+ __uitod
+ __uitof
+ __ulltod
+ __ulltof
+ __umodi
+}
diff --git a/gcc/config/frv/linux.h b/gcc/config/frv/linux.h
new file mode 100644
index 0000000..6f0f1b2
--- /dev/null
+++ b/gcc/config/frv/linux.h
@@ -0,0 +1,74 @@
+/* Target macros for the FRV Linux port of GCC.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+ Contributed by Red Hat Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#ifndef __FRV_LINUX_H__
+#define __FRV_LINUX_H__
+
+#undef SUBTARGET_DRIVER_SELF_SPECS
+#define SUBTARGET_DRIVER_SELF_SPECS \
+ "%{!mno-fdpic:-mfdpic}",
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} \
+ crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+
+#undef LINK_SPEC
+#define LINK_SPEC "\
+ %{mfdpic: -m elf32frvfd -z text} %{shared} %{pie} \
+ %{!shared: %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}} \
+ %{static}}"
+
+/* Support for compile-time default CPU. */
+#define OPTION_DEFAULT_SPECS \
+ {"cpu", "%{!mcpu=*:-mcpu=%(VALUE)}" }
+
+/* Define OS-specific predefined preprocessor macros. */
+#define TARGET_OS_CPP_BUILTINS() \
+ do { \
+ builtin_define ("__gnu_linux__"); \
+ builtin_define_std ("linux"); \
+ builtin_define_std ("unix"); \
+ builtin_assert ("system=linux"); \
+ } while (0)
+
+#define HAS_INIT_SECTION 1
+#define INIT_SECTION_ASM_OP "\t.section .init,\"ax\""
+#define FINI_SECTION_ASM_OP "\t.section .fini,\"ax\""
+
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+asm (SECTION_OP); \
+asm ("ldi.p @(fp,4), gr15 ! call " #FUNC); \
+asm (TEXT_SECTION_ASM_OP);
+
+#undef INVOKE__main
+
+#undef Twrite
+#define Twrite __write
+
+#endif /* __FRV_LINUX_H__ */
diff --git a/gcc/config/frv/t-frv b/gcc/config/frv/t-frv
index a9130ff..37662b6 100644
--- a/gcc/config/frv/t-frv
+++ b/gcc/config/frv/t-frv
@@ -82,9 +82,9 @@ $(T)frvend$(objext): $(srcdir)/config/frv/frvend.c $(GCC_PASSES) \
#MULTILIB_EXCEPTIONS = *mcpu=simple/*msoft-float* *mcpu=frv/*msoft-float*
#MULTILIB_EXTRA_OPTS = mlibrary-pic
-MULTILIB_OPTIONS = mcpu=frv/mcpu=fr400/mcpu=simple mno-pack mlibrary-pic
-MULTILIB_DIRNAMES = frv fr400 simple unpacked pic
-MULTILIB_MATCHES = mcpu?simple=mcpu?fr300 mlibrary-pic=fpic mlibrary-pic=fPIC
+MULTILIB_OPTIONS = mcpu=frv/mcpu=fr400/mcpu=simple mno-pack mlibrary-pic/mfdpic
+MULTILIB_DIRNAMES = frv fr400 simple unpacked pic fdpic
+MULTILIB_MATCHES = mcpu?simple=mcpu?fr300 mlibrary-pic=multilib-library-pic
MULTILIB_EXCEPTIONS = mcpu=frv/mno-pack* mcpu=simple/mno-pack*
LIBGCC = stmp-multilib
diff --git a/gcc/config/frv/t-linux b/gcc/config/frv/t-linux
new file mode 100644
index 0000000..298f59b
--- /dev/null
+++ b/gcc/config/frv/t-linux
@@ -0,0 +1,12 @@
+# We don't want multilibs.
+MULTILIB_OPTIONS=
+MULTILIB_DIRNAMES=
+MULTILIB_MATCHES=
+MULTILIB_EXCEPTIONS=
+MULTILIB_EXTRA_OPTS=
+
+CRTSTUFF_T_CFLAGS = -fPIC
+TARGET_LIBGCC2_CFLAGS = -fPIC
+
+SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver \
+ $(srcdir)/config/frv/libgcc-frv.ver
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 2607e40..3fe6573 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -633,6 +633,7 @@ in the following sections.
-malloc-cc -mfixed-cc -mdword -mno-dword @gol
-mdouble -mno-double @gol
-mmedia -mno-media -mmuladd -mno-muladd @gol
+-mfdpic -minline-plt -mgprel-ro -multilib-library-pic -mlinked-fp @gol
-mlibrary-pic -macc-4 -macc-8 @gol
-mpack -mno-pack -mno-eflags -mcond-move -mno-cond-move @gol
-mscc -mno-scc -mcond-exec -mno-cond-exec @gol
@@ -8655,6 +8656,53 @@ configure option, gcc's program search path, and finally by the user's
@env{PATH}. The linker used by GCC can be printed using @samp{which
`gcc -print-prog-name=ld`}.
+@item -mfdpic
+@opindex mfdpic
+
+Select the FDPIC ABI, that uses function descriptors to represent
+pointers to functions. Without any PIC/PIE-related options, it
+implies @option{-fPIE}. With @option{-fpic} or @option{-fpie}, it
+assumes GOT entries and small data are within a 12-bit range from the
+GOT base address; with @option{-fPIC} or @option{-fPIE}, GOT offsets
+are computed with 32 bits.
+
+@item -minline-plt
+@opindex minline-plt
+
+Enable inlining of PLT entries in function calls to functions that are
+not known to bind locally. It has no effect without @option{-mfdpic}.
+It's enabled by default if optimizing for speed and compiling for
+shared libraries (i.e., @option{-fPIC} or @option{-fpic}), or when an
+optimization option such as @option{-O3} or above is present in the
+command line.
+
+@item -mgprel-ro
+@opindex mgprel-ro
+
+Enable the use of @code{GPREL} relocations in the FDPIC ABI for data
+that is known to be in read-only sections. It's enabled by default,
+except for @option{-fpic} or @option{-fpie}: even though it may help
+make the global offset table smaller, it trades 1 instruction for 4.
+With @option{-fPIC} or @option{-fPIE}, it trades 3 instructions for 4,
+one of which may be shared by multiple symbols, and it avoids the need
+for a GOT entry for the referenced symbol, so it's more likely to be a
+win. If it is not, @option{-mno-gprel-ro} can be used to disable it.
+
+@item -multilib-library-pic
+@opindex multilib-library-pic
+
+Link with the (library, not FD) pic libraries. It's implied by
+@option{-mlibrary-pic}, as well as by @option{-fPIC} and
+@option{-fpic} without @option{-mfdpic}. You should never have to use
+it explicitly.
+
+@item -mlinked-fp
+@opindex mlinked-fp
+
+Follow the EABI requirement of always creating a frame pointer whenever
+a stack frame is allocated. This option is enabled by default and can
+be disabled with @option{-mno-linked-fp}.
+
@item -mlong-calls
@opindex mno-long-calls
Generate code that uses long call sequences. This ensures that a call
@@ -10429,7 +10477,7 @@ Do not use multiply and add/subtract instructions.
@item -mlibrary-pic
@opindex mlibrary-pic
-Enable PIC support for building libraries
+Generate position-independent EABI code.
@item -macc-4
@opindex macc-4
diff --git a/gcc/reload.c b/gcc/reload.c
index b649a99..5ac5a81 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -105,6 +105,7 @@ a register with any other reload. */
#include "function.h"
#include "toplev.h"
#include "params.h"
+#include "target.h"
#ifndef REGNO_MODE_OK_FOR_BASE_P
#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
@@ -113,6 +114,12 @@ a register with any other reload. */
#ifndef REG_MODE_OK_FOR_BASE_P
#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
#endif
+
+/* True if X is a constant that can be forced into the constant pool. */
+#define CONST_POOL_OK_P(X) \
+ (CONSTANT_P (X) \
+ && GET_CODE (X) != HIGH \
+ && !targetm.cannot_force_const_mem (X))
/* All reloads of the current insn are recorded here. See reload.h for
comments. */
@@ -3114,9 +3121,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))
win = 1;
- if (CONSTANT_P (operand)
- /* force_const_mem does not accept HIGH. */
- && GET_CODE (operand) != HIGH)
+ if (CONST_POOL_OK_P (operand))
badop = 0;
constmemok = 1;
break;
@@ -3178,8 +3183,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
&& offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
|| (reg_equiv_address[REGNO (operand)] != 0))))
win = 1;
- /* force_const_mem does not accept HIGH. */
- if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH)
+ if (CONST_POOL_OK_P (operand)
|| GET_CODE (operand) == MEM)
badop = 0;
constmemok = 1;
@@ -3299,7 +3303,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
/* If we didn't already win, we can reload
constants via force_const_mem, and other
MEMs by reloading the address like for 'o'. */
- if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH)
+ if (CONST_POOL_OK_P (operand)
|| GET_CODE (operand) == MEM)
badop = 0;
constmemok = 1;
@@ -3375,9 +3379,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
an early reload pass. Note that the test here is
precisely the same as in the code below that calls
force_const_mem. */
- if (CONSTANT_P (operand)
- /* force_const_mem does not accept HIGH. */
- && GET_CODE (operand) != HIGH
+ if (CONST_POOL_OK_P (operand)
&& ((PREFERRED_RELOAD_CLASS (operand,
(enum reg_class) this_alternative[i])
== NO_REGS)
@@ -3751,9 +3753,7 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
into registers are here changed into memory references. */
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i]
- && CONSTANT_P (recog_data.operand[i])
- /* force_const_mem does not accept HIGH. */
- && GET_CODE (recog_data.operand[i]) != HIGH
+ && CONST_POOL_OK_P (recog_data.operand[i])
&& ((PREFERRED_RELOAD_CLASS (recog_data.operand[i],
(enum reg_class) goal_alternative[i])
== NO_REGS)
diff --git a/gcc/unwind-dw2-fde-glibc.c b/gcc/unwind-dw2-fde-glibc.c
index 71fbf61..f6f62c6 100644
--- a/gcc/unwind-dw2-fde-glibc.c
+++ b/gcc/unwind-dw2-fde-glibc.c
@@ -52,6 +52,10 @@
&& (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
|| (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
+#ifndef __RELOC_POINTER
+# define __RELOC_POINTER(ptr, base) ((ptr) + (base))
+#endif
+
static const fde * _Unwind_Find_registered_FDE (void *pc, struct dwarf_eh_bases *bases);
#define _Unwind_Find_FDE _Unwind_Find_registered_FDE
@@ -109,7 +113,11 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
struct unw_eh_callback_data *data = (struct unw_eh_callback_data *) ptr;
const ElfW(Phdr) *phdr, *p_eh_frame_hdr, *p_dynamic;
long n, match;
+#ifdef __FRV_FDPIC__
+ struct elf32_fdpic_loadaddr load_base;
+#else
_Unwind_Ptr load_base;
+#endif
const unsigned char *p;
const struct unw_eh_frame_hdr *hdr;
_Unwind_Ptr eh_frame;
@@ -132,7 +140,8 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
{
if (phdr->p_type == PT_LOAD)
{
- _Unwind_Ptr vaddr = phdr->p_vaddr + load_base;
+ _Unwind_Ptr vaddr = (_Unwind_Ptr)
+ __RELOC_POINTER (phdr->p_vaddr, load_base);
if (data->pc >= vaddr && data->pc < vaddr + phdr->p_memsz)
match = 1;
}
@@ -146,7 +155,7 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
/* Read .eh_frame_hdr header. */
hdr = (const struct unw_eh_frame_hdr *)
- (p_eh_frame_hdr->p_vaddr + load_base);
+ __RELOC_POINTER (p_eh_frame_hdr->p_vaddr, load_base);
if (hdr->version != 1)
return 1;
@@ -157,7 +166,8 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
{
/* For dynamically linked executables and shared libraries,
DT_PLTGOT is the gp value for that object. */
- ElfW(Dyn) *dyn = (ElfW(Dyn) *) (p_dynamic->p_vaddr + load_base);
+ ElfW(Dyn) *dyn = (ElfW(Dyn) *)
+ __RELOC_POINTER (p_dynamic->p_vaddr, load_base);
for (; dyn->d_tag != DT_NULL ; dyn++)
if (dyn->d_tag == DT_PLTGOT)
{
@@ -166,6 +176,8 @@ _Unwind_IteratePhdrCallback (struct dl_phdr_info *info, size_t size, void *ptr)
break;
}
}
+# elif defined __FRV_FDPIC__ && defined __linux__
+ data->dbase = load_base.got_value;
# else
# error What is DW_EH_PE_datarel base on this platform?
# endif