diff options
210 files changed, 12780 insertions, 854 deletions
diff --git a/ChangeLog b/ChangeLog index d8cbbd8dffd..7c9bcf60b2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-10-16 Nick Clifton <nickc@redhat.com> + + * MAINTAINERS: Add myself as a maintainer for the RX port. + +2009-10-26 Johannes Singler <singler@kit.edu> + + * MAINTAINERS (Write After Approval): Update my e-mail address. + 2009-10-23 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> * configure.ac (CLooG test): Use = with test. diff --git a/ChangeLog.MELT b/ChangeLog.MELT index 827b5b7dc1b..b30546b9ac7 100644 --- a/ChangeLog.MELT +++ b/ChangeLog.MELT @@ -1,4 +1,7 @@ +2009-10-27 Basile Starynkevitch <basile@starynkevitch.net> + MELT branch merged with trunk rev 153581 + 2009-10-24 Basile Starynkevitch <basile@starynkevitch.net> MELT branch merged with trunk rev 153531 diff --git a/MAINTAINERS b/MAINTAINERS index 0b122acc12a..ed045813a06 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -82,6 +82,7 @@ picochip port Daniel Towner dant@picochip.com rs6000 port Geoff Keating geoffk@geoffk.org rs6000 port David Edelsohn edelsohn@gnu.org rs6000 vector extns Aldy Hernandez aldyh@redhat.com +rx port Nick Clifton nickc@redhat.com s390 port Hartmut Penner hpenner@de.ibm.com s390 port Ulrich Weigand uweigand@de.ibm.com s390 port Andreas Krebbel Andreas.Krebbel@de.ibm.com @@ -451,7 +452,7 @@ Svein Seldal svein@dev.seldal.com Thiemo Seufer ths@networkno.de Mark Shinwell shinwell@codesourcery.com Ghassan Shobaki ghassan.shobaki@amd.com -Johannes Singler singler@ira.uka.de +Johannes Singler singler@kit.edu Franz Sirl franz.sirl-kernel@lauterbach.com Jan Sjodin jan.sjodin@amd.com Edward Smith-Rowland 3dw4rd@verizon.net diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b46a2ef7288..3014db71c12 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,535 @@ - 2009-09-27 Andy Hutchinson <hutchinsonandy@gcc.gnu.org> +2009-10-26 Ben Elliston <bje@au.ibm.com> + Michael Meissner <meissner@linux.vnet.ibm.com> + Ulrich Weigand <uweigand@de.ibm.com> + + * config.gcc (spu-*-elf*): Add spu_cache.h to extra_headers. + * config/spu/spu_cache.h: New file. + + * config/spu/cachemgr.c: New file. + * config/spu/cache.S: New file. + + * config/spu/spu.h (ASM_OUTPUT_SYMBOL_REF): Define. + (ADDR_SPACE_EA): Define. + (TARGET_ADDR_SPACE_KEYWORDS): Define. + * config/spu/spu.c (EAmode): New macro. + (TARGET_ADDR_SPACE_POINTER_MODE): Define. + (TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise. + (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Likewise. + (TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Likewise. + (TARGET_ADDR_SPACE_SUBSET_P): Likewise. + (TARGET_ADDR_SPACE_CONVERT): Likewise. + (TARGET_ASM_SELECT_SECTION): Likewise. + (TARGET_ASM_UNIQUE_SECTION): Likewise. + (TARGET_ASM_UNALIGNED_SI_OP): Likewise. + (TARGET_ASM_ALIGNED_DI_OP): Likewise. + (ea_symbol_ref): New function. + (spu_legitimate_constant_p): Handle __ea qualified addresses. + (spu_addr_space_legitimate_address_p): New function. + (spu_addr_space_legitimize_address): Likewise. + (cache_fetch): New global. + (cache_fetch_dirty): Likewise. + (ea_alias_set): Likewise. + (ea_load_store): New function. + (ea_load_store_inline): Likewise. + (expand_ea_mem): Likewise. + (spu_expand_mov): Handle __ea qualified memory references. + (spu_addr_space_pointer_mode): New function. + (spu_addr_space_address_mode): Likewise. + (spu_addr_space_subset_p): Likewise. + (spu_addr_space_convert): Likewise. + (spu_section_type_flags): Handle "._ea" section. + (spu_select_section): New function. + (spu_unique_section): Likewise. + * config/spu/spu-c.c (spu_cpu_cpp_builtins): Support __EA32__ + and __EA64__ predefined macros. + * config/spu/spu-elf.h (LIB_SPEC): Handle -mcache-size= and + -matomic-updates switches. + + * config/spu/t-spu-elf (MULTILIB_OPTIONS): Define. + (EXTRA_MULTILIB_PARTS): Add libgcc_cachemgr.a, + libgcc_cachemgr_nonatomic.a, libgcc_cache8k.a, libgcc_cache16k.a, + libgcc_cache32k.a, libgcc_cache64k.a, libgcc_cache128k.a. + ($(T)cachemgr.o, $(T)cachemgr_nonatomic.o): New target. + ($(T)cache8k.o, $(T)cache16k.o, $(T)cache32k.o, $(T)cache64k.o, + $(T)cache128k.o): Likewise. + ($(T)libgcc_%.a): Likewise. + + * config/spu/spu.h (TARGET_DEFAULT): Add MASK_ADDRESS_SPACE_CONVERSION. + * config/spu/spu.opt (-mea32/-mea64): Add switches. + (-maddress-space-conversion): Likewise. + (-mcache-size=): Likewise. + (-matomic-updates): Likewise. + * doc/invoke.texi (-mea32/-mea64): Document. + (-maddress-space-conversion): Likewise. + (-mcache-size=): Likewise. + (-matomic-updates): Likewise. + +2009-10-26 Ben Elliston <bje@au.ibm.com> + Michael Meissner <meissner@linux.vnet.ibm.com> + Ulrich Weigand <uweigand@de.ibm.com> + + * doc/tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document. + + * c-common.c (c_common_reswords): If TARGET_ADDR_SPACE_KEYWORDS is + defined, add the named address space keywords. + (c_addr_space_name): New function. + (complete_array_type): Preserve named address space. + (handle_mode_attribute): Use targetm.addr_space.valid_pointer_mode + instead of targetm.valid_pointer_mode. + + * c-common.h (enum rid): Add RID_ADDR_SPACE_0 .. RID_ADDR_SPACE_15, + RID_FIRST_ADDR_SPACE and RID_LAST_ADDR_SPACE. + (ADDR_SPACE_KEYWORD): New macro. + (c_addr_space_name): Add prototype. + + * c-tree.h (struct c_declspecs): Add address_space member. + (declspecs_add_addrspace): Add prototype. + + * c-pretty-print.c (pp_c_type_qualifier_list): Handle address spaces. + + * c-parser.c (c_parse_init): Add assertion. + (typedef enum c_id_kind): Add C_ID_ADDRSPACE. + (c_lex_one_token): Handle address space keywords. + (c_token_starts_typename): Likewise. + (c_token_starts_declspecs): Likewise. + (c_parser_declspecs): Likewise. + (c_parser_postfix_expression_after_paren_type): Diagnose compound + literal within function qualified with named address space. + + * c-decl.c (diagnose_mismatched_decls): Diagnose conflicting named + address space qualifiers. + (shadow_tag_warned): Warn about useless address space qualifiers. + (quals_from_declspecs): Handle address space qualifiers. + (grokdeclarator): Likewise. + (build_null_declspecs): Likewise. + (declspecs_add_addrspace): New function. + + * c-typeck.c (addr_space_superset): New function. + (qualify_type): Handle named address spaces. + (composite_type): Likewise. + (common_pointer_type): Likewise. + (comp_target_types): Likewise. + (build_conditional_expr): Likewise. + (handle_warn_cast_qual): Likewise. + (build_c_cast): Likewise. + (convert_for_assignment): Likewise. + (build_binary_op): Likewise. + (pointer_diff): Handle named address spaces. Use intermediate + integer type of sufficient size if required. + +2009-10-26 Ben Elliston <bje@au.ibm.com> + Michael Meissner <meissner@linux.vnet.ibm.com> + Ulrich Weigand <uweigand@de.ibm.com> + + * doc/tm.texi (TARGET_ADDR_SPACE_POINTER_MODE): Document. + (TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise. + (TARGET_ADDR_SPACE_VALID_POINTER_MODE): Likewise. + + * target.h (struct target_def): Add pointer_mode, address_mode, + and valid_pointer_mode to addr_space substructure. + * target-def.h (TARGET_ADDR_SPACE_POINTER_MODE): Define. + (TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise. + (TARGET_ADDR_SPACE_VALID_POINTER_MODE): Likewise. + (TARGET_ADDR_SPACE_HOOKS): Add them. + * targhooks.c (target_default_pointer_address_modes_p): New function. + * target.h (target_default_pointer_address_modes_p): Add prototype. + * targhooks.c (default_addr_space_pointer_mode): New function. + (default_addr_space_address_mode): Likewise. + (default_addr_space_valid_pointer_mode): Likewise. + * targhooks.h (default_addr_space_pointer_mode): Add prototype. + (default_addr_space_address_mode): Likewise. + (default_addr_space_valid_pointer_mode): Likewise. + * output.h (default_valid_pointer_mode): Move to ... + * targhooks.h (default_valid_pointer_mode): ... here. + * varasm.c (default_valid_pointer_mode): Move to ... + * targhooks.c (default_valid_pointer_mode): ... here. + + * varasm.c (output_constant): Use targetm.addr_space.valid_pointer_mode + instead of targetm.valid_pointer_mode. + + * fold-const.c (fit_double_type): Use int_or_pointer_precision. + * tree.c (integer_pow2p): Likewise. + (tree_log2): Likewise. + (tree_floor_log2): Likewise. + (signed_or_unsigned_type_for): Support pointer type of different size. + (int_or_pointer_precision): New function. + * tree.h (int_or_pointer_precision): Add prototype. + * stor-layout.c (layout_type): Set TYPE_PRECISION for offset types. + * varasm.c (initializer_constant_valid_p): Use TYPE_PRECISION of + incoming pointer type instead of POINTER_SIZE. + + * tree.c (build_pointer_type): Use appropriate pointer mode + instead of ptr_mode. + (build_reference_type): Likewise. + * expr.c (store_expr): Likewise. + (expand_expr_addr_expr): Likewise. + * tree-vect-data-refs.c (vect_create_data_ref_ptr): Likewise. + * cfgexpand.c (expand_debug_expr): Likewise. + + * auto-inc-dec.c: Include "target.h". + (try_merge): Use appropriate address mode instead of Pmode. + (find_inc): Likewise. + * combine.c (find_split_point): Likewise. + * cselib.c (cselib_record_sets): Likewise. + * dse.c (replace_inc_dec): Likewise. + (canon_address): Likewise. + * var-tracking.c (replace_expr_with_values): Likewise. + (count_uses): Likewise. + (add_uses): Likewise. + (add_stores): Likewise. + * emit-rtl.c: Include "target.h". + (adjust_address_1): Use appropriate address mode instead of Pmode. + (offset_address): Likewise. + * explow.c (break_out_memory_refs): Likewise. + (memory_address_addr_space): Likewise. + (promote_mode): Likewise. + * expr.c (move_by_pieces): Likewise. + (emit_block_move_via_loop): Likewise. + (store_by_pieces): Likewise. + (store_by_pieces_1): Likewise. + (expand_assignment): Likewise. + (store_constructor): Likewise. + (expand_expr_addr_expr): Likewise. + (expand_expr_real_1): Likewise. + * cfgexpand.c (expand_debug_expr): Likewise. + * ifcvt.c (noce_try_cmove_arith): Likewise. + * regcprop.c (kill_autoinc_value): Likewise. + * regmove.c (try_auto_increment): Likewise. + * reload.c (find_reloads): Likewise. + (find_reloads_address): Likewise. + (find_reloads_address_1): Likewise. + * sched-deps.c: Include "target.h". + (sched_analyze_1): Use appropriate address mode instead of Pmode. + (sched_analyze_2): Likewise. + * sel-sched-dump.c: Include "target.h". + (debug_mem_addr_value): Use appropriate address mode instead of Pmode. + * stor-layout.c (layout_type): Likewise. + * tree-ssa-loop-ivopts.c (produce_memory_decl_rtl): Likewise. + (multiplier_allowed_in_address_p): Likewise. + (get_address_cost): Likewise. + * varasm.c (make_decl_rtl): Likewise. + + * expr.c (expand_assignment): Always convert offsets to appropriate + address mode. + (store_expr): Likewise. + (store_constructor): Likewise. + (expand_expr_real_1): Likewise. + + * reload.h (form_sum): Add MODE argument. + * reload.c (form_sum): Add MODE argument, use it instead of Pmode. + Update recursive calls. + (subst_indexed_address): Update calls to form_sum. + + * tree-flow.h (addr_for_mem_ref): Add ADDRSPACE argument. + * tree-ssa-address.c: Include "target.h". + (templates): Replace by ... + (mem_addr_template_list): ... this new vector. + (TEMPL_IDX): Handle address space numbers. + (gen_addr_rtx): Add address mode argument, use it instead of Pmode. + (addr_for_mem_ref): Add ADDRSPACE argument. Use per-address-space + instead of global cache. Update call to gen_addr_rtx. + (valid_mem_ref_p): Update call to addr_for_mem_ref. + * expr.c (expand_expr_real_1): Update call to addr_for_mem_ref. + + * rtl.h (convert_memory_address_addr_space): Add prototype. + (convert_memory_address): Define as macro. + * explow.c (convert_memory_address): Rename to ... + (convert_memory_address_addr_space): ... this. Add ADDRSPACE argument. + Use appropriate pointer and address modes instead of ptr_mode / Pmode. + Update recursive calls. + (memory_address_addr_space): Call convert_memory_address_addr_space. + * expmed.c (make_tree): Likewise. + * expr.c (expand_assignment): Likewise. + (expand_expr_addr_expr_1): Likewise. Also, add ADDRSPACE argument. + (expand_expr_addr_expr): Likewise. Also, update call. + + * alias.c (find_base_value): Guard pointer size optimizations. + (find_base_term): Likewise. + * rtlanal.c (nonzero_bits1): Likewise. + (num_sign_bit_copies1): Likewise. + * simplify-rtx.c (simplify_unary_operation_1): Likewise. + + * Makefile.in (tree-ssa-address.o): Add $(TARGET_H) dependency. + (emit-rtl.o): Likewise. + (auto-inc-dec.o): Likewise. + (sched-deps.o): Likewise. + +2009-10-26 Ben Elliston <bje@au.ibm.com> + Michael Meissner <meissner@linux.vnet.ibm.com> + Ulrich Weigand <uweigand@de.ibm.com> + + * doc/extend.texi (Named Address Spaces): New section. + * coretypes.h (addr_space_t): New type. + (ADDR_SPACE_GENERIC): New define. + (ADDR_SPACE_GENERIC_P): New macro. + + * doc/tm.texi (Named Address Spaces): New section. + (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Document. + (TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Document. + (TARGET_ADDR_SPACE_SUBSET_P): Document. + (TARGET_ADDR_SPACE_CONVERT): Document. + * target.h (struct gcc_target): Add addr_space substructure. + * target-def.h (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Define. + (TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Likewise. + (TARGET_ADDR_SPACE_SUBSET_P): Likewise. + (TARGET_ADDR_SPACE_CONVERT): Likewise. + (TARGET_ADDR_SPACE_HOOKS): Likewise. + (TARGET_INITIALIZER): Initialize addr_space hooks. + * targhooks.c (default_addr_space_legitimate_address_p): New function. + (default_addr_space_legitimize_address): Likewise. + (default_addr_space_subset_p): Likewise. + (default_addr_space_convert): Likewise. + * targhooks.h (default_addr_space_legitimate_address_p): Add prototype. + (default_addr_space_legitimize_address): Likewise. + (default_addr_space_subset_p): Likewise. + (default_addr_space_convert): Likewise. + + * doc/rtl.texi (MEM_ADDR_SPACE): Document. + * rtl.h (mem_attrs): Add ADDRSPACE memory attribute. + (MEM_ADDR_SPACE): New macro. + * emit-rtl.c (get_mem_attrs): Add ADDRSPACE argument and set + address space memory attribute. + (mem_attrs_htab_hash): Handle address space memory attribute. + (mem_attrs_htab_eq): Likewise. + (set_mem_attributes_minus_bitpos): Likewise. + (set_mem_alias_set): Likewise. + (set_mem_align): Likewise. + (set_mem_expr): Likewise. + (set_mem_offset): Likewise. + (set_mem_size): Likewise. + (adjust_address_1): Likewise. + (offset_address): Likewise. + (widen_memoy_address): Likewise. + (get_spill_slot_decl): Likewise. + (set_mem_attrs_for_spill): Likewise. + (set_mem_addr_space): New function. + * emit-rtl.h (set_mem_addr_space): Add prototype. + * print-rtl.c (print_rtx): Print address space memory attribute. + * expr.c (expand_assignment): Set address space memory attribute + of generated MEM RTXes as appropriate. + (expand_expr_real_1): Likewise. + * cfgexpand.c (expand_debug_expr): Likewise. + * tree-ssa-loop-ivopts.c (produce_memory_decl_rtl): Likewise. + + * tree.h (struct tree_base): Add address_space bitfield. Reduce + size of "spare" bitfield. + (TYPE_ADDR_SPACE): New macro. + (ENCODE_QUAL_ADDR_SPACE): Likewise. + (DECODE_QUAL_ADDR_SPACE): Likewise. + (CLEAR_QUAL_ADDR_SPACE): Likewise. + (KEEP_QUAL_ADDR_SPACE): Likewise. + (TYPE_QUALS): Encode type address space. + (TYPE_QUALS_NO_ADDR_SPACE): New macro. + * tree.c (set_type_quals): Set type address space. + (build_array_type): Inherit array address space from element type. + * print-tree.c (print_node_brief): Print type address space. + (print_node): Likewise. + * tree-pretty-print.c (dump_generic_node): Likewise. + + * explow.c (memory_address): Rename to ... + (memory_address_addr_space): ... this. Add ADDRSPACE argument. + Use address-space aware variants of memory address routines. + * recog.c (memory_address_p): Rename to ... + (memory_address_addr_space_p): ... this. Add ADDSPACE argument. + Use address-space aware variants of memory address routines. + (offsettable_address_p): Rename to ... + (offsettable_address_addr_space_p): ... this. Add ADDRSPACE argument. + Use address-space aware variants of memory address routines. + * reload.c (strict_memory_address_p): Rename to ... + (strict_memory_address_addr_space_p): ... this. Add ADDSPACE argument. + Use address-space aware variants of memory address routines. + (maybe_memory_address_p): Rename to ... + (maybe_memory_address_addr_space_p): ... this. Add ADDSPACE argument. + Use address-space aware variants of memory address routines. + * expr.h (memory_address_addr_space): Add prototype. + (memory_address): Define as macro. + * recog.h (memory_address_addr_space_p): Add prototype. + (memory_address_p): Define as macro. + (offsettable_address_addr_space_p): Add prototype. + (offsettable_address_p): Define as macro. + (strict_memory_address_addr_space_p): Add prototype. + (strict_memory_address_p): Define as macro. + + * combine.c (find_split_point): Use address-space aware variants + of memory address routines. + * emit-rtl.c (operand_subword): Likewise. + (change_address_1): Likewise. + (adjust_address_1): Likewise. + (offset_address): Likewise. + * expr.c (emit_move_insn): Likewise. + (expand_assignment): Likewise. + (expand_expr_real_1): Likewise. + * recog.c (verify_changes): Likewise. + (general_operand): Likewise. + (offsettable_memref_p): Likewise. + (offsettable_nonstrict_memref_p): Likewise. + (constrain_operands): Likewise. + * reload.c (get_secondary_mem): Likewise. + (find_reloads_toplev): Likewise. + (find_reloads_address): Likewise. + (find_reloads_subreg_address): Likewise. + * reload1.c (reload): Likewise. + * rtlhooks.c (gen_lowpart_if_possible): Likewise. + * rtl.h (address_cost): Add ADDRSPACE argument. + * rtlanal.c (address_cost): Add ADDRSPACE argument. Use address-space + aware variant of memory address routines. + * loop-invariant.c (create_new_invariant): Update address_cost call. + * tree-ssa-loop-ivopts.c (computation_cost): Likewise. + * fwprop.c (should_replace_address): Add ADDRSPACE argument. + Use address-space aware variant of memory address routines. + (propagate_rtx_1): Update call to should_replace_address. + * tree-flow.h (multiplier_allowed_in_address_p): Add ADDRSPACE + argument. + * tree-ssa-loop-ivopts.c (multiplier_allowed_in_address_p): Add + ADDRSPACE argument. Use per-address-space instead of global cache. + Use address-space aware variant of memory address routines. + (get_address_cost): Likewise. + (get_computation_cost_at): Update calls. + * tree-ssa-address.c (valid_mem_ref_p): Add ADDRSPACE argument. + Use address-space aware variant of memory address routines. + (create_mem_ref_raw): Update call to valid_mem_ref_p. + (most_expensive_mult_to_index): Update call to + multiplier_allowed_in_address_p. + + * dwarf2out.c (modified_type_die): Output DW_AT_address_class + attribute to indicate named address spaces. + + * varasm.c (get_variable_section): DECLs in named address spaces + cannot be "common". + + * reload.c (find_reloads_address): Do not use LEGITIMIZE_RELOAD_ADDRESS + for addresses in a non-generic address space. + + * expr.c (emit_block_move_hints): Do not use libcalls for + memory in non-generic address spaces. + (clear_storage_hints): Likewise. + (expand_assignment): Likewise. + + * fold-const.c (operand_equal_p): Expressions refering to different + address spaces are not equivalent. + + * rtl.c (rtx_equal_p_cb): MEMs refering to different address + spaces are not equivalent. + (rtx_equal_p): Likewise. + * cse.c (exp_equiv_p): Likewise. + * jump.c (rtx_renumbered_equal_p): Likewise. + * reload.c (operands_match_p): Likewise. + + * alias.c (nonoverlapping_memrefs_p): MEMs refering to different + address spaces may alias. + (true_dependence): Likewise. + (canon_true_dependence): Likewise. + (write_dependence_p): Likewise. + + * dse.c (canon_address): Handle named address spaces. + * ifcvt.c (noce_try_cmove_arith): Likewise. + + * tree.def (ADDR_SPACE_CONVERT_EXPR): New tree code. + * expr.c (expand_expr_real_2): Expand ADDR_SPACE_CONVERT_EXPR. + * convert.c (convert_to_pointer): Generate ADDR_SPACE_CONVERT_EXPR + to handle conversions between different address spaces. + * fold-const.c (fold_convert_loc): Likewise. + (fold_unary_loc): Handle ADDR_SPACE_CONVERT_EXPR. + * tree-pretty-print.c (dump_generic_node): Likewise. + * gimple-pretty-print.c (dump_unary_rhs): Likewise. + * tree-cfg.c (verify_gimple_assign_unary): Likewise. + * tree-inline.c (estimate_operator_cost): Likewise. + * tree-ssa.c (useless_type_conversion_p): Conversions between pointers + to different address spaces are not useless. + +2009-10-26 Jakub Jelinek <jakub@redhat.com> + + PR bootstrap/41345 + * cfgcleanup.c (trivially_empty_bb_p): New function. + (try_optimize_bb): Use it instead of checking BB_HEAD == BB_END. + + PR debug/41828 + * dwarf2out.c (add_pubname, add_pubtype, generic_parameter_die, + add_name_and_src_coords_attributes, gen_namespace_die, + dwarf2out_set_name): Handle dwarf2_name returning NULL. + +2009-10-26 Nick Clifton <nickc@redhat.com> + + * config.gcc: Add support for RX target. + * config/rx: New directory. + * config/rx/constraints.md: New file. + * config/rx/predicates.md: New file. + * config/rx/rx.c: New file. + * config/rx/rx.h: New file. + * config/rx/rx.md: New file. + * config/rx/rx.opt: New file. + * config/rx/rx-protos.h: New file. + * config/rx/t-rx: New file. + * doc/extend.texi: Document RX function attributes. + * doc/invoke.texi: Document RX specific command line options. + * doc/contrib.texi: Document RX contribution. + * doc/md.texi: Document RX constraints. + * doc/install.texi: Document RX support. + +2009-10-26 Michael Matz <matz@suse.de> + + PR tree-optimization/41783 + * tree-ssa-alias.c (get_continuation_for_phi): Export, add a special + case for simple diamonds. + * tree-ssa-alias.h (get_continuation_for_phi): Declare. + * tree-ssa-pre.c (translate_vuse_through_block): Add same_valid + argument, use alias oracle to skip some vdefs. + (phi_translate_1): Change call to above, don't allocate new + value ids if they can stay the same. + (compute_avail): Allow vuse walking when looking up references. + +2009-10-26 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/41826 + * tree-ssa-structalias.c (get_constraint_for_ptr_offset): Avoid + access to re-allocated vector fields. + +2009-10-26 Richard Guenther <rguenther@suse.de> + + * graphite-sese-to-poly.c (check_poly_representation): Fix + compile without checking. + +2009-10-26 Janus Weil <janus@gcc.gnu.org> + + PR fortran/41714 + * gimple.h (tree_annotate_all_with_location): Remove prototype. + * gimplify.c (tree_should_carry_location_p, + tree_annotate_one_with_location,tree_annotate_all_with_location): + Remove obsolete functions. + +2009-10-25 Kaz Kojima <kkojima@gcc.gnu.org> + + PR target/41813 + * config/sh/sh.md (stuff_delay_slot): Don't set T_REG in pattern. + +2009-10-25 Richard Guenther <rguenther@suse.de> + + * lto-streamer-in.c (unpack_ts_decl_common_value_fields): + Stream DECL_RESTRICTED_P. + * lto-streamer-out.c (pack_ts_decl_common_value_fields): Likewise. + +2009-10-25 Richard Sandiford <rdsandiford@googlemail.com> + + * config/mips/mips.c (mips_restore_gp_from_cprestore_slot): Emit + a note when expanding to nothing. + +2009-10-25 Richard Guenther <rguenther@suse.de> + + PR middle-end/41814 + * tree.c (find_decls_types_r): Deal with Java overloading + BINFO_VIRTUALS for its own purpose. + +2009-10-24 Adam Nemet <anemet@caviumnetworks.com> + + * config/mips/predicates.md (hilo_operand): New predicate. + * config/mips/mips.md (<u>mulsidi3_64bit): Change it to a + define_insn. Correct !ISA_HAS_EXT_INS length from 24 to 28. Move + splitter part from here ...: + (<u>mulsidi3_64bit splitter for !ISA_HAS_EXT_INS): ... to here. Swap + op0 and op4 to match the DINS case. + (<u>mulsidi3_64bit splitter for ISA_HAS_EXT_INS): New splitter. + +2009-10-24 Andy Hutchinson <hutchinsonandy@gcc.gnu.org> PR middle-end/19154 * avr.md (QIDI): Add new mode iterator. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 68b8c8cae81..3fb5c938e9b 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20091024 +20091027 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index d1d2dfcad3e..fa278fe791b 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2455,7 +2455,7 @@ tree-ssa-address.o : tree-ssa-address.c $(TREE_FLOW_H) $(CONFIG_H) \ $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) \ output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ $(TREE_PASS_H) $(FLAGS_H) $(TREE_INLINE_H) $(RECOG_H) insn-config.h \ - $(EXPR_H) gt-tree-ssa-address.h $(GGC_H) tree-affine.h + $(EXPR_H) gt-tree-ssa-address.h $(GGC_H) tree-affine.h $(TARGET_H) tree-ssa-loop-niter.o : tree-ssa-loop-niter.c $(TREE_FLOW_H) $(CONFIG_H) \ $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(PARAMS_H) \ $(TREE_INLINE_H) output.h $(DIAGNOSTIC_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ @@ -2867,7 +2867,7 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) insn-config.h $(RECOG_H) \ $(GGC_H) $(EXPR_H) hard-reg-set.h $(BITMAP_H) $(TOPLEV_H) $(BASIC_BLOCK_H) \ $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h $(TREE_PASS_H) gt-emit-rtl.h \ - $(REAL_H) $(DF_H) $(PARAMS_H) + $(REAL_H) $(DF_H) $(PARAMS_H) $(TARGET_H) real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(TOPLEV_H) $(TM_P_H) $(REAL_H) dfp.h dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ @@ -3077,7 +3077,7 @@ alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h $(HASHTAB_H) auto-inc-dec.o : auto-inc-dec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(RTL_H) $(TM_P_H) hard-reg-set.h $(BASIC_BLOCK_H) insn-config.h \ $(REGS_H) $(FLAGS_H) output.h $(FUNCTION_H) $(EXCEPT_H) $(TOPLEV_H) $(RECOG_H) \ - $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) + $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) $(TARGET_H) cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \ $(REGS_H) hard-reg-set.h output.h $(TOPLEV_H) $(FUNCTION_H) $(EXCEPT_H) $(GGC_H) \ $(TM_P_H) $(TIMEVAR_H) $(OBSTACK_H) $(TREE_H) alloc-pool.h \ @@ -3258,7 +3258,7 @@ haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ $(FUNCTION_H) $(INSN_ATTR_H) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) cselib.h \ - ira.h $(PARAMS_H) $(TM_P_H) ira.h + ira.h $(PARAMS_H) $(TM_P_H) ira.h $(TARGET_H) sched-rgn.o : sched-rgn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ $(FUNCTION_H) $(INSN_ATTR_H) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) $(PARAMS_H) \ diff --git a/gcc/alias.c b/gcc/alias.c index 09ec775c5d0..40226f26b17 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -1060,6 +1060,11 @@ find_base_value (rtx src) return 0; case TRUNCATE: + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + break; if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode)) break; /* Fall through. */ @@ -1074,6 +1079,12 @@ find_base_value (rtx src) case ZERO_EXTEND: case SIGN_EXTEND: /* used for NT/Alpha pointers */ + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + break; + { rtx temp = find_base_value (XEXP (src, 0)); @@ -1466,6 +1477,11 @@ find_base_term (rtx x) return REG_BASE_VALUE (x); case TRUNCATE: + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + return 0; if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode)) return 0; /* Fall through. */ @@ -1480,6 +1496,12 @@ find_base_term (rtx x) case ZERO_EXTEND: case SIGN_EXTEND: /* Used for Alpha/NT pointers */ + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + return 0; + { rtx temp = find_base_term (XEXP (x, 0)); @@ -2188,6 +2210,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) && ! rtx_equal_p (rtlx, rtly)) return 1; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_P (rtlx) && MEM_P (rtly) + && MEM_ADDR_SPACE (rtlx) != MEM_ADDR_SPACE (rtly)) + return 0; + /* Get the base and offsets of both decls. If either is a register, we know both are and are the same, so use that as the base. The only we can avoid overlap is if we can deduce that they are nonoverlapping @@ -2279,6 +2308,12 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x, if (nonoverlapping_memrefs_p (mem, x)) return 0; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + if (mem_mode == VOIDmode) mem_mode = GET_MODE (mem); @@ -2356,6 +2391,12 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr, if (nonoverlapping_memrefs_p (x, mem)) return 0; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + if (! x_addr) x_addr = get_addr (XEXP (x, 0)); @@ -2416,6 +2457,12 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep) if (nonoverlapping_memrefs_p (x, mem)) return 0; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + x_addr = get_addr (XEXP (x, 0)); mem_addr = get_addr (XEXP (mem, 0)); diff --git a/gcc/auto-inc-dec.c b/gcc/auto-inc-dec.c index 929a2dcade8..3b3006c985f 100644 --- a/gcc/auto-inc-dec.c +++ b/gcc/auto-inc-dec.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "df.h" #include "dbgcnt.h" +#include "target.h" /* This pass was originally removed from flow.c. However there is almost nothing that remains of that code. @@ -613,6 +614,7 @@ try_merge (void) /* The width of the mem being accessed. */ int size = GET_MODE_SIZE (GET_MODE (mem)); rtx last_insn = NULL; + enum machine_mode reg_mode = GET_MODE (inc_reg); switch (inc_insn.form) { @@ -667,33 +669,33 @@ try_merge (void) case SIMPLE_PRE_INC: /* ++size */ if (dump_file) fprintf (dump_file, "trying SIMPLE_PRE_INC\n"); - return attempt_change (gen_rtx_PRE_INC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_POST_INC: /* size++ */ if (dump_file) fprintf (dump_file, "trying SIMPLE_POST_INC\n"); - return attempt_change (gen_rtx_POST_INC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_PRE_DEC: /* --size */ if (dump_file) fprintf (dump_file, "trying SIMPLE_PRE_DEC\n"); - return attempt_change (gen_rtx_PRE_DEC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_POST_DEC: /* size-- */ if (dump_file) fprintf (dump_file, "trying SIMPLE_POST_DEC\n"); - return attempt_change (gen_rtx_POST_DEC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg); break; case DISP_PRE: /* ++con */ if (dump_file) fprintf (dump_file, "trying DISP_PRE\n"); - return attempt_change (gen_rtx_PRE_MODIFY (Pmode, + return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -702,9 +704,9 @@ try_merge (void) case DISP_POST: /* con++ */ if (dump_file) fprintf (dump_file, "trying POST_DISP\n"); - return attempt_change (gen_rtx_POST_MODIFY (Pmode, + return attempt_change (gen_rtx_POST_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -713,9 +715,9 @@ try_merge (void) case REG_PRE: /* ++reg */ if (dump_file) fprintf (dump_file, "trying PRE_REG\n"); - return attempt_change (gen_rtx_PRE_MODIFY (Pmode, + return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -724,9 +726,9 @@ try_merge (void) case REG_POST: /* reg++ */ if (dump_file) fprintf (dump_file, "trying POST_REG\n"); - return attempt_change (gen_rtx_POST_MODIFY (Pmode, + return attempt_change (gen_rtx_POST_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -1089,7 +1091,9 @@ find_inc (bool first_try) we are going to increment the result of the add insn. For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ - if (GET_MODE (inc_insn.reg_res) != Pmode) + addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); + if (GET_MODE (inc_insn.reg_res) + != targetm.addr_space.address_mode (as)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); @@ -1138,7 +1142,9 @@ find_inc (bool first_try) { /* For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ - if (GET_MODE (inc_insn.reg_res) != Pmode) + addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); + if (GET_MODE (inc_insn.reg_res) + != targetm.addr_space.address_mode (as)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); diff --git a/gcc/c-common.c b/gcc/c-common.c index 8a6d15b9d9b..1f30d06f4c7 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -710,6 +710,11 @@ const struct c_common_resword c_common_reswords[] = { "inout", RID_INOUT, D_OBJC }, { "oneway", RID_ONEWAY, D_OBJC }, { "out", RID_OUT, D_OBJC }, + +#ifdef TARGET_ADDR_SPACE_KEYWORDS + /* Any address space keywords recognized by the target. */ + TARGET_ADDR_SPACE_KEYWORDS, +#endif }; const unsigned int num_c_common_reswords = @@ -840,6 +845,19 @@ const struct attribute_spec c_common_format_attribute_table[] = { NULL, 0, 0, false, false, false, NULL } }; +/* Return identifier for address space AS. */ +const char * +c_addr_space_name (addr_space_t as) +{ + unsigned int i; + + for (i = 0; i < num_c_common_reswords; i++) + if (c_common_reswords[i].rid == RID_FIRST_ADDR_SPACE + as) + return c_common_reswords[i].word; + + gcc_unreachable (); +} + /* Push current bindings for the function name VAR_DECLS. */ void @@ -6459,9 +6477,10 @@ handle_mode_attribute (tree *node, tree name, tree args, if (POINTER_TYPE_P (type)) { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); tree (*fn)(tree, enum machine_mode, bool); - if (!targetm.valid_pointer_mode (mode)) + if (!targetm.addr_space.valid_pointer_mode (mode, as)) { error ("invalid pointer mode %qs", p); return NULL_TREE; @@ -8511,7 +8530,7 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default) if (quals == 0) unqual_elt = elt; else - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals)); /* Using build_distinct_type_copy and modifying things afterward instead of using build_array_type to create a new type preserves all of the diff --git a/gcc/c-common.h b/gcc/c-common.h index 61d52c870fb..d91546ff239 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -126,6 +126,30 @@ enum rid RID_AT_INTERFACE, RID_AT_IMPLEMENTATION, + /* Named address support, mapping the keyword to a particular named address + number. Named address space 0 is reserved for the generic address. If + there are more than 254 named addresses, the addr_space_t type will need + to be grown from an unsigned char to unsigned short. */ + RID_ADDR_SPACE_0, /* generic address */ + RID_ADDR_SPACE_1, + RID_ADDR_SPACE_2, + RID_ADDR_SPACE_3, + RID_ADDR_SPACE_4, + RID_ADDR_SPACE_5, + RID_ADDR_SPACE_6, + RID_ADDR_SPACE_7, + RID_ADDR_SPACE_8, + RID_ADDR_SPACE_9, + RID_ADDR_SPACE_10, + RID_ADDR_SPACE_11, + RID_ADDR_SPACE_12, + RID_ADDR_SPACE_13, + RID_ADDR_SPACE_14, + RID_ADDR_SPACE_15, + + RID_FIRST_ADDR_SPACE = RID_ADDR_SPACE_0, + RID_LAST_ADDR_SPACE = RID_ADDR_SPACE_15, + RID_MAX, RID_FIRST_MODIFIER = RID_STATIC, @@ -263,6 +287,10 @@ struct c_common_resword #define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */ #define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */ +/* Macro for backends to define named address keywords. */ +#define ADDR_SPACE_KEYWORD(STRING, VALUE) \ + { STRING, RID_FIRST_ADDR_SPACE + (VALUE), D_CONLY | D_EXT } + /* The reserved keyword table. */ extern const struct c_common_resword c_common_reswords[]; @@ -760,6 +788,7 @@ extern const struct attribute_spec c_common_format_attribute_table[]; extern tree (*make_fname_decl) (location_t, tree, int); +extern const char *c_addr_space_name (addr_space_t as); extern tree identifier_global_value (tree); extern void record_builtin_type (enum rid, const char *, tree); extern tree build_void_list_node (void); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index e237332f174..492d2e673b7 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1746,8 +1746,35 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, } else { - if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype)) - error ("conflicting type qualifiers for %q+D", newdecl); + int new_quals = TYPE_QUALS (newtype); + int old_quals = TYPE_QUALS (oldtype); + + if (new_quals != old_quals) + { + addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); + addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); + if (new_addr != old_addr) + { + if (ADDR_SPACE_GENERIC_P (new_addr)) + error ("conflicting named address spaces (generic vs %s) " + "for %q+D", + c_addr_space_name (old_addr), newdecl); + else if (ADDR_SPACE_GENERIC_P (old_addr)) + error ("conflicting named address spaces (%s vs generic) " + "for %q+D", + c_addr_space_name (new_addr), newdecl); + else + error ("conflicting named address spaces (%s vs %s) " + "for %q+D", + c_addr_space_name (new_addr), + c_addr_space_name (old_addr), + newdecl); + } + + if (CLEAR_QUAL_ADDR_SPACE (new_quals) + != CLEAR_QUAL_ADDR_SPACE (old_quals)) + error ("conflicting type qualifiers for %q+D", newdecl); + } else error ("conflicting types for %q+D", newdecl); diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); @@ -3605,7 +3632,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) else if (!declspecs->tag_defined_p && (declspecs->const_p || declspecs->volatile_p - || declspecs->restrict_p)) + || declspecs->restrict_p + || declspecs->address_space)) { if (warned != 1) pedwarn (input_location, 0, @@ -3676,7 +3704,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) if (!warned && !in_system_header && (declspecs->const_p || declspecs->volatile_p - || declspecs->restrict_p)) + || declspecs->restrict_p + || declspecs->address_space)) { warning (0, "useless type qualifier in empty declaration"); warned = 2; @@ -3699,7 +3728,8 @@ quals_from_declspecs (const struct c_declspecs *specs) { int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) - | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)); + | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) + | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); gcc_assert (!specs->type && !specs->decl_attr && specs->typespec_word == cts_none @@ -4750,6 +4780,7 @@ grokdeclarator (const struct c_declarator *declarator, bool bitfield = width != NULL; tree element_type; struct c_arg_info *arg_info = 0; + addr_space_t as1, as2, address_space; location_t loc = UNKNOWN_LOCATION; const char *errmsg; tree expr_dummy; @@ -4880,6 +4911,10 @@ grokdeclarator (const struct c_declarator *declarator, constp = declspecs->const_p + TYPE_READONLY (element_type); restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); + as1 = declspecs->address_space; + as2 = TYPE_ADDR_SPACE (element_type); + address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; + if (pedantic && !flag_isoc99) { if (constp > 1) @@ -4889,11 +4924,17 @@ grokdeclarator (const struct c_declarator *declarator, if (volatilep > 1) pedwarn (loc, OPT_pedantic, "duplicate %<volatile%>"); } + + if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) + error_at (loc, "conflicting named address spaces (%s vs %s)", + c_addr_space_name (as1), c_addr_space_name (as2)); + if (!flag_gen_aux_info && (TYPE_QUALS (element_type))) type = TYPE_MAIN_VARIANT (type); type_quals = ((constp ? TYPE_QUAL_CONST : 0) | (restrictp ? TYPE_QUAL_RESTRICT : 0) - | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + | (volatilep ? TYPE_QUAL_VOLATILE : 0) + | ENCODE_QUAL_ADDR_SPACE (address_space)); /* Warn about storage classes that are invalid for certain kinds of declarations (parameters, typenames, etc.). */ @@ -5309,7 +5350,14 @@ grokdeclarator (const struct c_declarator *declarator, it, but here we want to make sure we don't ever modify the shared type, so we gcc_assert (itype) below. */ - type = build_array_type (type, itype); + { + addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) + type = build_qualified_type (type, + ENCODE_QUAL_ADDR_SPACE (as)); + + type = build_array_type (type, itype); + } if (type != error_mark_node) { @@ -5515,6 +5563,59 @@ grokdeclarator (const struct c_declarator *declarator, /* Now TYPE has the actual type, apart from any qualifiers in TYPE_QUALS. */ + /* Warn about address space used for things other than static memory or + pointers. */ + address_space = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (address_space)) + { + if (decl_context == NORMAL) + { + switch (storage_class) + { + case csc_auto: + error ("%qs combined with %<auto%> qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_register: + error ("%qs combined with %<register%> qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_none: + if (current_function_scope) + { + error ("%qs specified for auto variable %qE", + c_addr_space_name (address_space), name); + break; + } + break; + case csc_static: + case csc_extern: + case csc_typedef: + break; + default: + gcc_unreachable (); + } + } + else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) + { + if (name) + error ("%qs specified for parameter %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for unnamed parameter", + c_addr_space_name (address_space)); + } + else if (decl_context == FIELD) + { + if (name) + error ("%qs specified for structure field %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for structure field", + c_addr_space_name (address_space)); + } + } + /* Check the type and width of a bit-field. */ if (bitfield) check_bitfield_type_and_width (&type, width, name); @@ -8297,9 +8398,29 @@ build_null_declspecs (void) ret->volatile_p = false; ret->restrict_p = false; ret->saturating_p = false; + ret->address_space = ADDR_SPACE_GENERIC; return ret; } +/* Add the address space ADDRSPACE to the declaration specifiers + SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) +{ + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + + if (!ADDR_SPACE_GENERIC_P (specs->address_space) + && specs->address_space != as) + error ("incompatible address space qualifiers %qs and %qs", + c_addr_space_name (as), + c_addr_space_name (specs->address_space)); + else + specs->address_space = as; + return specs; +} + /* Add the type qualifier QUAL to the declaration specifiers SPECS, returning SPECS. */ diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 767d97fbe58..1a6012e9128 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -72,6 +72,10 @@ c_parse_init (void) tree id; int mask = 0; + /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in + the c_token structure. */ + gcc_assert (RID_MAX <= 255); + mask |= D_CXXONLY; if (!flag_isoc99) mask |= D_C99; @@ -132,6 +136,8 @@ typedef enum c_id_kind { C_ID_TYPENAME, /* An identifier declared as an Objective-C class name. */ C_ID_CLASSNAME, + /* An address space identifier. */ + C_ID_ADDRSPACE, /* Not an identifier. */ C_ID_NONE } c_id_kind; @@ -226,6 +232,13 @@ c_lex_one_token (c_parser *parser, c_token *token) "identifier %qE conflicts with C++ keyword", token->value); } + else if (rid_code >= RID_FIRST_ADDR_SPACE + && rid_code <= RID_LAST_ADDR_SPACE) + { + token->id_kind = C_ID_ADDRSPACE; + token->keyword = rid_code; + break; + } else if (c_dialect_objc ()) { if (!objc_is_reserved_word (token->value) @@ -352,6 +365,8 @@ c_token_starts_typename (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -422,6 +437,8 @@ c_token_starts_declspecs (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -1411,6 +1428,7 @@ c_parser_asm_definition (c_parser *parser) const restrict volatile + address-space-qualifier (restrict is new in C99.) @@ -1419,6 +1437,12 @@ c_parser_asm_definition (c_parser *parser) declaration-specifiers: attributes declaration-specifiers[opt] + type-qualifier: + address-space + + address-space: + identifier recognized by the target + storage-class-specifier: __thread @@ -1459,6 +1483,17 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, { tree value = c_parser_peek_token (parser)->value; c_id_kind kind = c_parser_peek_token (parser)->id_kind; + + if (kind == C_ID_ADDRSPACE) + { + addr_space_t as + = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (specs, as); + c_parser_consume_token (parser); + attrs_ok = true; + continue; + } + /* This finishes the specifiers unless a type name is OK, it is declared as a type name and a type name hasn't yet been seen. */ @@ -5775,6 +5810,14 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, finish_init (); maybe_warn_string_init (type, init); + if (type != error_mark_node + && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) + && current_function_decl) + { + error ("compound literal qualified by address-space qualifier"); + type = error_mark_node; + } + if (!flag_isoc99) pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals"); non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) diff --git a/gcc/c-pretty-print.c b/gcc/c-pretty-print.c index c4e6e96c296..01770014c21 100644 --- a/gcc/c-pretty-print.c +++ b/gcc/c-pretty-print.c @@ -225,7 +225,11 @@ pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t) const restrict -- C99 __restrict__ -- GNU C - volatile */ + address-space-qualifier -- GNU C + volatile + + address-space-qualifier: + identifier -- GNU C */ void pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) @@ -245,6 +249,12 @@ pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) pp_c_cv_qualifier (pp, "volatile"); if (qualifiers & TYPE_QUAL_RESTRICT) pp_c_cv_qualifier (pp, flag_isoc99 ? "restrict" : "__restrict__"); + + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t))) + { + const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t)); + pp_c_identifier (pp, as); + } } /* pointer: diff --git a/gcc/c-tree.h b/gcc/c-tree.h index c7490e461a3..e71771ae840 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -277,6 +277,8 @@ struct c_declspecs { BOOL_BITFIELD restrict_p : 1; /* Whether "_Sat" was specified. */ BOOL_BITFIELD saturating_p : 1; + /* The address space that the declaration belongs to. */ + addr_space_t address_space; }; /* The various kinds of declarators in C. */ @@ -476,6 +478,8 @@ extern struct c_declspecs *declspecs_add_type (location_t, struct c_typespec); extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree); extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *, + addr_space_t); extern struct c_declspecs *finish_declspecs (struct c_declspecs *); /* in c-objc-common.c */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 3274e0730ec..c7d2bc8da22 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -284,14 +284,55 @@ c_type_promotes_to (tree type) return type; } +/* Return true if between two named address spaces, whether there is a superset + named address space that encompasses both address spaces. If there is a + superset, return which address space is the superset. */ + +static bool +addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common) +{ + if (as1 == as2) + { + *common = as1; + return true; + } + else if (targetm.addr_space.subset_p (as1, as2)) + { + *common = as2; + return true; + } + else if (targetm.addr_space.subset_p (as2, as1)) + { + *common = as1; + return true; + } + else + return false; +} + /* Return a variant of TYPE which has all the type qualifiers of LIKE as well as those of TYPE. */ static tree qualify_type (tree type, tree like) { + addr_space_t as_type = TYPE_ADDR_SPACE (type); + addr_space_t as_like = TYPE_ADDR_SPACE (like); + addr_space_t as_common; + + /* If the two named address spaces are different, determine the common + superset address space. If there isn't one, raise an error. */ + if (!addr_space_superset (as_type, as_like, &as_common)) + { + as_common = as_type; + error ("%qT and %qT are in disjoint named address spaces", + type, like); + } + return c_build_qualified_type (type, - TYPE_QUALS (type) | TYPE_QUALS (like)); + TYPE_QUALS_NO_ADDR_SPACE (type) + | TYPE_QUALS_NO_ADDR_SPACE (like) + | ENCODE_QUAL_ADDR_SPACE (as_common)); } /* Return true iff the given tree T is a variable length array. */ @@ -371,7 +412,8 @@ composite_type (tree t1, tree t2) bool t1_complete, t2_complete; /* We should not have any type quals on arrays at all. */ - gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2)); + gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) + && !TYPE_QUALS_NO_ADDR_SPACE (t2)); t1_complete = COMPLETE_TYPE_P (t1); t2_complete = COMPLETE_TYPE_P (t2); @@ -585,6 +627,8 @@ common_pointer_type (tree t1, tree t2) tree pointed_to_2, mv2; tree target; unsigned target_quals; + addr_space_t as1, as2, as_common; + int quals1, quals2; /* Save time if the two types are the same. */ @@ -616,10 +660,24 @@ common_pointer_type (tree t1, tree t2) /* For function types do not merge const qualifiers, but drop them if used inconsistently. The middle-end uses these to mark const and noreturn functions. */ + quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1); + quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2); + if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE) - target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2); + target_quals = (quals1 & quals2); else - target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2); + target_quals = (quals1 | quals2); + + /* If the two named address spaces are different, determine the common + superset address space. This is guaranteed to exist due to the + assumption that comp_target_type returned non-zero. */ + as1 = TYPE_ADDR_SPACE (pointed_to_1); + as2 = TYPE_ADDR_SPACE (pointed_to_2); + if (!addr_space_superset (as1, as2, &as_common)) + gcc_unreachable (); + + target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); + t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); return build_type_attribute_variant (t1, attributes); } @@ -1103,20 +1161,28 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p) return attrval == 2 && val == 1 ? 2 : val; } -/* Return 1 if TTL and TTR are pointers to types that are equivalent, - ignoring their qualifiers. */ +/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring + their qualifiers, except for named address spaces. If the pointers point to + different named addresses, then we must determine if one address space is a + subset of the other. */ static int comp_target_types (location_t location, tree ttl, tree ttr) { int val; - tree mvl, mvr; + tree mvl = TREE_TYPE (ttl); + tree mvr = TREE_TYPE (ttr); + addr_space_t asl = TYPE_ADDR_SPACE (mvl); + addr_space_t asr = TYPE_ADDR_SPACE (mvr); + addr_space_t as_common; bool enum_and_int_p; + /* Fail if pointers point to incompatible address spaces. */ + if (!addr_space_superset (asl, asr, &as_common)) + return 0; + /* Do not lose qualifiers on element types of array types that are pointer targets by taking their TYPE_MAIN_VARIANT. */ - mvl = TREE_TYPE (ttl); - mvr = TREE_TYPE (ttr); if (TREE_CODE (mvl) != ARRAY_TYPE) mvl = TYPE_MAIN_VARIANT (mvl); if (TREE_CODE (mvr) != ARRAY_TYPE) @@ -3063,11 +3129,43 @@ static tree pointer_diff (location_t loc, tree op0, tree op1) { tree restype = ptrdiff_type_node; + tree result, inttype; + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0))); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1))); tree target_type = TREE_TYPE (TREE_TYPE (op0)); tree con0, con1, lit0, lit1; tree orig_op1 = op1; + /* If the operands point into different address spaces, we need to + explicitly convert them to pointers into the common address space + before we can subtract the numerical address values. */ + if (as0 != as1) + { + addr_space_t as_common; + tree common_type; + + /* Determine the common superset address space. This is guaranteed + to exist because the caller verified that comp_target_types + returned non-zero. */ + if (!addr_space_superset (as0, as1, &as_common)) + gcc_unreachable (); + + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1)); + op0 = convert (common_type, op0); + op1 = convert (common_type, op1); + } + + /* Determine integer type to perform computations in. This will usually + be the same as the result type (ptrdiff_t), but may need to be a wider + type if pointers for the address space are wider than ptrdiff_t. */ + if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0))) + inttype = lang_hooks.types.type_for_size + (TYPE_PRECISION (TREE_TYPE (op0)), 0); + else + inttype = restype; + + if (TREE_CODE (target_type) == VOID_TYPE) pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, "pointer of type %<void *%> used in subtraction"); @@ -3125,8 +3223,8 @@ pointer_diff (location_t loc, tree op0, tree op1) in case restype is a short type. */ op0 = build_binary_op (loc, - MINUS_EXPR, convert (restype, op0), - convert (restype, op1), 0); + MINUS_EXPR, convert (inttype, op0), + convert (inttype, op1), 0); /* This generates an error if op1 is pointer to incomplete type. */ if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) error_at (loc, "arithmetic on pointer to an incomplete type"); @@ -3135,8 +3233,11 @@ pointer_diff (location_t loc, tree op0, tree op1) op1 = c_size_in_bytes (target_type); /* Divide by the size, in easiest possible way. */ - return fold_build2_loc (loc, EXACT_DIV_EXPR, restype, - op0, convert (restype, op1)); + result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype, + op0, convert (inttype, op1)); + + /* Convert to final result type if necessary. */ + return convert (restype, result); } /* Construct and perhaps optimize a tree representation @@ -3956,12 +4057,22 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, } else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) { + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2)); + addr_space_t as_common; + if (comp_target_types (colon_loc, type1, type2)) result_type = common_pointer_type (type1, type2); else if (null_pointer_constant_p (orig_op1)) - result_type = qualify_type (type2, type1); + result_type = type2; else if (null_pointer_constant_p (orig_op2)) - result_type = qualify_type (type1, type2); + result_type = type1; + else if (!addr_space_superset (as1, as2, &as_common)) + { + error_at (colon_loc, "pointers to disjoint address spaces " + "used in conditional expression"); + return error_mark_node; + } else if (VOID_TYPE_P (TREE_TYPE (type1))) { if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) @@ -3982,10 +4093,13 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, } else { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + if (!objc_ok) pedwarn (colon_loc, 0, "pointer type mismatch in conditional expression"); - result_type = build_pointer_type (void_type_node); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); } } else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) @@ -4144,7 +4258,8 @@ build_compound_expr (location_t loc, tree expr1, tree expr2) /* Issue -Wcast-qual warnings when appropriate. TYPE is the type to which we are casting. OTYPE is the type of the expression being cast. Both TYPE and OTYPE are pointer types. -Wcast-qual appeared - on the command line. */ + on the command line. Named address space qualifiers are not handled + here, because they result in different warnings. */ static void handle_warn_cast_qual (tree type, tree otype) @@ -4170,9 +4285,11 @@ handle_warn_cast_qual (tree type, tree otype) taken away. */ if (TREE_CODE (in_otype) == FUNCTION_TYPE && TREE_CODE (in_type) == FUNCTION_TYPE) - added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype)); + added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype)); else - discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type)); + discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_type)); } while (TREE_CODE (in_type) == POINTER_TYPE && TREE_CODE (in_otype) == POINTER_TYPE); @@ -4321,6 +4438,36 @@ build_c_cast (location_t loc, tree type, tree expr) && TREE_CODE (otype) == POINTER_TYPE) handle_warn_cast_qual (type, otype); + /* Warn about conversions between pointers to disjoint + address spaces. */ + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && !null_pointer_constant_p (value)) + { + addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype)); + addr_space_t as_common; + + if (!addr_space_superset (as_to, as_from, &as_common)) + { + if (ADDR_SPACE_GENERIC_P (as_from)) + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint generic address space pointer", + c_addr_space_name (as_to)); + + else if (ADDR_SPACE_GENERIC_P (as_to)) + warning_at (loc, 0, "cast to generic address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_from)); + + else + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_to), + c_addr_space_name (as_from)); + } + } + /* Warn about possible alignment problems. */ if (STRICT_ALIGNMENT && TREE_CODE (type) == POINTER_TYPE @@ -4915,7 +5062,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE " "makes qualified function " @@ -4929,7 +5077,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, G_("return makes qualified function " "pointer from unqualified")); } - else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE discards " "qualifiers from pointer target type"), @@ -4962,6 +5111,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, tree mvr = ttr; bool is_opaque_pointer; int target_cmp = 0; /* Cache comp_target_types () result. */ + addr_space_t asl; + addr_space_t asr; if (TREE_CODE (mvl) != ARRAY_TYPE) mvl = TYPE_MAIN_VARIANT (mvl); @@ -4982,6 +5133,36 @@ convert_for_assignment (location_t location, tree type, tree rhs, "request for implicit conversion " "from %qT to %qT not permitted in C++", rhstype, type); + /* See if the pointers point to incompatible address spaces. */ + asl = TYPE_ADDR_SPACE (ttl); + asr = TYPE_ADDR_SPACE (ttr); + if (!null_pointer_constant_p (rhs) + && asr != asl && !targetm.addr_space.subset_p (asr, asl)) + { + switch (errtype) + { + case ic_argpass: + error_at (location, "passing argument %d of %qE from pointer to " + "non-enclosed address space", parmnum, rname); + break; + case ic_assign: + error_at (location, "assignment from pointer to " + "non-enclosed address space"); + break; + case ic_init: + error_at (location, "initialization from pointer to " + "non-enclosed address space"); + break; + case ic_return: + error_at (location, "return from pointer to " + "non-enclosed address space"); + break; + default: + gcc_unreachable (); + } + return error_mark_node; + } + /* Check if the right-hand side has a format attribute but the left-hand side doesn't. */ if (warn_missing_format_attribute @@ -5045,7 +5226,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, else if (TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttl) != FUNCTION_TYPE) { - if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) { /* Types differing only by the presence of the 'volatile' qualifier are acceptable if the 'volatile' has been added @@ -5085,7 +5267,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, that say the function will not do certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE makes " "qualified function pointer " @@ -9193,24 +9376,34 @@ build_binary_op (location_t location, enum tree_code code, { tree tt0 = TREE_TYPE (type0); tree tt1 = TREE_TYPE (type1); + addr_space_t as0 = TYPE_ADDR_SPACE (tt0); + addr_space_t as1 = TYPE_ADDR_SPACE (tt1); + addr_space_t as_common = ADDR_SPACE_GENERIC; + /* Anything compares with void *. void * compares with anything. Otherwise, the targets must be compatible and both must be object or both incomplete. */ if (comp_target_types (location, type0, type1)) result_type = common_pointer_type (type0, type1); + else if (null_pointer_constant_p (orig_op0)) + result_type = type1; + else if (null_pointer_constant_p (orig_op1)) + result_type = type0; + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } else if (VOID_TYPE_P (tt0)) { - /* op0 != orig_op0 detects the case of something - whose value is 0 but which isn't a valid null ptr const. */ - if (pedantic && !null_pointer_constant_p (orig_op0) - && TREE_CODE (tt1) == FUNCTION_TYPE) + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) pedwarn (location, OPT_pedantic, "ISO C forbids " "comparison of %<void *%> with function pointer"); } else if (VOID_TYPE_P (tt1)) { - if (pedantic && !null_pointer_constant_p (orig_op1) - && TREE_CODE (tt0) == FUNCTION_TYPE) + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) pedwarn (location, OPT_pedantic, "ISO C forbids " "comparison of %<void *%> with function pointer"); } @@ -9221,7 +9414,11 @@ build_binary_op (location_t location, enum tree_code code, "comparison of distinct pointer types lacks a cast"); if (result_type == NULL_TREE) - result_type = ptr_type_node; + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } } else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) { @@ -9265,6 +9462,10 @@ build_binary_op (location_t location, enum tree_code code, short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0)); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as_common; + if (comp_target_types (location, type0, type1)) { result_type = common_pointer_type (type0, type1); @@ -9276,9 +9477,17 @@ build_binary_op (location_t location, enum tree_code code, pedwarn (location, OPT_pedantic, "ISO C forbids " "ordered comparisons of pointers to functions"); } + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } else { - result_type = ptr_type_node; + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); pedwarn (location, 0, "comparison of distinct pointer types lacks a cast"); } diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index cfb19b60275..ffe36e45a9e 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -958,7 +958,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) if (NOTE_INSN_BASIC_BLOCK_P (i1) && NOTE_INSN_BASIC_BLOCK_P (i2)) return true; - p1 = PATTERN (i1); + p1 = PATTERN (i1); p2 = PATTERN (i2); if (GET_CODE (p1) != GET_CODE (p2)) @@ -1814,6 +1814,24 @@ try_crossjump_bb (int mode, basic_block bb) return changed; } +/* Return true if BB contains just bb note, or bb note followed + by only DEBUG_INSNs. */ + +static bool +trivially_empty_bb_p (basic_block bb) +{ + rtx insn = BB_END (bb); + + while (1) + { + if (insn == BB_HEAD (bb)) + return true; + if (!DEBUG_INSN_P (insn)) + return false; + insn = PREV_INSN (insn); + } +} + /* Do simple CFG optimizations - basic block merging, simplifying of jump instructions etc. Return nonzero if changes were made. */ @@ -1865,14 +1883,10 @@ try_optimize_cfg (int mode) __builtin_unreachable (). */ if (EDGE_COUNT (b->preds) == 0 || (EDGE_COUNT (b->succs) == 0 - && BB_HEAD (b) == BB_END (b) + && trivially_empty_bb_p (b) && single_succ_edge (ENTRY_BLOCK_PTR)->dest != b)) { c = b->prev_bb; - if (dump_file) - fprintf (dump_file, "Deleting block %i.\n", - b->index); - delete_basic_block (b); if (!(mode & CLEANUP_CFGLAYOUT)) changed = true; diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index be46028fa58..fdc4de586ef 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2235,6 +2235,9 @@ expand_debug_expr (tree exp) rtx op0 = NULL_RTX, op1 = NULL_RTX, op2 = NULL_RTX; enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp)); + addr_space_t as; + enum machine_mode address_mode; + enum machine_mode pointer_mode; switch (TREE_CODE_CLASS (TREE_CODE (exp))) { @@ -2428,20 +2431,29 @@ expand_debug_expr (tree exp) if (!op0) return NULL; - gcc_assert (GET_MODE (op0) == Pmode - || GET_MODE (op0) == ptr_mode + if (POINTER_TYPE_P (TREE_TYPE (exp))) + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + else + as = ADDR_SPACE_GENERIC; + + address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.addr_space.pointer_mode (as); + + gcc_assert (GET_MODE (op0) == address_mode + || GET_MODE (op0) == pointer_mode || GET_CODE (op0) == CONST_INT || GET_CODE (op0) == CONST_DOUBLE); if (TREE_CODE (exp) == ALIGN_INDIRECT_REF) { int align = TYPE_ALIGN_UNIT (TREE_TYPE (exp)); - op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align)); + op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align)); } op0 = gen_rtx_MEM (mode, op0); set_mem_attributes (op0, exp, 0); + set_mem_addr_space (op0, as); return op0; @@ -2455,14 +2467,19 @@ expand_debug_expr (tree exp) if (!op0) return NULL; - gcc_assert (GET_MODE (op0) == Pmode - || GET_MODE (op0) == ptr_mode + as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); + address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.addr_space.pointer_mode (as); + + gcc_assert (GET_MODE (op0) == address_mode + || GET_MODE (op0) == pointer_mode || GET_CODE (op0) == CONST_INT || GET_CODE (op0) == CONST_DOUBLE); op0 = gen_rtx_MEM (mode, op0); set_mem_attributes (op0, exp, 0); + set_mem_addr_space (op0, as); return op0; diff --git a/gcc/combine.c b/gcc/combine.c index 129cd4dff39..2311755691c 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -4159,9 +4159,12 @@ find_split_point (rtx *loc, rtx insn) if (GET_CODE (XEXP (x, 0)) == CONST || GET_CODE (XEXP (x, 0)) == SYMBOL_REF) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + SUBST (XEXP (x, 0), - gen_rtx_LO_SUM (Pmode, - gen_rtx_HIGH (Pmode, XEXP (x, 0)), + gen_rtx_LO_SUM (address_mode, + gen_rtx_HIGH (address_mode, XEXP (x, 0)), XEXP (x, 0))); return &XEXP (XEXP (x, 0), 0); } @@ -4174,7 +4177,8 @@ find_split_point (rtx *loc, rtx insn) it will not remain in the result. */ if (GET_CODE (XEXP (x, 0)) == PLUS && CONST_INT_P (XEXP (XEXP (x, 0), 1)) - && ! memory_address_p (GET_MODE (x), XEXP (x, 0))) + && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), + MEM_ADDR_SPACE (x))) { rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER]; rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg, @@ -4197,8 +4201,9 @@ find_split_point (rtx *loc, rtx insn) && NONJUMP_INSN_P (NEXT_INSN (seq)) && GET_CODE (PATTERN (NEXT_INSN (seq))) == SET && SET_DEST (PATTERN (NEXT_INSN (seq))) == reg - && memory_address_p (GET_MODE (x), - SET_SRC (PATTERN (NEXT_INSN (seq))))) + && memory_address_addr_space_p + (GET_MODE (x), SET_SRC (PATTERN (NEXT_INSN (seq))), + MEM_ADDR_SPACE (x))) { rtx src1 = SET_SRC (PATTERN (seq)); rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq))); @@ -4237,7 +4242,8 @@ find_split_point (rtx *loc, rtx insn) /* If we have a PLUS whose first operand is complex, try computing it separately by making a split there. */ if (GET_CODE (XEXP (x, 0)) == PLUS - && ! memory_address_p (GET_MODE (x), XEXP (x, 0)) + && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), + MEM_ADDR_SPACE (x)) && ! OBJECT_P (XEXP (XEXP (x, 0), 0)) && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0))))) diff --git a/gcc/config.gcc b/gcc/config.gcc index 7666dd61861..4f388babe6a 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -287,7 +287,7 @@ i[34567]86-*-*) extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h - immintrin.h x86intrin.h avxintrin.h + immintrin.h x86intrin.h avxintrin.h ia32intrin.h cross-stdarg.h" ;; x86_64-*-*) @@ -2077,6 +2077,10 @@ rs6000-ibm-aix[6789].* | powerpc-ibm-aix[6789].*) use_gcc_stdint=wrap extra_headers=altivec.h ;; +rx-*-elf*) + tm_file="dbxelf.h elfos.h svr4.h newlib-stdint.h ${tm_file} ../../libgcc/config/rx/rx-abi.h" + tmake_file="${tmake_file} rx/t-rx" + ;; s390-*-linux*) tm_file="s390/s390.h dbxelf.h elfos.h svr4.h linux.h glibc-stdint.h s390/linux.h" ;; @@ -2445,7 +2449,7 @@ sparc64-*-netbsd*) spu-*-elf*) tm_file="dbxelf.h elfos.h spu/spu-elf.h spu/spu.h newlib-stdint.h" tmake_file="spu/t-spu-elf" - extra_headers="spu_intrinsics.h spu_internals.h vmx2spu.h spu_mfcio.h vec_types.h" + extra_headers="spu_intrinsics.h spu_internals.h vmx2spu.h spu_mfcio.h vec_types.h spu_cache.h" extra_modes=spu/spu-modes.def c_target_objs="${c_target_objs} spu-c.o" cxx_target_objs="${cxx_target_objs} spu-c.o" diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 4b4353c95ac..f82091a7f36 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -9537,7 +9537,10 @@ mips_restore_gp_from_cprestore_slot (rtx temp) gcc_assert (TARGET_ABICALLS && TARGET_OLDABI && epilogue_completed); if (!cfun->machine->must_restore_gp_when_clobbered_p) - return; + { + emit_note (NOTE_INSN_DELETED); + return; + } if (TARGET_MIPS16) { diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 2d11ed07c5f..5005bf7f0fb 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -1879,7 +1879,7 @@ (set_attr "mode" "SI") (set_attr "length" "12")]) -(define_insn_and_split "<u>mulsidi3_64bit" +(define_insn "<u>mulsidi3_64bit" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) @@ -1887,37 +1887,67 @@ (clobber (match_scratch:DI 4 "=d"))] "TARGET_64BIT && !TARGET_FIX_R4000" "#" - "&& reload_completed" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set (attr "length") + (if_then_else (ne (symbol_ref "ISA_HAS_EXT_INS") (const_int 0)) + (const_int 16) + (const_int 28)))]) + +(define_split + [(set (match_operand:DI 0 "d_operand") + (mult:DI (any_extend:DI (match_operand:SI 1 "d_operand")) + (any_extend:DI (match_operand:SI 2 "d_operand")))) + (clobber (match_operand:TI 3 "hilo_operand")) + (clobber (match_operand:DI 4 "d_operand"))] + "TARGET_64BIT && !TARGET_FIX_R4000 && ISA_HAS_EXT_INS && reload_completed" + [(set (match_dup 3) + (unspec:TI [(mult:DI (any_extend:DI (match_dup 1)) + (any_extend:DI (match_dup 2)))] + UNSPEC_SET_HILO)) + + ;; OP0 <- LO, OP4 <- HI + (set (match_dup 0) (match_dup 5)) + (set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) + + (set (zero_extract:DI (match_dup 0) (const_int 32) (const_int 32)) + (match_dup 4))] + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); }) + +(define_split + [(set (match_operand:DI 0 "d_operand") + (mult:DI (any_extend:DI (match_operand:SI 1 "d_operand")) + (any_extend:DI (match_operand:SI 2 "d_operand")))) + (clobber (match_operand:TI 3 "hilo_operand")) + (clobber (match_operand:DI 4 "d_operand"))] + "TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_EXT_INS && reload_completed" [(set (match_dup 3) (unspec:TI [(mult:DI (any_extend:DI (match_dup 1)) (any_extend:DI (match_dup 2)))] UNSPEC_SET_HILO)) - ;; OP4 <- LO, OP0 <- HI - (set (match_dup 4) (match_dup 5)) - (set (match_dup 0) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) + ;; OP0 <- LO, OP4 <- HI + (set (match_dup 0) (match_dup 5)) + (set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) ;; Zero-extend OP4. - (set (match_dup 4) - (ashift:DI (match_dup 4) + (set (match_dup 0) + (ashift:DI (match_dup 0) (const_int 32))) - (set (match_dup 4) - (lshiftrt:DI (match_dup 4) + (set (match_dup 0) + (lshiftrt:DI (match_dup 0) (const_int 32))) ;; Shift OP0 into place. - (set (match_dup 0) - (ashift:DI (match_dup 0) + (set (match_dup 4) + (ashift:DI (match_dup 4) (const_int 32))) ;; OR the two halves together (set (match_dup 0) (ior:DI (match_dup 0) (match_dup 4)))] - { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); } - [(set_attr "type" "imul") - (set_attr "mode" "SI") - (set_attr "length" "24")]) + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); }) (define_insn "<u>mulsidi3_64bit_hilo" [(set (match_operand:TI 0 "register_operand" "=x") diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md index e1cb4573688..7430dd32b78 100644 --- a/gcc/config/mips/predicates.md +++ b/gcc/config/mips/predicates.md @@ -119,6 +119,10 @@ (and (match_code "reg") (match_test "REGNO (op) == LO_REGNUM"))) +(define_predicate "hilo_operand" + (and (match_code "reg") + (match_test "MD_REG_P (REGNO (op))"))) + (define_predicate "fcc_reload_operand" (and (match_code "reg,subreg") (match_test "ST_REG_P (true_regnum (op))"))) diff --git a/gcc/config/rx/constraints.md b/gcc/config/rx/constraints.md new file mode 100644 index 00000000000..f15b586afb5 --- /dev/null +++ b/gcc/config/rx/constraints.md @@ -0,0 +1,81 @@ +;; Constraint definitions for Renesas RX. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. +;; +;; 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 3, 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 COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + + +(define_constraint "Symbol" + "@internal Constraint on the type of rtx allowed in call insns" + (match_test "GET_CODE (op) == SYMBOL_REF") +) + + +(define_constraint "Int08" + "@internal A signed or unsigned 8-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 8), (1 << 8) - 1)") + ) +) + +(define_constraint "Sint08" + "@internal A signed 8-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 7), (1 << 7) - 1)") + ) +) + +(define_constraint "Sint16" + "@internal A signed 16-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 15), (1 << 15) - 1)") + ) +) + +(define_constraint "Sint24" + "@internal A signed 24-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 23), (1 << 23) - 1)") + ) +) + +;; This constraint is used by the SUBSI3 pattern because the +;; RX SUB instruction can only take a 4-bit unsigned integer +;; value. +(define_constraint "Uint04" + "@internal An unsigned 4-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 0, 15)") + ) +) + +;; This is used in arithmetic and logic instructions for +;; a source operand that lies in memory and which satisfies +;; rx_restricted_memory_address(). + +(define_memory_constraint "Q" + "A MEM which only uses REG or REG+INT addressing." + (and (match_code "mem") + (ior (match_code "reg" "0") + (and (match_code "plus" "0") + (and (match_code "reg,subreg" "00") + (match_code "const_int" "01") + ) + ) + ) + ) +) diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md new file mode 100644 index 00000000000..75cf8ebaed8 --- /dev/null +++ b/gcc/config/rx/predicates.md @@ -0,0 +1,282 @@ +;; Predicate definitions for Renesas RX. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. +;; +;; 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 3, 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 COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + + + +;; Check that the operand is suitable for a call insn. +;; Only registers and symbol refs are allowed. + +(define_predicate "rx_call_operand" + (match_code "symbol_ref,reg") +) + +;; For sibcall operations we can only use a symbolic address. + +(define_predicate "rx_symbolic_call_operand" + (match_code "symbol_ref") +) + +;; Check that the operand is suitable for a shift insn +;; Only small integers or a value in a register are permitted. + +(define_predicate "rx_shift_operand" + (match_code "const_int,reg") + { + if (CONST_INT_P (op)) + return IN_RANGE (INTVAL (op), 0, 31); + return true; + } +) + +;; Check that the operand is suitable as the source operand +;; for a logic or arithmeitc instruction. Registers, integers +;; and a restricted subset of memory addresses are allowed. + +(define_predicate "rx_source_operand" + (match_code "const_int,reg,mem") + { + if (CONST_INT_P (op)) + return rx_is_legitimate_constant (op); + + if (! MEM_P (op)) + return true; + + /* Do not allow size conversions whilst accessing memory. */ + if (GET_MODE (op) != mode) + return false; + + return rx_is_restricted_memory_address (XEXP (op, 0), mode); + } +) + +;; Check that the operand is suitable as the source operand +;; for a comparison instruction. This is the same as +;; rx_source_operand except that SUBREGs are allowed but +;; CONST_INTs are not. + +(define_predicate "rx_compare_operand" + (match_code "subreg,reg,mem") + { + if (GET_CODE (op) == SUBREG) + return REG_P (XEXP (op, 0)); + + if (! MEM_P (op)) + return true; + + return rx_is_restricted_memory_address (XEXP (op, 0), mode); + } +) + +;; Return true if OP is a store multiple operation. This looks like: +;; +;; [(set (SP) (MINUS (SP) (INT))) +;; (set (MEM (SP)) (REG)) +;; (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated} +;; ] + +(define_special_predicate "rx_store_multiple_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int src_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != MINUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! MEM_P (SET_DEST (element)) + || ! REG_P (XEXP (SET_DEST (element), 0)) + || REGNO (XEXP (SET_DEST (element), 0)) != SP_REG + || ! REG_P (SET_SRC (element))) + return false; + + src_regno = REGNO (SET_SRC (element)); + + /* Check that the remaining elements use SP-<disp> + addressing and incremental register numbers. */ + for (i = 2; i < count; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || REGNO (SET_SRC (element)) != src_regno + (i - 1) + || ! MEM_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS + || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + return true; +}) + +;; Return true if OP is a load multiple operation. +;; This looks like: +;; [(set (SP) (PLUS (SP) (INT))) +;; (set (REG) (MEM (SP))) +;; (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated} +;; ] + +(define_special_predicate "rx_load_multiple_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != PLUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || ! MEM_P (SET_SRC (element)) + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG) + return false; + + dest_regno = REGNO (SET_DEST (element)); + + /* Check that the remaining elements use SP+<disp> + addressing and incremental register numbers. */ + for (i = 2; i < count; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || REGNO (SET_DEST (element)) != dest_regno + (i - 1) + || ! MEM_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS + || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + return true; +}) + +;; Return true if OP is a pop-and-return load multiple operation. +;; This looks like: +;; [(set (SP) (PLUS (SP) (INT))) +;; (set (REG) (MEM (SP))) +;; (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated} +;; (return) +;; ] + +(define_special_predicate "rx_rtsd_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != PLUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || ! MEM_P (SET_SRC (element)) + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG) + return false; + + dest_regno = REGNO (SET_DEST (element)); + + /* Check that the remaining elements, if any, and except + for the last one, use SP+<disp> addressing and incremental + register numbers. */ + for (i = 2; i < count - 1; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || REGNO (SET_DEST (element)) != dest_regno + (i - 1) + || ! MEM_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS + || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + + /* The last element must be a RETURN. */ + element = XVECEXP (op, 0, count - 1); + return GET_CODE (element) == RETURN; +}) diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h new file mode 100644 index 00000000000..5c37fe0a83c --- /dev/null +++ b/gcc/config/rx/rx-protos.h @@ -0,0 +1,52 @@ +/* Exported function prototypes from the Renesas RX backend. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +#ifndef GCC_RX_PROTOS_H +#define GCC_RX_PROTOS_H + +/* A few abbreviations to make the prototypes shorter. */ +#define Mmode enum machine_mode +#define Fargs CUMULATIVE_ARGS + +extern void rx_conditional_register_usage (void); +extern void rx_expand_prologue (void); +extern int rx_initial_elimination_offset (int, int); + +#ifdef RTX_CODE +extern void rx_emit_stack_popm (rtx *, bool); +extern void rx_emit_stack_pushm (rtx *); +extern void rx_expand_epilogue (bool); +extern bool rx_expand_insv (rtx *); +extern const char * rx_gen_cond_branch_template (rtx, bool); +extern char * rx_gen_move_template (rtx *, bool); +extern bool rx_is_legitimate_constant (rtx); +extern bool rx_is_mode_dependent_addr (rtx); +extern bool rx_is_restricted_memory_address (rtx, Mmode); +extern void rx_notice_update_cc (rtx body, rtx insn); +extern void rx_print_operand (FILE *, rtx, int); +extern void rx_print_operand_address (FILE *, rtx); +#endif + +#ifdef TREE_CODE +extern unsigned int rx_function_arg_size (Mmode, const_tree); +extern struct rtx_def * rx_function_arg (Fargs *, Mmode, const_tree, bool); +#endif + +#endif /* GCC_RX_PROTOS_H */ diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c new file mode 100644 index 00000000000..cf2b098e83c --- /dev/null +++ b/gcc/config/rx/rx.c @@ -0,0 +1,2363 @@ +/* Subroutines used for code generation on Renesas RX processors. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* To Do: + + * Re-enable memory-to-memory copies and fix up reload. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "optabs.h" +#include "libfuncs.h" +#include "recog.h" +#include "toplev.h" +#include "reload.h" +#include "df.h" +#include "ggc.h" +#include "tm_p.h" +#include "debug.h" +#include "target.h" +#include "target-def.h" +#include "langhooks.h" + +/* Return true if OP is a reference to an object in a small data area. */ + +static bool +rx_small_data_operand (rtx op) +{ + if (rx_small_data_limit == 0) + return false; + + if (GET_CODE (op) == SYMBOL_REF) + return SYMBOL_REF_SMALL_P (op); + + return false; +} + +static bool +rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED) +{ + if (RTX_OK_FOR_BASE (x, strict)) + /* Register Indirect. */ + return true; + + if (GET_MODE_SIZE (mode) == 4 + && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)) + /* Pre-decrement Register Indirect or + Post-increment Register Indirect. */ + return RTX_OK_FOR_BASE (XEXP (x, 0), strict); + + if (GET_CODE (x) == PLUS) + { + rtx arg1 = XEXP (x, 0); + rtx arg2 = XEXP (x, 1); + rtx index = NULL_RTX; + + if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, strict)) + index = arg2; + else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, strict)) + index = arg1; + else + return false; + + switch (GET_CODE (index)) + { + case CONST_INT: + { + /* Register Relative: REG + INT. + Only positive, mode-aligned, mode-sized + displacements are allowed. */ + HOST_WIDE_INT val = INTVAL (index); + int factor; + + if (val < 0) + return false; + + switch (GET_MODE_SIZE (mode)) + { + default: + case 4: factor = 4; break; + case 2: factor = 2; break; + case 1: factor = 1; break; + } + + if (val > (65535 * factor)) + return false; + return (val % factor) == 0; + } + + case REG: + /* Unscaled Indexed Register Indirect: REG + REG + Size has to be "QI", REG has to be valid. */ + return GET_MODE_SIZE (mode) == 1 && RTX_OK_FOR_BASE (index, strict); + + case MULT: + { + /* Scaled Indexed Register Indirect: REG + (REG * FACTOR) + Factor has to equal the mode size, REG has to be valid. */ + rtx factor; + + factor = XEXP (index, 1); + index = XEXP (index, 0); + + return REG_P (index) + && RTX_OK_FOR_BASE (index, strict) + && CONST_INT_P (factor) + && GET_MODE_SIZE (mode) == INTVAL (factor); + } + + default: + return false; + } + } + + /* Small data area accesses turn into register relative offsets. */ + return rx_small_data_operand (x); +} + +/* Returns TRUE for simple memory addreses, ie ones + that do not involve register indirect addressing + or pre/post increment/decrement. */ + +bool +rx_is_restricted_memory_address (rtx mem, enum machine_mode mode) +{ + rtx base, index; + + if (! rx_is_legitimate_address + (mode, mem, reload_in_progress || reload_completed)) + return false; + + switch (GET_CODE (mem)) + { + case REG: + /* Simple memory addresses are OK. */ + return true; + + case PRE_DEC: + case POST_INC: + return false; + + case PLUS: + /* Only allow REG+INT addressing. */ + base = XEXP (mem, 0); + index = XEXP (mem, 1); + + return RX_REG_P (base) && CONST_INT_P (index); + + case SYMBOL_REF: + /* Can happen when small data is being supported. + Assume that it will be resolved into GP+INT. */ + return true; + + default: + gcc_unreachable (); + } +} + +bool +rx_is_mode_dependent_addr (rtx addr) +{ + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + switch (GET_CODE (addr)) + { + /* --REG and REG++ only work in SImode. */ + case PRE_DEC: + case POST_INC: + return true; + + case MINUS: + case PLUS: + if (! REG_P (XEXP (addr, 0))) + return true; + + addr = XEXP (addr, 1); + + switch (GET_CODE (addr)) + { + case REG: + /* REG+REG only works in SImode. */ + return true; + + case CONST_INT: + /* REG+INT is only mode independent if INT is a + multiple of 4, positive and will fit into 8-bits. */ + if (((INTVAL (addr) & 3) == 0) + && IN_RANGE (INTVAL (addr), 4, 252)) + return false; + return true; + + case SYMBOL_REF: + case LABEL_REF: + return true; + + case MULT: + gcc_assert (REG_P (XEXP (addr, 0))); + gcc_assert (CONST_INT_P (XEXP (addr, 1))); + /* REG+REG*SCALE is always mode dependent. */ + return true; + + default: + /* Not recognized, so treat as mode dependent. */ + return true; + } + + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case REG: + /* These are all mode independent. */ + return false; + + default: + /* Everything else is unrecognized, + so treat as mode dependent. */ + return true; + } +} + + +/* A C compound statement to output to stdio stream FILE the + assembler syntax for an instruction operand that is a memory + reference whose address is ADDR. */ + +void +rx_print_operand_address (FILE * file, rtx addr) +{ + switch (GET_CODE (addr)) + { + case REG: + fprintf (file, "["); + rx_print_operand (file, addr, 0); + fprintf (file, "]"); + break; + + case PRE_DEC: + fprintf (file, "[-"); + rx_print_operand (file, XEXP (addr, 0), 0); + fprintf (file, "]"); + break; + + case POST_INC: + fprintf (file, "["); + rx_print_operand (file, XEXP (addr, 0), 0); + fprintf (file, "+]"); + break; + + case PLUS: + { + rtx arg1 = XEXP (addr, 0); + rtx arg2 = XEXP (addr, 1); + rtx base, index; + + if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, true)) + base = arg1, index = arg2; + else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, true)) + base = arg2, index = arg1; + else + { + rx_print_operand (file, arg1, 0); + fprintf (file, " + "); + rx_print_operand (file, arg2, 0); + break; + } + + if (REG_P (index) || GET_CODE (index) == MULT) + { + fprintf (file, "["); + rx_print_operand (file, index, 'A'); + fprintf (file, ","); + } + else /* GET_CODE (index) == CONST_INT */ + { + rx_print_operand (file, index, 'A'); + fprintf (file, "["); + } + rx_print_operand (file, base, 0); + fprintf (file, "]"); + break; + } + + case LABEL_REF: + case SYMBOL_REF: + case CONST: + fprintf (file, "#"); + default: + output_addr_const (file, addr); + break; + } +} + +static void +rx_print_integer (FILE * file, HOST_WIDE_INT val) +{ + if (IN_RANGE (val, -64, 64)) + fprintf (file, HOST_WIDE_INT_PRINT_DEC, val); + else + fprintf (file, + TARGET_AS100_SYNTAX + ? "0%" HOST_WIDE_INT_PRINT "xH" : HOST_WIDE_INT_PRINT_HEX, + val); +} + +static bool +rx_assemble_integer (rtx x, unsigned int size, int is_aligned) +{ + const char * op = integer_asm_op (size, is_aligned); + + if (! CONST_INT_P (x)) + return default_assemble_integer (x, size, is_aligned); + + if (op == NULL) + return false; + fputs (op, asm_out_file); + + rx_print_integer (asm_out_file, INTVAL (x)); + fputc ('\n', asm_out_file); + return true; +} + + +int rx_float_compare_mode; + +/* Handles the insertion of a single operand into the assembler output. + The %<letter> directives supported are: + + %A Print an operand without a leading # character. + %B Print an integer comparison name. + %C Print a control register name. + %F Print a condition code flag name. + %H Print high part of a DImode register, integer or address. + %L Print low part of a DImode register, integer or address. + %Q If the operand is a MEM, then correctly generate + register indirect or register relative addressing. */ + +void +rx_print_operand (FILE * file, rtx op, int letter) +{ + switch (letter) + { + case 'A': + /* Print an operand without a leading #. */ + if (MEM_P (op)) + op = XEXP (op, 0); + + switch (GET_CODE (op)) + { + case LABEL_REF: + case SYMBOL_REF: + output_addr_const (file, op); + break; + case CONST_INT: + fprintf (file, "%ld", (long) INTVAL (op)); + break; + default: + rx_print_operand (file, op, 0); + break; + } + break; + + case 'B': + switch (GET_CODE (op)) + { + case LT: fprintf (file, "lt"); break; + case GE: fprintf (file, "ge"); break; + case GT: fprintf (file, "gt"); break; + case LE: fprintf (file, "le"); break; + case GEU: fprintf (file, "geu"); break; + case LTU: fprintf (file, "ltu"); break; + case GTU: fprintf (file, "gtu"); break; + case LEU: fprintf (file, "leu"); break; + case EQ: fprintf (file, "eq"); break; + case NE: fprintf (file, "ne"); break; + default: debug_rtx (op); gcc_unreachable (); + } + break; + + case 'C': + gcc_assert (CONST_INT_P (op)); + switch (INTVAL (op)) + { + case 0: fprintf (file, "psw"); break; + case 2: fprintf (file, "usp"); break; + case 3: fprintf (file, "fpsw"); break; + case 4: fprintf (file, "cpen"); break; + case 8: fprintf (file, "bpsw"); break; + case 9: fprintf (file, "bpc"); break; + case 0xa: fprintf (file, "isp"); break; + case 0xb: fprintf (file, "fintv"); break; + case 0xc: fprintf (file, "intb"); break; + default: + gcc_unreachable (); + } + break; + + case 'F': + gcc_assert (CONST_INT_P (op)); + switch (INTVAL (op)) + { + case 0: case 'c': case 'C': fprintf (file, "C"); break; + case 1: case 'z': case 'Z': fprintf (file, "Z"); break; + case 2: case 's': case 'S': fprintf (file, "S"); break; + case 3: case 'o': case 'O': fprintf (file, "O"); break; + case 8: case 'i': case 'I': fprintf (file, "I"); break; + case 9: case 'u': case 'U': fprintf (file, "U"); break; + default: + gcc_unreachable (); + } + break; + + case 'H': + if (REG_P (op)) + fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 0 : 1)]); + else if (CONST_INT_P (op)) + { + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op) >> 32); + } + else + { + gcc_assert (MEM_P (op)); + + if (! WORDS_BIG_ENDIAN) + op = adjust_address (op, SImode, 4); + output_address (XEXP (op, 0)); + } + break; + + case 'L': + if (REG_P (op)) + fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 1 : 0)]); + else if (CONST_INT_P (op)) + { + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op) & 0xffffffff); + } + else + { + gcc_assert (MEM_P (op)); + + if (WORDS_BIG_ENDIAN) + op = adjust_address (op, SImode, 4); + output_address (XEXP (op, 0)); + } + break; + + case 'Q': + if (MEM_P (op)) + { + HOST_WIDE_INT offset; + + op = XEXP (op, 0); + + if (REG_P (op)) + offset = 0; + else if (GET_CODE (op) == PLUS) + { + rtx displacement; + + if (REG_P (XEXP (op, 0))) + { + displacement = XEXP (op, 1); + op = XEXP (op, 0); + } + else + { + displacement = XEXP (op, 0); + op = XEXP (op, 1); + gcc_assert (REG_P (op)); + } + + gcc_assert (CONST_INT_P (displacement)); + offset = INTVAL (displacement); + gcc_assert (offset >= 0); + + fprintf (file, "%ld", offset); + } + else + gcc_unreachable (); + + fprintf (file, "["); + rx_print_operand (file, op, 0); + fprintf (file, "]."); + + switch (GET_MODE_SIZE (GET_MODE (op))) + { + case 1: + gcc_assert (offset < 65535 * 1); + fprintf (file, "B"); + break; + case 2: + gcc_assert (offset % 2 == 0); + gcc_assert (offset < 65535 * 2); + fprintf (file, "W"); + break; + default: + gcc_assert (offset % 4 == 0); + gcc_assert (offset < 65535 * 4); + fprintf (file, "L"); + break; + } + break; + } + + /* Fall through. */ + + default: + switch (GET_CODE (op)) + { + case MULT: + /* Should be the scaled part of an + indexed register indirect address. */ + { + rtx base = XEXP (op, 0); + rtx index = XEXP (op, 1); + + /* Check for a swaped index register and scaling factor. + Not sure if this can happen, but be prepared to handle it. */ + if (CONST_INT_P (base) && REG_P (index)) + { + rtx tmp = base; + base = index; + index = tmp; + } + + gcc_assert (REG_P (base)); + gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER); + gcc_assert (CONST_INT_P (index)); + /* Do not try to verify the value of the scalar as it is based + on the mode of the MEM not the mode of the MULT. (Which + will always be SImode). */ + fprintf (file, "%s", reg_names [REGNO (base)]); + break; + } + + case MEM: + output_address (XEXP (op, 0)); + break; + + case PLUS: + output_address (op); + break; + + case REG: + gcc_assert (REGNO (op) < FIRST_PSEUDO_REGISTER); + fprintf (file, "%s", reg_names [REGNO (op)]); + break; + + case SUBREG: + gcc_assert (subreg_regno (op) < FIRST_PSEUDO_REGISTER); + fprintf (file, "%s", reg_names [subreg_regno (op)]); + break; + + /* This will only be single precision.... */ + case CONST_DOUBLE: + { + unsigned long val; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + fprintf (file, TARGET_AS100_SYNTAX ? "#0%lxH" : "#0x%lx", val); + break; + } + + case CONST_INT: + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op)); + break; + + case SYMBOL_REF: + case CONST: + case LABEL_REF: + case CODE_LABEL: + case UNSPEC: + rx_print_operand_address (file, op); + break; + + default: + gcc_unreachable (); + } + break; + } +} + +/* Returns an assembler template for a move instruction. */ + +char * +rx_gen_move_template (rtx * operands, bool is_movu) +{ + static char template [64]; + const char * extension = TARGET_AS100_SYNTAX ? ".L" : ""; + const char * src_template; + const char * dst_template; + rtx dest = operands[0]; + rtx src = operands[1]; + + /* Decide which extension, if any, should be given to the move instruction. */ + switch (CONST_INT_P (src) ? GET_MODE (dest) : GET_MODE (src)) + { + case QImode: + /* The .B extension is not valid when + loading an immediate into a register. */ + if (! REG_P (dest) || ! CONST_INT_P (src)) + extension = ".B"; + break; + case HImode: + if (! REG_P (dest) || ! CONST_INT_P (src)) + /* The .W extension is not valid when + loading an immediate into a register. */ + extension = ".W"; + break; + case SFmode: + case SImode: + extension = ".L"; + break; + case VOIDmode: + /* This mode is used by constants. */ + break; + default: + debug_rtx (src); + gcc_unreachable (); + } + + if (MEM_P (src) && rx_small_data_operand (XEXP (src, 0))) + src_template = "%%gp(%A1)[r13]"; + else + src_template = "%1"; + + if (MEM_P (dest) && rx_small_data_operand (XEXP (dest, 0))) + dst_template = "%%gp(%A0)[r13]"; + else + dst_template = "%0"; + + sprintf (template, "%s%s\t%s, %s", is_movu ? "movu" : "mov", + extension, src_template, dst_template); + return template; +} + +/* Returns an assembler template for a conditional branch instruction. */ + +const char * +rx_gen_cond_branch_template (rtx condition, bool reversed) +{ + enum rtx_code code = GET_CODE (condition); + + + if ((cc_status.flags & CC_NO_OVERFLOW) && ! rx_float_compare_mode) + gcc_assert (code != GT && code != GE && code != LE && code != LT); + + if ((cc_status.flags & CC_NO_CARRY) || rx_float_compare_mode) + gcc_assert (code != GEU && code != GTU && code != LEU && code != LTU); + + if (reversed) + { + if (rx_float_compare_mode) + code = reverse_condition_maybe_unordered (code); + else + code = reverse_condition (code); + } + + /* We do not worry about encoding the branch length here as GAS knows + how to choose the smallest version, and how to expand a branch that + is to a destination that is out of range. */ + + switch (code) + { + case UNEQ: return "bo\t1f\n\tbeq\t%0\n1:"; + case LTGT: return "bo\t1f\n\tbne\t%0\n1:"; + case UNLT: return "bo\t1f\n\tbn\t%0\n1:"; + case UNGE: return "bo\t1f\n\tbpz\t%0\n1:"; + case UNLE: return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:"; + case UNGT: return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:"; + case UNORDERED: return "bo\t%0"; + case ORDERED: return "bno\t%0"; + + case LT: return rx_float_compare_mode ? "bn\t%0" : "blt\t%0"; + case GE: return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0"; + case GT: return "bgt\t%0"; + case LE: return "ble\t%0"; + case GEU: return "bgeu\t%0"; + case LTU: return "bltu\t%0"; + case GTU: return "bgtu\t%0"; + case LEU: return "bleu\t%0"; + case EQ: return "beq\t%0"; + case NE: return "bne\t%0"; + default: + gcc_unreachable (); + } +} + +/* Return VALUE rounded up to the next ALIGNMENT boundary. */ + +static inline unsigned int +rx_round_up (unsigned int value, unsigned int alignment) +{ + alignment -= 1; + return (value + alignment) & (~ alignment); +} + +/* Return the number of bytes in the argument registers + occupied by an argument of type TYPE and mode MODE. */ + +unsigned int +rx_function_arg_size (Mmode mode, const_tree type) +{ + unsigned int num_bytes; + + num_bytes = (mode == BLKmode) + ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + return rx_round_up (num_bytes, UNITS_PER_WORD); +} + +#define NUM_ARG_REGS 4 +#define MAX_NUM_ARG_BYTES (NUM_ARG_REGS * UNITS_PER_WORD) + +/* Return an RTL expression describing the register holding a function + parameter of mode MODE and type TYPE or NULL_RTX if the parameter should + be passed on the stack. CUM describes the previous parameters to the + function and NAMED is false if the parameter is part of a variable + parameter list, or the last named parameter before the start of a + variable parameter list. */ + +rtx +rx_function_arg (Fargs * cum, Mmode mode, const_tree type, bool named) +{ + unsigned int next_reg; + unsigned int bytes_so_far = *cum; + unsigned int size; + unsigned int rounded_size; + + /* An exploded version of rx_function_arg_size. */ + size = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + + rounded_size = rx_round_up (size, UNITS_PER_WORD); + + /* Don't pass this arg via registers if there + are insufficient registers to hold all of it. */ + if (rounded_size + bytes_so_far > MAX_NUM_ARG_BYTES) + return NULL_RTX; + + /* Unnamed arguments and the last named argument in a + variadic function are always passed on the stack. */ + if (!named) + return NULL_RTX; + + /* Structures must occupy an exact number of registers, + otherwise they are passed on the stack. */ + if ((type == NULL || AGGREGATE_TYPE_P (type)) + && (size % UNITS_PER_WORD) != 0) + return NULL_RTX; + + next_reg = (bytes_so_far / UNITS_PER_WORD) + 1; + + return gen_rtx_REG (mode, next_reg); +} + +/* Return an RTL describing where a function return value of type RET_TYPE + is held. */ + +static rtx +rx_function_value (const_tree ret_type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (ret_type), FUNC_RETURN_REGNUM); +} + +static bool +rx_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + HOST_WIDE_INT size; + + if (TYPE_MODE (type) != BLKmode + && ! AGGREGATE_TYPE_P (type)) + return false; + + size = int_size_in_bytes (type); + /* Large structs and those whose size is not an + exact multiple of 4 are returned in memory. */ + return size < 1 + || size > 16 + || (size % UNITS_PER_WORD) != 0; +} + +static rtx +rx_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (Pmode, STRUCT_VAL_REGNUM); +} + +static bool +rx_return_in_msb (const_tree valtype) +{ + return TARGET_BIG_ENDIAN_DATA + && (AGGREGATE_TYPE_P (valtype) || TREE_CODE (valtype) == COMPLEX_TYPE); +} + +/* Returns true if the provided function has the specified attribute. */ + +static inline bool +has_func_attr (const_tree decl, const char * func_attr) +{ + if (decl == NULL_TREE) + decl = current_function_decl; + + return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE; +} + +/* Returns true if the provided function has + the "[fast_]interrupt" attribute. */ + +static inline bool +is_fast_interrupt_func (const_tree decl) +{ + return has_func_attr (decl, "interrupt") + || has_func_attr (decl, "fast_interrupt") ; +} + +/* Returns true if the provided function has the "exception" attribute. */ + +static inline bool +is_exception_func (const_tree decl) +{ + return has_func_attr (decl, "exception"); +} + +/* Returns true if the provided function has the "naked" attribute. */ + +static inline bool +is_naked_func (const_tree decl) +{ + return has_func_attr (decl, "naked"); +} + +static bool use_fixed_regs = false; + +void +rx_conditional_register_usage (void) +{ + static bool using_fixed_regs = false; + + if (rx_small_data_limit > 0) + fixed_regs[GP_BASE_REGNUM] = call_used_regs [GP_BASE_REGNUM] = 1; + + if (use_fixed_regs != using_fixed_regs) + { + static char saved_fixed_regs[FIRST_PSEUDO_REGISTER]; + static char saved_call_used_regs[FIRST_PSEUDO_REGISTER]; + + if (use_fixed_regs) + { + unsigned int switched = 0; + unsigned int r; + + /* This is for fast interrupt handlers. Any register in + the range r10 to r13 (inclusive) that is currently + marked as fixed is now a viable, call-saved register. + All other registers are fixed. */ + memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs); + memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs); + + for (r = 1; r < 10; r++) + fixed_regs[r] = call_used_regs[r] = 1; + + for (r = 10; r <= 13; r++) + if (fixed_regs[r]) + { + fixed_regs[r] = 0; + call_used_regs[r] = 1; + ++ switched; + } + else + { + fixed_regs[r] = 1; + call_used_regs[r] = 1; + } + + fixed_regs[14] = call_used_regs[14] = 1; + fixed_regs[15] = call_used_regs[15] = 1; + + if (switched == 0) + { + static bool warned = false; + + if (! warned) + { + warning (0, "no fixed registers available " + "for use by fast interrupt handler"); + warned = true; + } + } + } + else + { + /* Restore the normal register masks. */ + memcpy (fixed_regs, saved_fixed_regs, sizeof fixed_regs); + memcpy (call_used_regs, saved_call_used_regs, sizeof call_used_regs); + } + + using_fixed_regs = use_fixed_regs; + } +} + +/* Perform any actions necessary before starting to compile FNDECL. + For the RX we use this to make sure that we have the correct + set of register masks selected. If FNDECL is NULL then we are + compiling top level things. */ + +static void +rx_set_current_function (tree fndecl) +{ + /* Remember the last target of rx_set_current_function. */ + static tree rx_previous_fndecl; + bool prev_was_interrupt; + bool current_is_interrupt; + + /* Only change the context if the function changes. This hook is called + several times in the course of compiling a function, and we don't want + to slow things down too much or call target_reinit when it isn't safe. */ + if (fndecl == rx_previous_fndecl) + return; + + prev_was_interrupt + = rx_previous_fndecl + ? is_fast_interrupt_func (rx_previous_fndecl) : false; + current_is_interrupt + = fndecl ? is_fast_interrupt_func (fndecl) : false; + + if (prev_was_interrupt != current_is_interrupt) + { + use_fixed_regs = current_is_interrupt; + target_reinit (); + } + + rx_previous_fndecl = fndecl; +} + +/* Typical stack layout should looks like this after the function's prologue: + + | | + -- ^ + | | \ | + | | arguments saved | Increasing + | | on the stack | addresses + PARENT arg pointer -> | | / + -------------------------- ---- ------------------- + CHILD |ret | return address + -- + | | \ + | | call saved + | | registers + | | / + -- + | | \ + | | local + | | variables + frame pointer -> | | / + -- + | | \ + | | outgoing | Decreasing + | | arguments | addresses + current stack pointer -> | | / | + -------------------------- ---- ------------------ V + | | */ + +static unsigned int +bit_count (unsigned int x) +{ + const unsigned int m1 = 0x55555555; + const unsigned int m2 = 0x33333333; + const unsigned int m4 = 0x0f0f0f0f; + + x -= (x >> 1) & m1; + x = (x & m2) + ((x >> 2) & m2); + x = (x + (x >> 4)) & m4; + x += x >> 8; + + return (x + (x >> 16)) & 0x3f; +} + +/* Returns either the lowest numbered and highest numbered registers that + occupy the call-saved area of the stack frame, if the registers are + stored as a contiguous block, or else a bitmask of the individual + registers if they are stored piecemeal. + + Also computes the size of the frame and the size of the outgoing + arguments block (in bytes). */ + +static void +rx_get_stack_layout (unsigned int * lowest, + unsigned int * highest, + unsigned int * register_mask, + unsigned int * frame_size, + unsigned int * stack_size) +{ + unsigned int reg; + unsigned int low; + unsigned int high; + unsigned int fixed_reg = 0; + unsigned int save_mask; + unsigned int pushed_mask; + unsigned int unneeded_pushes; + + if (is_naked_func (NULL_TREE) + || is_fast_interrupt_func (NULL_TREE)) + { + /* Naked functions do not create their own stack frame. + Instead the programmer must do that for us. + + Fast interrupt handlers use fixed registers that have + been epsecially released to the function, so they do + not need or want a stack frame. */ + * lowest = 0; + * highest = 0; + * register_mask = 0; + * frame_size = 0; + * stack_size = 0; + return; + } + + for (save_mask = high = low = 0, reg = 1; reg < FIRST_PSEUDO_REGISTER; reg++) + { + if (df_regs_ever_live_p (reg) + && (! call_used_regs[reg] + /* Even call clobbered registered must + be pushed inside exception handlers. */ + || is_exception_func (NULL_TREE))) + { + if (low == 0) + low = reg; + high = reg; + + save_mask |= 1 << reg; + } + + /* Remember if we see a fixed register + after having found the low register. */ + if (low != 0 && fixed_reg == 0 && fixed_regs [reg]) + fixed_reg = reg; + } + + /* Decide if it would be faster fill in the call-saved area of the stack + frame using multiple PUSH instructions instead of a single PUSHM + instruction. + + SAVE_MASK is a bitmask of the registers that must be stored in the + call-save area. PUSHED_MASK is a bitmask of the registers that would + be pushed into the area if we used a PUSHM instruction. UNNEEDED_PUSHES + is a bitmask of those registers in pushed_mask that are not in + save_mask. + + We use a simple heuristic that says that it is better to use + multiple PUSH instructions if the number of unnecessary pushes is + greater than the number of necessary pushes. + + We also use multiple PUSH instructions if there are any fixed registers + between LOW and HIGH. The only way that this can happen is if the user + has specified --fixed-<reg-name> on the command line and in such + circumstances we do not want to touch the fixed registers at all. + + FIXME: Is it worth improving this heuristic ? */ + pushed_mask = (-1 << low) & ~(-1 << (high + 1)); + unneeded_pushes = (pushed_mask & (~ save_mask)) & pushed_mask; + + if ((fixed_reg && fixed_reg <= high) + || (optimize_function_for_speed_p (cfun) + && bit_count (save_mask) < bit_count (unneeded_pushes))) + { + /* Use multiple pushes. */ + * lowest = 0; + * highest = 0; + * register_mask = save_mask; + } + else + { + /* Use one push multiple instruction. */ + * lowest = low; + * highest = high; + * register_mask = 0; + } + + * frame_size = rx_round_up + (get_frame_size (), STACK_BOUNDARY / BITS_PER_UNIT); + + if (crtl->args.size > 0) + * frame_size += rx_round_up + (crtl->args.size, STACK_BOUNDARY / BITS_PER_UNIT); + + * stack_size = rx_round_up + (crtl->outgoing_args_size, STACK_BOUNDARY / BITS_PER_UNIT); +} + +/* Generate a PUSHM instruction that matches the given operands. */ + +void +rx_emit_stack_pushm (rtx * operands) +{ + HOST_WIDE_INT last_reg; + rtx first_push; + + gcc_assert (CONST_INT_P (operands[0])); + last_reg = (INTVAL (operands[0]) / UNITS_PER_WORD) - 1; + + gcc_assert (GET_CODE (operands[1]) == PARALLEL); + first_push = XVECEXP (operands[1], 0, 1); + gcc_assert (SET_P (first_push)); + first_push = SET_SRC (first_push); + gcc_assert (REG_P (first_push)); + + asm_fprintf (asm_out_file, "\tpushm\t%s-%s\n", + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); + +} + +/* Generate a PARALLEL that will pass the rx_store_multiple_vector predicate. */ + +static rtx +gen_rx_store_vector (unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int count = (high - low) + 2; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + gen_rtx_MINUS (SImode, stack_pointer_rtx, + GEN_INT ((count - 1) * UNITS_PER_WORD))); + + for (i = 0; i < count - 1; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : gen_rtx_MINUS (SImode, stack_pointer_rtx, + GEN_INT (i * UNITS_PER_WORD))), + gen_rtx_REG (SImode, low + i)); + + return vector; +} + +void +rx_expand_prologue (void) +{ + unsigned int stack_size; + unsigned int frame_size; + unsigned int mask; + unsigned int low; + unsigned int high; + rtx insn; + + /* Naked functions use their own, programmer provided prologues. */ + if (is_naked_func (NULL_TREE) + /* Fast interrupt functions never use the stack. */ + || is_fast_interrupt_func (NULL_TREE)) + return; + + rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + + /* If we use any of the callee-saved registers, save them now. */ + if (mask) + { + unsigned int reg; + + /* Push registers in reverse order. */ + for (reg = FIRST_PSEUDO_REGISTER; reg --;) + if (mask & (1 << reg)) + { + insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, reg))); + RTX_FRAME_RELATED_P (insn) = 1; + } + } + else if (low) + { + if (high == low) + insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, low))); + else + insn = emit_insn (gen_stack_pushm (GEN_INT (((high - low) + 1) + * UNITS_PER_WORD), + gen_rx_store_vector (low, high))); + RTX_FRAME_RELATED_P (insn) = 1; + } + + /* If needed, set up the frame pointer. */ + if (frame_pointer_needed) + { + if (frame_size) + insn = emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size))); + else + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + + RTX_FRAME_RELATED_P (insn) = 1; + } + + insn = NULL_RTX; + + /* Allocate space for the outgoing args. + If the stack frame has not already been set up then handle this as well. */ + if (stack_size) + { + if (frame_size) + { + if (frame_pointer_needed) + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) + stack_size))); + else + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) + (frame_size + stack_size)))); + } + else + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) stack_size))); + } + else if (frame_size) + { + if (! frame_pointer_needed) + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size))); + else + insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + } + + if (insn != NULL_RTX) + RTX_FRAME_RELATED_P (insn) = 1; +} + +static void +rx_output_function_prologue (FILE * file, + HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED) +{ + if (is_fast_interrupt_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Fast Interrupt Handler\n"); + + if (is_exception_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Exception Handler\n"); + + if (is_naked_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Naked Function\n"); + + if (cfun->static_chain_decl != NULL) + asm_fprintf (file, "\t; Note: Nested function declared " + "inside another function.\n"); + + if (crtl->calls_eh_return) + asm_fprintf (file, "\t; Note: Calls __builtin_eh_return.\n"); +} + +/* Generate a POPM or RTSD instruction that matches the given operands. */ + +void +rx_emit_stack_popm (rtx * operands, bool is_popm) +{ + HOST_WIDE_INT stack_adjust; + HOST_WIDE_INT last_reg; + rtx first_push; + + gcc_assert (CONST_INT_P (operands[0])); + stack_adjust = INTVAL (operands[0]); + + gcc_assert (GET_CODE (operands[1]) == PARALLEL); + last_reg = XVECLEN (operands[1], 0) - (is_popm ? 2 : 3); + + first_push = XVECEXP (operands[1], 0, 1); + gcc_assert (SET_P (first_push)); + first_push = SET_DEST (first_push); + gcc_assert (REG_P (first_push)); + + if (is_popm) + asm_fprintf (asm_out_file, "\tpopm\t%s-%s\n", + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); + else + asm_fprintf (asm_out_file, "\trtsd\t#%d, %s-%s\n", + (int) stack_adjust, + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); +} + +/* Generate a PARALLEL which will satisfy the rx_rtsd_vector predicate. */ + +static rtx +gen_rx_rtsd_vector (unsigned int adjust, unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int bias = 3; + unsigned int count = (high - low) + bias; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, adjust)); + + for (i = 0; i < count - 2; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_REG (SImode, low + i), + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : plus_constant (stack_pointer_rtx, + i * UNITS_PER_WORD))); + + XVECEXP (vector, 0, count - 1) = gen_rtx_RETURN (VOIDmode); + + return vector; +} + +/* Generate a PARALLEL which will satisfy the rx_load_multiple_vector predicate. */ + +static rtx +gen_rx_popm_vector (unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int count = (high - low) + 2; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + (count - 1) * UNITS_PER_WORD)); + + for (i = 0; i < count - 1; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_REG (SImode, low + i), + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : plus_constant (stack_pointer_rtx, + i * UNITS_PER_WORD))); + + return vector; +} + +void +rx_expand_epilogue (bool is_sibcall) +{ + unsigned int low; + unsigned int high; + unsigned int frame_size; + unsigned int stack_size; + unsigned int register_mask; + unsigned int regs_size; + unsigned HOST_WIDE_INT total_size; + + if (is_naked_func (NULL_TREE)) + { + /* Naked functions use their own, programmer provided epilogues. + But, in order to keep gcc happy we have to generate some kind of + epilogue RTL. */ + emit_jump_insn (gen_naked_return ()); + return; + } + + rx_get_stack_layout (& low, & high, & register_mask, + & frame_size, & stack_size); + + total_size = frame_size + stack_size; + regs_size = ((high - low) + 1) * UNITS_PER_WORD; + + /* See if we are unable to use the special stack frame deconstruct and + return instructions. In most cases we can use them, but the exceptions + are: + + - Sibling calling functions deconstruct the frame but do not return to + their caller. Instead they branch to their sibling and allow their + return instruction to return to this function's parent. + + - Fast interrupt and exception handling functions have to use special + return instructions. + + - Functions where we have pushed a fragmented set of registers into the + call-save area must have the same set of registers popped. */ + if (is_sibcall + || is_fast_interrupt_func (NULL_TREE) + || is_exception_func (NULL_TREE) + || register_mask) + { + /* Cannot use the special instructions - deconstruct by hand. */ + if (total_size) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size))); + + if (register_mask) + { + unsigned int reg; + + for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) + if (register_mask & (1 << reg)) + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, reg))); + } + else if (low) + { + if (high == low) + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, low))); + else + emit_insn (gen_stack_popm (GEN_INT (regs_size), + gen_rx_popm_vector (low, high))); + } + + if (is_fast_interrupt_func (NULL_TREE)) + emit_jump_insn (gen_fast_interrupt_return ()); + else if (is_exception_func (NULL_TREE)) + emit_jump_insn (gen_exception_return ()); + else if (! is_sibcall) + emit_jump_insn (gen_simple_return ()); + + return; + } + + /* If we allocated space on the stack, free it now. */ + if (total_size) + { + unsigned HOST_WIDE_INT rtsd_size; + + /* See if we can use the RTSD instruction. */ + rtsd_size = total_size + regs_size; + if (rtsd_size < 1024 && (rtsd_size % 4) == 0) + { + if (low) + emit_jump_insn (gen_pop_and_return + (GEN_INT (rtsd_size), + gen_rx_rtsd_vector (rtsd_size, low, high))); + else + emit_jump_insn (gen_deallocate_and_return (GEN_INT (total_size))); + + return; + } + + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size))); + } + + if (low) + emit_jump_insn (gen_pop_and_return (GEN_INT (regs_size), + gen_rx_rtsd_vector (regs_size, + low, high))); + else + emit_jump_insn (gen_simple_return ()); +} + + +/* Compute the offset (in words) between FROM (arg pointer + or frame pointer) and TO (frame pointer or stack pointer). + See ASCII art comment at the start of rx_expand_prologue + for more information. */ + +int +rx_initial_elimination_offset (int from, int to) +{ + unsigned int low; + unsigned int high; + unsigned int frame_size; + unsigned int stack_size; + unsigned int mask; + + rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + + if (from == ARG_POINTER_REGNUM) + { + /* Extend the computed size of the stack frame to + include the registers pushed in the prologue. */ + if (low) + frame_size += ((high - low) + 1) * UNITS_PER_WORD; + else + frame_size += bit_count (mask) * UNITS_PER_WORD; + + /* Remember to include the return address. */ + frame_size += 1 * UNITS_PER_WORD; + + if (to == FRAME_POINTER_REGNUM) + return frame_size; + + gcc_assert (to == STACK_POINTER_REGNUM); + return frame_size + stack_size; + } + + gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM); + return stack_size; +} + +/* Update the status of the condition + codes (cc0) based on the given INSN. */ + +void +rx_notice_update_cc (rtx body, rtx insn) +{ + switch (get_attr_cc (insn)) + { + case CC_NONE: + /* Insn does not affect cc0 at all. */ + break; + case CC_CLOBBER: + /* Insn doesn't leave cc0 in a usable state. */ + CC_STATUS_INIT; + break; + case CC_SET_ZSOC: + /* The insn sets all the condition code bits. */ + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (body); + break; + case CC_SET_ZSO: + /* Insn sets the Z,S and O flags, but not the C flag. */ + CC_STATUS_INIT; + cc_status.flags |= CC_NO_CARRY; + /* Do not set the value1 field in this case. The final_scan_insn() + function naively believes that if cc_status.value1 is set then + it can eliminate *any* comparison against that value, even if + the type of comparison cannot be satisfied by the range of flag + bits being set here. See gcc.c-torture/execute/20041210-1.c + for an example of this in action. */ + break; + case CC_SET_ZS: + /* Insn sets the Z and S flags, but not the O or C flags. */ + CC_STATUS_INIT; + cc_status.flags |= (CC_NO_CARRY | CC_NO_OVERFLOW); + /* See comment above regarding cc_status.value1. */ + break; + default: + gcc_unreachable (); + } +} + +/* Decide if a variable should go into one of the small data sections. */ + +static bool +rx_in_small_data (const_tree decl) +{ + int size; + const_tree section; + + if (rx_small_data_limit == 0) + return false; + + if (TREE_CODE (decl) != VAR_DECL) + return false; + + /* We do not put read-only variables into a small data area because + they would be placed with the other read-only sections, far away + from the read-write data sections, and we only have one small + data area pointer. + Similarly commons are placed in the .bss section which might be + far away (and out of alignment with respect to) the .data section. */ + if (TREE_READONLY (decl) || DECL_COMMON (decl)) + return false; + + section = DECL_SECTION_NAME (decl); + if (section) + { + const char * const name = TREE_STRING_POINTER (section); + + return (strcmp (name, "D_2") == 0) || (strcmp (name, "B_2") == 0); + } + + size = int_size_in_bytes (TREE_TYPE (decl)); + + return (size > 0) && (size <= rx_small_data_limit); +} + +/* Return a section for X. + The only special thing we do here is to honor small data. */ + +static section * +rx_select_rtx_section (enum machine_mode mode, + rtx x, + unsigned HOST_WIDE_INT align) +{ + if (rx_small_data_limit > 0 + && GET_MODE_SIZE (mode) <= rx_small_data_limit + && align <= (unsigned HOST_WIDE_INT) rx_small_data_limit * BITS_PER_UNIT) + return sdata_section; + + return default_elf_select_rtx_section (mode, x, align); +} + +static section * +rx_select_section (tree decl, + int reloc, + unsigned HOST_WIDE_INT align) +{ + if (rx_small_data_limit > 0) + { + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_SDATA: return sdata_section; + case SECCAT_SBSS: return sbss_section; + case SECCAT_SRODATA: + /* Fall through. We do not put small, read only + data into the C_2 section because we are not + using the C_2 section. We do not use the C_2 + section because it is located with the other + read-only data sections, far away from the read-write + data sections and we only have one small data + pointer (r13). */ + default: + break; + } + } + + /* If we are supporting the Renesas assembler + we cannot use mergeable sections. */ + if (TARGET_AS100_SYNTAX) + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_RODATA_MERGE_CONST: + case SECCAT_RODATA_MERGE_STR_INIT: + case SECCAT_RODATA_MERGE_STR: + return readonly_data_section; + + default: + break; + } + + return default_elf_select_section (decl, reloc, align); +} + +enum rx_builtin +{ + RX_BUILTIN_BRK, + RX_BUILTIN_CLRPSW, + RX_BUILTIN_INT, + RX_BUILTIN_MACHI, + RX_BUILTIN_MACLO, + RX_BUILTIN_MULHI, + RX_BUILTIN_MULLO, + RX_BUILTIN_MVFACHI, + RX_BUILTIN_MVFACMI, + RX_BUILTIN_MVFC, + RX_BUILTIN_MVTACHI, + RX_BUILTIN_MVTACLO, + RX_BUILTIN_MVTC, + RX_BUILTIN_RACW, + RX_BUILTIN_REVW, + RX_BUILTIN_RMPA, + RX_BUILTIN_ROUND, + RX_BUILTIN_SAT, + RX_BUILTIN_SETPSW, + RX_BUILTIN_WAIT, + RX_BUILTIN_max +}; + +static void +rx_init_builtins (void) +{ +#define ADD_RX_BUILTIN1(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE##_type_node, \ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_RX_BUILTIN2(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_RX_BUILTIN3(UC_NAME,LC_NAME,RET_TYPE,ARG_TYPE1,ARG_TYPE2,ARG_TYPE3) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + ARG_TYPE3##_type_node,\ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + + ADD_RX_BUILTIN1 (BRK, "brk", void, void); + ADD_RX_BUILTIN1 (CLRPSW, "clrpsw", void, integer); + ADD_RX_BUILTIN1 (SETPSW, "setpsw", void, integer); + ADD_RX_BUILTIN1 (INT, "int", void, integer); + ADD_RX_BUILTIN2 (MACHI, "machi", void, intSI, intSI); + ADD_RX_BUILTIN2 (MACLO, "maclo", void, intSI, intSI); + ADD_RX_BUILTIN2 (MULHI, "mulhi", void, intSI, intSI); + ADD_RX_BUILTIN2 (MULLO, "mullo", void, intSI, intSI); + ADD_RX_BUILTIN1 (MVFACHI, "mvfachi", intSI, void); + ADD_RX_BUILTIN1 (MVFACMI, "mvfacmi", intSI, void); + ADD_RX_BUILTIN1 (MVTACHI, "mvtachi", void, intSI); + ADD_RX_BUILTIN1 (MVTACLO, "mvtaclo", void, intSI); + ADD_RX_BUILTIN1 (RMPA, "rmpa", void, void); + ADD_RX_BUILTIN1 (MVFC, "mvfc", intSI, integer); + ADD_RX_BUILTIN2 (MVTC, "mvtc", void, integer, integer); + ADD_RX_BUILTIN1 (RACW, "racw", void, integer); + ADD_RX_BUILTIN1 (ROUND, "round", intSI, float); + ADD_RX_BUILTIN1 (REVW, "revw", intSI, intSI); + ADD_RX_BUILTIN1 (SAT, "sat", intSI, intSI); + ADD_RX_BUILTIN1 (WAIT, "wait", void, void); +} + +static rtx +rx_expand_builtin_stz (rtx arg, rtx target, rtx (* gen_func)(rtx, rtx)) +{ + if (! CONST_INT_P (arg)) + return NULL_RTX; + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target, arg)); + + return target; +} + +static rtx +rx_expand_void_builtin_1_arg (rtx arg, rtx (* gen_func)(rtx), bool reg) +{ + if (reg && ! REG_P (arg)) + arg = force_reg (SImode, arg); + + emit_insn (gen_func (arg)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mvtc (tree exp) +{ + rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); + + if (! CONST_INT_P (arg1)) + return NULL_RTX; + + if (! REG_P (arg2)) + arg2 = force_reg (SImode, arg2); + + emit_insn (gen_mvtc (arg1, arg2)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mvfc (tree t_arg, rtx target) +{ + rtx arg = expand_normal (t_arg); + + if (! CONST_INT_P (arg)) + return NULL_RTX; + + if (! REG_P (target)) + target = force_reg (SImode, target); + + emit_insn (gen_mvfc (target, arg)); + + return target; +} + +static rtx +rx_expand_builtin_mac (tree exp, rtx (* gen_func)(rtx, rtx)) +{ + rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); + + if (! REG_P (arg1)) + arg1 = force_reg (SImode, arg1); + + if (! REG_P (arg2)) + arg2 = force_reg (SImode, arg2); + + emit_insn (gen_func (arg1, arg2)); + + return NULL_RTX; +} + +static rtx +rx_expand_int_builtin_1_arg (rtx arg, + rtx target, + rtx (* gen_func)(rtx, rtx), + bool mem_ok) +{ + if (! REG_P (arg)) + if (!mem_ok || ! MEM_P (arg)) + arg = force_reg (SImode, arg); + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target, arg)); + + return target; +} + +static rtx +rx_expand_int_builtin_0_arg (rtx target, rtx (* gen_func)(rtx)) +{ + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target)); + + return target; +} + +static rtx +rx_expand_builtin_round (rtx arg, rtx target) +{ + if ((! REG_P (arg) && ! MEM_P (arg)) + || GET_MODE (arg) != SFmode) + arg = force_reg (SFmode, arg); + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_lrintsf2 (target, arg)); + + return target; +} + +static rtx +rx_expand_builtin (tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + tree arg = CALL_EXPR_ARGS (exp) ? CALL_EXPR_ARG (exp, 0) : NULL_TREE; + rtx op = arg ? expand_normal (arg) : NULL_RTX; + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + + switch (fcode) + { + case RX_BUILTIN_BRK: emit_insn (gen_brk ()); return NULL_RTX; + case RX_BUILTIN_CLRPSW: return rx_expand_void_builtin_1_arg + (op, gen_clrpsw, false); + case RX_BUILTIN_SETPSW: return rx_expand_void_builtin_1_arg + (op, gen_setpsw, false); + case RX_BUILTIN_INT: return rx_expand_void_builtin_1_arg + (op, gen_int, false); + case RX_BUILTIN_MACHI: return rx_expand_builtin_mac (exp, gen_machi); + case RX_BUILTIN_MACLO: return rx_expand_builtin_mac (exp, gen_maclo); + case RX_BUILTIN_MULHI: return rx_expand_builtin_mac (exp, gen_mulhi); + case RX_BUILTIN_MULLO: return rx_expand_builtin_mac (exp, gen_mullo); + case RX_BUILTIN_MVFACHI: return rx_expand_int_builtin_0_arg + (target, gen_mvfachi); + case RX_BUILTIN_MVFACMI: return rx_expand_int_builtin_0_arg + (target, gen_mvfacmi); + case RX_BUILTIN_MVTACHI: return rx_expand_void_builtin_1_arg + (op, gen_mvtachi, true); + case RX_BUILTIN_MVTACLO: return rx_expand_void_builtin_1_arg + (op, gen_mvtaclo, true); + case RX_BUILTIN_RMPA: emit_insn (gen_rmpa ()); return NULL_RTX; + case RX_BUILTIN_MVFC: return rx_expand_builtin_mvfc (arg, target); + case RX_BUILTIN_MVTC: return rx_expand_builtin_mvtc (exp); + case RX_BUILTIN_RACW: return rx_expand_void_builtin_1_arg + (op, gen_racw, false); + case RX_BUILTIN_ROUND: return rx_expand_builtin_round (op, target); + case RX_BUILTIN_REVW: return rx_expand_int_builtin_1_arg + (op, target, gen_revw, false); + case RX_BUILTIN_SAT: return rx_expand_int_builtin_1_arg + (op, target, gen_sat, false); + case RX_BUILTIN_WAIT: emit_insn (gen_wait ()); return NULL_RTX; + + default: + internal_error ("bad builtin code"); + break; + } + + return NULL_RTX; +} + +/* Place an element into a constructor or destructor section. + Like default_ctor_section_asm_out_constructor in varasm.c + except that it uses .init_array (or .fini_array) and it + handles constructor priorities. */ + +static void +rx_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor) +{ + section * s; + + if (priority != DEFAULT_INIT_PRIORITY) + { + char buf[18]; + + sprintf (buf, "%s.%.5u", + is_ctor ? ".init_array" : ".fini_array", + priority); + s = get_section (buf, SECTION_WRITE, NULL_TREE); + } + else if (is_ctor) + s = ctors_section; + else + s = dtors_section; + + switch_to_section (s); + assemble_align (POINTER_SIZE); + assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); +} + +static void +rx_elf_asm_constructor (rtx symbol, int priority) +{ + rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */true); +} + +static void +rx_elf_asm_destructor (rtx symbol, int priority) +{ + rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */false); +} + +/* Check "interrupt", "exception" and "naked" attributes. */ + +static tree +rx_handle_func_attribute (tree * node, + tree name, + tree args, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + gcc_assert (DECL_P (* node)); + gcc_assert (args == NULL_TREE); + + if (TREE_CODE (* node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + * no_add_attrs = true; + } + + /* FIXME: We ought to check for conflicting attributes. */ + + /* FIXME: We ought to check that the interrupt and exception + handler attributes have been applied to void functions. */ + return NULL_TREE; +} + +/* Table of RX specific attributes. */ +const struct attribute_spec rx_attribute_table[] = +{ + /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler. */ + { "interrupt", 0, 0, true, false, false, rx_handle_func_attribute }, + { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute }, + { "exception", 0, 0, true, false, false, rx_handle_func_attribute }, + { "naked", 0, 0, true, false, false, rx_handle_func_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +static bool +rx_allocate_stack_slots_for_args (void) +{ + /* Naked functions should not allocate stack slots for arguments. */ + return ! is_naked_func (NULL_TREE); +} + +static bool +rx_func_attr_inlinable (const_tree decl) +{ + return ! is_fast_interrupt_func (decl) + && ! is_exception_func (decl) + && ! is_naked_func (decl); +} + +static void +rx_file_start (void) +{ + if (! TARGET_AS100_SYNTAX) + default_file_start (); +} + +static bool +rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Try to generate code for the "isnv" pattern which inserts bits + into a word. + operands[0] => Location to be altered. + operands[1] => Number of bits to change. + operands[2] => Starting bit. + operands[3] => Value to insert. + Returns TRUE if successful, FALSE otherwise. */ + +bool +rx_expand_insv (rtx * operands) +{ + if (INTVAL (operands[1]) != 1 + || ! CONST_INT_P (operands[3])) + return false; + + if (MEM_P (operands[0]) + && INTVAL (operands[2]) > 7) + return false; + + switch (INTVAL (operands[3])) + { + case 0: + if (MEM_P (operands[0])) + emit_insn (gen_bitclr_in_memory (operands[0], operands[0], + operands[2])); + else + emit_insn (gen_bitclr (operands[0], operands[0], operands[2])); + break; + case 1: + case -1: + if (MEM_P (operands[0])) + emit_insn (gen_bitset_in_memory (operands[0], operands[0], + operands[2])); + else + emit_insn (gen_bitset (operands[0], operands[0], operands[2])); + break; + default: + return false; + } + return true; +} + +/* Returns true if X a legitimate constant for an immediate + operand on the RX. X is already known to satisfy CONSTANT_P. */ + +bool +rx_is_legitimate_constant (rtx x) +{ + HOST_WIDE_INT val; + + switch (GET_CODE (x)) + { + case CONST: + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + { + if (! CONST_INT_P (XEXP (x, 1))) + return false; + + /* GCC would not pass us CONST_INT + CONST_INT so we + know that we have {SYMBOL|LABEL} + CONST_INT. */ + x = XEXP (x, 0); + gcc_assert (! CONST_INT_P (x)); + } + + switch (GET_CODE (x)) + { + case LABEL_REF: + case SYMBOL_REF: + return true; + + /* One day we may have to handle UNSPEC constants here. */ + default: + /* FIXME: Can this ever happen ? */ + abort (); + return false; + } + break; + + case LABEL_REF: + case SYMBOL_REF: + return true; + case CONST_DOUBLE: + return rx_max_constant_size == 0; + case CONST_VECTOR: + return false; + default: + gcc_assert (CONST_INT_P (x)); + break; + } + + if (rx_max_constant_size == 0) + /* If there is no constraint on the size of constants + used as operands, then any value is legitimate. */ + return true; + + val = INTVAL (x); + + /* rx_max_constant_size specifies the maximum number + of bytes that can be used to hold a signed value. */ + return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)), + ( 1 << (rx_max_constant_size * 8))); +} + +/* Extra processing for target specific command line options. */ + +static bool +rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value) +{ + switch (code) + { + case OPT_mint_register_: + switch (value) + { + case 4: + fixed_regs[10] = call_used_regs [10] = 1; + /* Fall through. */ + case 3: + fixed_regs[11] = call_used_regs [11] = 1; + /* Fall through. */ + case 2: + fixed_regs[12] = call_used_regs [12] = 1; + /* Fall through. */ + case 1: + fixed_regs[13] = call_used_regs [13] = 1; + /* Fall through. */ + case 0: + return true; + default: + return false; + } + break; + + case OPT_mmax_constant_size_: + /* Make sure that the the -mmax-constant_size option is in range. */ + return IN_RANGE (value, 0, 4); + + default: + return true; + } +} + +static int +rx_address_cost (rtx addr, bool speed) +{ + rtx a, b; + + if (GET_CODE (addr) != PLUS) + return COSTS_N_INSNS (1); + + a = XEXP (addr, 0); + b = XEXP (addr, 1); + + if (REG_P (a) && REG_P (b)) + /* Try to discourage REG+REG addressing as it keeps two registers live. */ + return COSTS_N_INSNS (4); + + if (speed) + /* [REG+OFF] is just as fast as [REG]. */ + return COSTS_N_INSNS (1); + + if (CONST_INT_P (b) + && ((INTVAL (b) > 128) || INTVAL (b) < -127)) + /* Try to discourage REG + <large OFF> when optimizing for size. */ + return COSTS_N_INSNS (2); + + return COSTS_N_INSNS (1); +} + +static bool +rx_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) +{ + /* We can always eliminate to the frame pointer. + We can eliminate to the stack pointer unless a frame + pointer is needed. */ + + return to == FRAME_POINTER_REGNUM + || ( to == STACK_POINTER_REGNUM && ! frame_pointer_needed); +} + + +static void +rx_trampoline_template (FILE * file) +{ + /* Output assembler code for a block containing the constant + part of a trampoline, leaving space for the variable parts. + + On the RX, (where r8 is the static chain regnum) the trampoline + looks like: + + mov #<static chain value>, r8 + mov #<function's address>, r9 + jmp r9 + + In big-endian-data-mode however instructions are read into the CPU + 4 bytes at a time. These bytes are then swapped around before being + passed to the decoder. So...we must partition our trampoline into + 4 byte packets and swap these packets around so that the instruction + reader will reverse the process. But, in order to avoid splitting + the 32-bit constants across these packet boundaries, (making inserting + them into the constructed trampoline very difficult) we have to pad the + instruction sequence with NOP insns. ie: + + nop + nop + mov.l #<...>, r8 + nop + nop + mov.l #<...>, r9 + jmp r9 + nop + nop */ + + if (! TARGET_BIG_ENDIAN_DATA) + { + asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", STATIC_CHAIN_REGNUM); + asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", TRAMPOLINE_TEMP_REGNUM); + asm_fprintf (file, "\tjmp\tr%d\n", TRAMPOLINE_TEMP_REGNUM); + } + else + { + char r8 = '0' + STATIC_CHAIN_REGNUM; + char r9 = '0' + TRAMPOLINE_TEMP_REGNUM; + + if (TARGET_AS100_SYNTAX) + { + asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r8); + asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n"); + asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r9); + asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n"); + asm_fprintf (file, "\t.BYTE 003H, 003H, 00%cH, 07fH\n", r9); + } + else + { + asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r8); + asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n"); + asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r9); + asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n"); + asm_fprintf (file, "\t.byte 0x03, 0x03, 0x0%c, 0x7f\n", r9); + } + } +} + +static void +rx_trampoline_init (rtx tramp, tree fndecl, rtx chain) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + + emit_block_move (tramp, assemble_trampoline_template (), + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + + if (TARGET_BIG_ENDIAN_DATA) + { + emit_move_insn (adjust_address (tramp, SImode, 4), chain); + emit_move_insn (adjust_address (tramp, SImode, 12), fnaddr); + } + else + { + emit_move_insn (adjust_address (tramp, SImode, 2), chain); + emit_move_insn (adjust_address (tramp, SImode, 6 + 2), fnaddr); + } +} + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE rx_function_value + +#undef TARGET_RETURN_IN_MSB +#define TARGET_RETURN_IN_MSB rx_return_in_msb + +#undef TARGET_IN_SMALL_DATA_P +#define TARGET_IN_SMALL_DATA_P rx_in_small_data + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY rx_return_in_memory + +#undef TARGET_HAVE_SRODATA_SECTION +#define TARGET_HAVE_SRODATA_SECTION true + +#undef TARGET_ASM_SELECT_RTX_SECTION +#define TARGET_ASM_SELECT_RTX_SECTION rx_select_rtx_section + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION rx_select_section + +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS rx_init_builtins + +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN rx_expand_builtin + +#undef TARGET_ASM_CONSTRUCTOR +#define TARGET_ASM_CONSTRUCTOR rx_elf_asm_constructor + +#undef TARGET_ASM_DESTRUCTOR +#define TARGET_ASM_DESTRUCTOR rx_elf_asm_destructor + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX rx_struct_value_rtx + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE rx_attribute_table + +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START rx_file_start + +#undef TARGET_MS_BITFIELD_LAYOUT_P +#define TARGET_MS_BITFIELD_LAYOUT_P rx_is_ms_bitfield_layout + +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P rx_is_legitimate_address + +#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS +#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS rx_allocate_stack_slots_for_args + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE rx_output_function_prologue + +#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P rx_func_attr_inlinable + +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION rx_set_current_function + +#undef TARGET_HANDLE_OPTION +#define TARGET_HANDLE_OPTION rx_handle_option + +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER rx_assemble_integer + +#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P +#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true + +#undef TARGET_MAX_ANCHOR_OFFSET +#define TARGET_MAX_ANCHOR_OFFSET 32 + +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST rx_address_cost + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE rx_can_eliminate + +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE rx_trampoline_template + +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT rx_trampoline_init + +struct gcc_target targetm = TARGET_INITIALIZER; + +/* #include "gt-rx.h" */ diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h new file mode 100644 index 00000000000..a01e194910b --- /dev/null +++ b/gcc/config/rx/rx.h @@ -0,0 +1,632 @@ +/* GCC backend definitions for the Renesas RX processor. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + + +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__RX__"); \ + builtin_assert ("cpu=RX"); \ + builtin_assert ("machine=RX"); \ + \ + if (TARGET_BIG_ENDIAN_DATA) \ + builtin_define ("__RX_BIG_ENDIAN__"); \ + else \ + builtin_define ("__RX_LITTLE_ENDIAN__");\ + \ + if (TARGET_64BIT_DOUBLES) \ + builtin_define ("__RX_64BIT_DOUBLES__");\ + else \ + builtin_define ("__RX_32BIT_DOUBLES__");\ + \ + if (TARGET_AS100_SYNTAX) \ + builtin_define ("__RX_AS100_SYNTAX__"); \ + else \ + builtin_define ("__RX_GAS_SYNTAX__"); \ + } \ + while (0) + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +#undef ASM_SPEC +#define ASM_SPEC "\ +%{mbig-endian-data:-mbig-endian-data} \ +%{m64bit-doubles:-m64bit-doubles} \ +%{msmall-data-limit*:-msmall-data-limit} \ +%{mrelax:-relax} \ +" + +#undef LIB_SPEC +#define LIB_SPEC " \ +--start-group \ +-lc \ +%{msim*:-lsim}%{!msim*:-lnosys} \ +%{fprofile-arcs|fprofile-generate|coverage:-lgcov} \ +--end-group \ +%{!T*: %{msim*:%Trx-sim.ld}%{!msim*:%Trx.ld}} \ +" + +#undef LINK_SPEC +#define LINK_SPEC "%{mbig-endian-data:--oformat elf32-rx-be} %{mrelax:-relax}" + + +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN TARGET_BIG_ENDIAN_DATA +#define WORDS_BIG_ENDIAN TARGET_BIG_ENDIAN_DATA + +#ifdef __RX_BIG_ENDIAN__ +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define UNITS_PER_WORD 4 + +#define INT_TYPE_SIZE 32 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 + +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE (TARGET_64BIT_DOUBLES ? 64 : 32) +#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE + +#ifdef __RX_64BIT_DOUBLES__ +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 +#define LIBGCC2_DOUBLE_TYPE_SIZE 64 +#define LIBGCC2_HAS_DF_MODE 1 +#else +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 32 +#define LIBGCC2_DOUBLE_TYPE_SIZE 32 +#endif + +#define DEFAULT_SIGNED_CHAR 0 + +#define STRICT_ALIGNMENT 1 +#define FUNCTION_BOUNDARY 8 +#define BIGGEST_ALIGNMENT 32 +#define STACK_BOUNDARY 32 +#define PARM_BOUNDARY 8 + +#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) 32 + +#define STACK_GROWS_DOWNWARD 1 +#define FRAME_GROWS_DOWNWARD 0 +#define FIRST_PARM_OFFSET(FNDECL) 0 + +#define MAX_REGS_PER_ADDRESS 2 + +#define Pmode SImode +#define POINTER_SIZE 32 +#undef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#define POINTERS_EXTEND_UNSIGNED 1 +#define FUNCTION_MODE QImode +#define CASE_VECTOR_MODE Pmode +#define WORD_REGISTER_OPERATIONS 1 +#define HAS_LONG_COND_BRANCH 0 +#define HAS_LONG_UNCOND_BRANCH 0 + +#define MOVE_MAX 4 +#define STARTING_FRAME_OFFSET 0 + +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0 +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +#define LEGITIMATE_CONSTANT_P(X) rx_is_legitimate_constant (X) + +#define HANDLE_PRAGMA_PACK_PUSH_POP 1 + +#define HAVE_PRE_DECCREMENT 1 +#define HAVE_POST_INCREMENT 1 + +#define MOVE_RATIO(SPEED) ((SPEED) ? 4 : 2) +#define SLOW_BYTE_ACCESS 1 + +#define STORE_FLAG_VALUE 1 +#define LOAD_EXTEND_OP(MODE) SIGN_EXTEND +#define SHORT_IMMEDIATES_SIGN_EXTEND 1 + +enum reg_class +{ + NO_REGS, /* No registers in set. */ + GR_REGS, /* Integer registers. */ + ALL_REGS, /* All registers. */ + LIM_REG_CLASSES /* Max value + 1. */ +}; + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "GR_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + { 0x00000000 }, /* No registers, */ \ + { 0x0000ffff }, /* Integer registers. */ \ + { 0x0000ffff } /* All registers. */ \ +} + +#define IRA_COVER_CLASSES \ + { \ + GR_REGS, LIM_REG_CLASSES \ + } + +#define SMALL_REGISTER_CLASSES 0 +#define N_REG_CLASSES (int) LIM_REG_CLASSES +#define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \ + + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +#define GENERAL_REGS GR_REGS +#define BASE_REG_CLASS GR_REGS +#define INDEX_REG_CLASS GR_REGS + +#define FIRST_PSEUDO_REGISTER 16 + +#define REGNO_REG_CLASS(REGNO) ((REGNO) < FIRST_PSEUDO_REGISTER \ + ? GR_REGS : NO_REGS) + +#define STACK_POINTER_REGNUM 0 +#define FUNC_RETURN_REGNUM 1 +#define FRAME_POINTER_REGNUM 6 +#define ARG_POINTER_REGNUM 7 +#define STATIC_CHAIN_REGNUM 8 +#define TRAMPOLINE_TEMP_REGNUM 9 +#define STRUCT_VAL_REGNUM 15 + +/* This is the register which is used to hold the address of the start + of the small data area, if that feature is being used. Note - this + register must not be call_used because otherwise library functions + that are compiled without small data support might clobber it. + + FIXME: The function gcc/config/rx/rx.c:rx_gen_move_template() has a + built in copy of this register's name, rather than constructing the + name from this #define. */ +#define GP_BASE_REGNUM 13 + +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }} + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = rx_initial_elimination_offset ((FROM), (TO)) + + +#define FUNCTION_ARG_REGNO_P(N) (((N) >= 1) && ((N) <= 4)) +#define FUNCTION_VALUE_REGNO_P(N) ((N) == FUNC_RETURN_REGNUM) +#define DEFAULT_PCC_STRUCT_RETURN 0 + +#define FIXED_REGISTERS \ +{ \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ +} + +#define CALL_USED_REGISTERS \ +{ \ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 \ +} + +#define CONDITIONAL_REGISTER_USAGE \ + rx_conditional_register_usage () + +#define LIBCALL_VALUE(MODE) \ + gen_rtx_REG (((GET_MODE_CLASS (MODE) != MODE_INT \ + || GET_MODE_SIZE (MODE) >= 4) \ + ? (MODE) \ + : SImode), \ + FUNC_RETURN_REGNUM) + +/* Order of allocation of registers. */ + +#define REG_ALLOC_ORDER \ +{ 7, 10, 11, 12, 13, 14, 4, 3, 2, 1, 9, 8, 6, 5, 15 \ +} + +#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + +#define REGNO_IN_RANGE(REGNO, MIN, MAX) \ + (IN_RANGE ((REGNO), (MIN), (MAX)) \ + || (reg_renumber != NULL \ + && reg_renumber[(REGNO)] >= (MIN) \ + && reg_renumber[(REGNO)] <= (MAX))) + +#ifdef REG_OK_STRICT +#define REGNO_OK_FOR_BASE_P(regno) REGNO_IN_RANGE (regno, 0, 15) +#else +#define REGNO_OK_FOR_BASE_P(regno) 1 +#endif + +#define REGNO_OK_FOR_INDEX_P(regno) REGNO_OK_FOR_BASE_P (regno) + +#define RTX_OK_FOR_BASE(X, STRICT) \ + ((STRICT) ? \ + ( (REG_P (X) \ + && REGNO_IN_RANGE (REGNO (X), 0, 15)) \ + || (GET_CODE (X) == SUBREG \ + && REG_P (SUBREG_REG (X)) \ + && REGNO_IN_RANGE (REGNO (SUBREG_REG (X)), 0, 15))) \ + : \ + ( (REG_P (X) \ + || (GET_CODE (X) == SUBREG \ + && REG_P (SUBREG_REG (X)))))) + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ + do \ + { \ + if (rx_is_mode_dependent_addr (ADDR)) \ + goto LABEL; \ + } \ + while (0) + + +#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \ + ((COUNT) == 0 \ + ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (-4))) \ + : NULL_RTX) + +#define INCOMING_RETURN_ADDR_RTX gen_rtx_MEM (Pmode, stack_pointer_rtx) + +#define ACCUMULATE_OUTGOING_ARGS 1 + +typedef unsigned int CUMULATIVE_ARGS; + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ + (CUM) = 0 + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + rx_function_arg (& CUM, MODE, TYPE, NAMED) + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM) += rx_function_arg_size (MODE, TYPE) + +#define TRAMPOLINE_SIZE (! TARGET_BIG_ENDIAN_DATA ? 14 : 20) +#define TRAMPOLINE_ALIGNMENT 32 + +#define NO_PROFILE_COUNTERS 1 +#define PROFILE_BEFORE_PROLOGUE 1 + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tbsr\t__mcount\n"); + + +#define HARD_REGNO_NREGS(REGNO, MODE) CLASS_MAX_NREGS (0, MODE) + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + REGNO_REG_CLASS (REGNO) == GR_REGS + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ( ( GET_MODE_CLASS (MODE1) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \ + == ( GET_MODE_CLASS (MODE2) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT)) + + +#define REGISTER_NAMES \ + { \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" \ + }; + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + { "sp", STACK_POINTER_REGNUM } \ + , { "fp", FRAME_POINTER_REGNUM } \ + , { "arg", ARG_POINTER_REGNUM } \ + , { "chain", STATIC_CHAIN_REGNUM } \ +} + +#define DATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION D,DATA" \ + : "\t.section D,\"aw\",@progbits\n\t.p2align 2") + +#define SDATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION D_2,DATA,ALIGN=2" \ + : "\t.section D_2,\"aw\",@progbits\n\t.p2align 1") + +#undef READONLY_DATA_SECTION_ASM_OP +#define READONLY_DATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION C,ROMDATA,ALIGN=4" \ + : "\t.section C,\"a\",@progbits\n\t.p2align 2") + +#define BSS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION B,DATA,ALIGN=4" \ + : "\t.section B,\"w\",@nobits\n\t.p2align 2") + +#define SBSS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION B_2,DATA,ALIGN=2" \ + : "\t.section B_2,\"w\",@nobits\n\t.p2align 1") + +/* The following definitions are conditional depending upon whether the + compiler is being built or crtstuff.c is being compiled by the built + compiler. */ +#if defined CRT_BEGIN || defined CRT_END +# ifdef __RX_AS100_SYNTAX +# define TEXT_SECTION_ASM_OP "\t.SECTION P,CODE" +# define CTORS_SECTION_ASM_OP "\t.SECTION init_array,CODE" +# define DTORS_SECTION_ASM_OP "\t.SECTION fini_array,CODE" +# define INIT_ARRAY_SECTION_ASM_OP "\t.SECTION init_array,CODE" +# define FINI_ARRAY_SECTION_ASM_OP "\t.SECTION fini_array,CODE" +# else +# define TEXT_SECTION_ASM_OP "\t.section P,\"ax\"" +# define CTORS_SECTION_ASM_OP \ + "\t.section\t.init_array,\"aw\",@init_array" +# define DTORS_SECTION_ASM_OP \ + "\t.section\t.fini_array,\"aw\",@fini_array" +# define INIT_ARRAY_SECTION_ASM_OP \ + "\t.section\t.init_array,\"aw\",@init_array" +# define FINI_ARRAY_SECTION_ASM_OP \ + "\t.section\t.fini_array,\"aw\",@fini_array" +# endif +#else +# define TEXT_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION P,CODE" : "\t.section P,\"ax\"") + +# define CTORS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION init_array,CODE" \ + : "\t.section\t.init_array,\"aw\",@init_array") + +# define DTORS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION fini_array,CODE" \ + : "\t.section\t.fini_array,\"aw\",@fini_array") + +# define INIT_ARRAY_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION init_array,CODE" \ + : "\t.section\t.init_array,\"aw\",@init_array") + +# define FINI_ARRAY_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION fini_array,CODE" \ + : "\t.section\t.fini_array,\"aw\",@fini_array") +#endif + +#define GLOBAL_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.GLB\t" : "\t.global\t") +#define ASM_COMMENT_START " ;" +#define ASM_APP_ON "" +#define ASM_APP_OFF "" +#define LOCAL_LABEL_PREFIX "L" +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +#define ASM_OUTPUT_ALIGN(STREAM, LOG) \ + do \ + { \ + if ((LOG) == 0) \ + break; \ + if (TARGET_AS100_SYNTAX) \ + { \ + if ((LOG) >= 2) \ + fprintf (STREAM, "\t.ALIGN 4\t; %d alignment actually requested\n", 1 << (LOG)); \ + else \ + fprintf (STREAM, "\t.ALIGN 2\n"); \ + } \ + else \ + fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \ + } \ + while (0) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, TARGET_AS100_SYNTAX ? "\t.LWORD L%d\n" : "\t.long .L%d\n", \ + VALUE) + +/* This is how to output an element of a case-vector that is relative. + Note: The local label referenced by the "3b" below is emitted by + the tablejump insn. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, TARGET_AS100_SYNTAX \ + ? "\t.LWORD L%d - ?-\n" : "\t.long .L%d - 1b\n", VALUE) + +#define ASM_OUTPUT_SIZE_DIRECTIVE(STREAM, NAME, SIZE) \ + do \ + { \ + HOST_WIDE_INT size_ = (SIZE); \ + \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + \ + fputs (SIZE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ", " HOST_WIDE_INT_PRINT_DEC "\n", size_); \ + } \ + while (0) + +#define ASM_OUTPUT_MEASURED_SIZE(STREAM, NAME) \ + do \ + { \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + fputs (SIZE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", .-", STREAM); \ + assemble_name (STREAM, NAME); \ + putc ('\n', STREAM); \ + } \ + while (0) + +#define ASM_OUTPUT_TYPE_DIRECTIVE(STREAM, NAME, TYPE) \ + do \ + { \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + fputs (TYPE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", ", STREAM); \ + fprintf (STREAM, TYPE_OPERAND_FMT, TYPE); \ + putc ('\n', STREAM); \ + } \ + while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + do \ + { \ + sprintf (LABEL, TARGET_AS100_SYNTAX ? "*%s%u" : "*.%s%u", \ + PREFIX, (unsigned) (NUM)); \ + } \ + while (0) + +#undef ASM_OUTPUT_EXTERNAL +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + do \ + { \ + if (TARGET_AS100_SYNTAX) \ + targetm.asm_out.globalize_label (FILE, NAME); \ + default_elf_asm_output_external (FILE, DECL, NAME); \ + } \ + while (0) + +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ + do \ + { \ + if (TARGET_AS100_SYNTAX) \ + { \ + fprintf ((FILE), "\t.GLB\t"); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), "\n"); \ + assemble_name ((FILE), (NAME)); \ + switch ((ALIGN) / BITS_PER_UNIT) \ + { \ + case 4: \ + fprintf ((FILE), ":\t.BLKL\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE) / 4); \ + break; \ + case 2: \ + fprintf ((FILE), ":\t.BLKW\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE) / 2); \ + break; \ + default: \ + fprintf ((FILE), ":\t.BLKB\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE)); \ + break; \ + } \ + } \ + else \ + { \ + fprintf ((FILE), "%s", COMMON_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \ + (SIZE), (ALIGN) / BITS_PER_UNIT); \ + } \ + } \ + while (0) + +#undef SKIP_ASM_OP +#define SKIP_ASM_OP (TARGET_AS100_SYNTAX ? "\t.BLKB\t" : "\t.zero\t") + +#undef ASM_OUTPUT_LIMITED_STRING +#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ + do \ + { \ + const unsigned char *_limited_str = \ + (const unsigned char *) (STR); \ + unsigned ch; \ + \ + fprintf ((FILE), TARGET_AS100_SYNTAX \ + ? "\t.BYTE\t\"" : "\t.string\t\""); \ + \ + for (; (ch = *_limited_str); _limited_str++) \ + { \ + int escape; \ + \ + switch (escape = ESCAPES[ch]) \ + { \ + case 0: \ + putc (ch, (FILE)); \ + break; \ + case 1: \ + fprintf ((FILE), "\\%03o", ch); \ + break; \ + default: \ + putc ('\\', (FILE)); \ + putc (escape, (FILE)); \ + break; \ + } \ + } \ + \ + fprintf ((FILE), TARGET_AS100_SYNTAX ? "\"\n\t.BYTE\t0\n" : "\"\n");\ + } \ + while (0) + +#undef IDENT_ASM_OP +#define IDENT_ASM_OP (TARGET_AS100_SYNTAX \ + ? "\t.END\t; Built by: ": "\t.ident\t") + +/* For PIC put jump tables into the text section so that the offsets that + they contain are always computed between two same-section symbols. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +#define PRINT_OPERAND(FILE, X, CODE) \ + rx_print_operand (FILE, X, CODE) +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + rx_print_operand_address (FILE, ADDR) + + +#define CC_NO_CARRY 0400 +#define NOTICE_UPDATE_CC(EXP, INSN) rx_notice_update_cc (EXP, INSN) + +extern int rx_float_compare_mode; + +/* This is a version of REG_P that also returns TRUE for SUBREGs. */ +#define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG) + +/* Like REG_P except that this macro is true for SET expressions. */ +#define SET_P(rtl) (GET_CODE (rtl) == SET) + +#define CAN_DEBUG_WITHOUT_FP 1 + +/* The AS100 assembler does not support .leb128 and .uleb128, but + the compiler-build-time configure tests will have enabled their + use because GAS supports them. So default to generating STABS + debug information instead of DWARF2 when generating AS100 + compatible output. */ +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE (TARGET_AS100_SYNTAX \ + ? DBX_DEBUG : DWARF2_DEBUG) + +#undef CC1_SPEC +#define CC1_SPEC "%{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}}" + +/* For some unknown reason LTO compression is not working, at + least on my local system. So set the default compression + level to none, for now. */ +#define OVERRIDE_OPTIONS \ + do \ + { \ + if (flag_lto_compression_level == -1) \ + flag_lto_compression_level = 0; \ + } \ + while (0) + +/* This macro is used to decide when RX FPU instructions can be used. */ +#define ALLOW_RX_FPU_INSNS flag_unsafe_math_optimizations diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md new file mode 100644 index 00000000000..165da4f41a1 --- /dev/null +++ b/gcc/config/rx/rx.md @@ -0,0 +1,1780 @@ +;; Machine Description for Renesas RX processors +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. + +;; 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 3, 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 COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + + +;; This code iterator allows all branch instructions to +;; be generated from a single define_expand template. +(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu + unordered ordered ]) + +;; This code iterator is used for sign- and zero- extensions. +(define_mode_iterator small_int_modes [(HI "") (QI "")]) + +;; We do not handle DFmode here because by default it is +;; the same as SFmode, and if -m64bit-doubles is active +;; then all operations on doubles have to be handled by +;; library functions. +(define_mode_iterator register_modes + [(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")]) + + +;; Used to map RX condition names to GCC +;; condition names for builtin instructions. +(define_code_iterator gcc_conds [eq ne gt ge lt le gtu geu ltu leu + unge unlt uneq ltgt]) +(define_code_attr rx_conds [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt") + (le "le") (gtu "gtu") (geu "geu") (ltu "ltu") + (leu "leu") (unge "pz") (unlt "n") (uneq "o") + (ltgt "no")]) + +(define_constants + [ + (SP_REG 0) + + (UNSPEC_LOW_REG 0) + (UNSPEC_HIGH_REG 1) + + (UNSPEC_RTE 10) + (UNSPEC_RTFI 11) + (UNSPEC_NAKED 12) + + (UNSPEC_MOVSTR 20) + (UNSPEC_MOVMEM 21) + (UNSPEC_SETMEM 22) + (UNSPEC_STRLEN 23) + (UNSPEC_CMPSTRN 24) + + (UNSPEC_BUILTIN_BRK 30) + (UNSPEC_BUILTIN_CLRPSW 31) + (UNSPEC_BUILTIN_INT 32) + (UNSPEC_BUILTIN_MACHI 33) + (UNSPEC_BUILTIN_MACLO 34) + (UNSPEC_BUILTIN_MULHI 35) + (UNSPEC_BUILTIN_MULLO 36) + (UNSPEC_BUILTIN_MVFACHI 37) + (UNSPEC_BUILTIN_MVFACMI 38) + (UNSPEC_BUILTIN_MVFC 39) + (UNSPEC_BUILTIN_MVFCP 40) + (UNSPEC_BUILTIN_MVTACHI 41) + (UNSPEC_BUILTIN_MVTACLO 42) + (UNSPEC_BUILTIN_MVTC 43) + (UNSPEC_BUILTIN_MVTCP 44) + (UNSPEC_BUILTIN_OPEPC 45) + (UNSPEC_BUILTIN_RACW 46) + (UNSPEC_BUILTIN_REVW 47) + (UNSPEC_BUILTIN_RMPA 48) + (UNSPEC_BUILTIN_ROUND 49) + (UNSPEC_BUILTIN_SAT 50) + (UNSPEC_BUILTIN_SETPSW 51) + (UNSPEC_BUILTIN_WAIT 52) + ] +) + +;; Condition code settings: +;; none - insn does not affect the condition code bits +;; set_zs - insn sets z,s to usable values; +;; set_zso - insn sets z,s,o to usable values; +;; set_zsoc - insn sets z,s,o,c to usable values; +;; clobber - value of cc0 is unknown +(define_attr "cc" "none,set_zs,set_zso,set_zsoc,clobber" (const_string "none")) + +(define_attr "length" "" (const_int 8)) + +(include "predicates.md") +(include "constraints.md") + +;; Pipeline description. + +;; The RX only has a single pipeline. It has five stages (fetch, +;; decode, execute, memory access, writeback) each of which normally +;; takes a single CPU clock cycle. + +;; The timings attribute consists of two numbers, the first is the +;; throughput, which is the number of cycles the instruction takes +;; to execute and generate a result. The second is the latency +;; which is the effective number of cycles the instruction takes to +;; execute if its result is used by the following instruction. The +;; latency is always greater than or equal to the throughput. +;; These values were taken from tables 2.13 and 2.14 in section 2.8 +;; of the RX610 Group Hardware Manual v0.11 + +;; Note - it would be nice to use strings rather than integers for +;; the possible values of this attribute, so that we can have the +;; gcc build mechanism check for values that are not supported by +;; the reservations below. But this will not work because the code +;; in rx_adjust_sched_cost() needs integers not strings. + +(define_attr "timings" "" (const_int 11)) + +(define_automaton "pipelining") +(define_cpu_unit "throughput" "pipelining") + +(define_insn_reservation "throughput__1_latency__1" 1 + (eq_attr "timings" "11") "throughput") +(define_insn_reservation "throughput__1_latency__2" 2 + (eq_attr "timings" "12") "throughput,nothing") +(define_insn_reservation "throughput__2_latency__2" 1 + (eq_attr "timings" "22") "throughput*2") +(define_insn_reservation "throughput__3_latency__3" 1 + (eq_attr "timings" "33") "throughput*3") +(define_insn_reservation "throughput__3_latency__4" 2 + (eq_attr "timings" "34") "throughput*3,nothing") +(define_insn_reservation "throughput__4_latency__4" 1 + (eq_attr "timings" "44") "throughput*4") +(define_insn_reservation "throughput__4_latency__5" 2 + (eq_attr "timings" "45") "throughput*4,nothing") +(define_insn_reservation "throughput__5_latency__5" 1 + (eq_attr "timings" "55") "throughput*5") +(define_insn_reservation "throughput__5_latency__6" 2 + (eq_attr "timings" "56") "throughput*5,nothing") +(define_insn_reservation "throughput__6_latency__6" 1 + (eq_attr "timings" "66") "throughput*6") +(define_insn_reservation "throughput_10_latency_10" 1 + (eq_attr "timings" "1010") "throughput*10") +(define_insn_reservation "throughput_11_latency_11" 1 + (eq_attr "timings" "1111") "throughput*11") +(define_insn_reservation "throughput_16_latency_16" 1 + (eq_attr "timings" "1616") "throughput*16") +(define_insn_reservation "throughput_18_latency_18" 1 + (eq_attr "timings" "1818") "throughput*18") + +;; Comparisons + +(define_expand "cbranchsi4" + [(set (cc0) (compare:CC (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand"))) + (set (pc) + (if_then_else (match_operator:SI 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + "" +) + +(define_expand "cbranchsf4" + [(set (cc0) (compare:CC (match_operand:SF 1 "register_operand") + (match_operand:SF 2 "rx_source_operand"))) + (set (pc) + (if_then_else (match_operator:SI 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions" + "" +) + +;; The TST instruction is not used as it does not set the Carry flag, +;; so for example, the LessThan comparison cannot be tested. +;; +;; (define_insn "tstsi" +;; [(set (cc0) +;; (match_operand:SI 0 "rx_source_operand" "r,i,Q")))] +;; "" +;; { +;; rx_float_compare_mode = false; +;; return "tst\t%Q0"; +;; } +;; [(set_attr "cc" "set_zs") +;; (set_attr "timings" "11,11,33") +;; (set_attr "length" "3,7,6")] +;; ) + +(define_insn "cmpsi" + [(set (cc0) (compare:CC + (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI 1 "rx_source_operand" + "r,Uint04,Int08,Sint16,Sint24,i,Q")))] + "" + { + rx_float_compare_mode = false; + return "cmp\t%Q1, %Q0"; + } + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,5")] +) + +;; This pattern is disabled when -fnon-call-exceptions is active because +;; it could generate a floating point exception, which would introduce an +;; edge into the flow graph between this insn and the conditional branch +;; insn to follow, thus breaking the cc0 relationship. Run the g++ test +;; g++.dg/eh/080514-1.C to see this happen. +(define_insn "cmpsf" + [(set (cc0) + (compare:CC (match_operand:SF 0 "register_operand" "r,r,r") + (match_operand:SF 1 "rx_source_operand" "r,i,Q")))] + "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions" + { + rx_float_compare_mode = true; + return "fcmp\t%1, %0"; + } + [(set_attr "cc" "set_zso") + (set_attr "timings" "11,11,33") + (set_attr "length" "3,7,5")] +) + +;; Flow Control Instructions: + +(define_expand "b<code>" + [(set (pc) + (if_then_else (most_cond (cc0) (const_int 0)) + (label_ref (match_operand 0)) + (pc)))] + "" + "" +) + +(define_insn "*conditional_branch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + { + return rx_gen_cond_branch_template (operands[1], false); + } + [(set_attr "length" "8") ;; This length is wrong, but it is + ;; too hard to compute statically. + (set_attr "timings" "33") ;; The timing assumes that the branch is taken. + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "*reveresed_conditional_branch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + { + return rx_gen_cond_branch_template (operands[1], true); + } + [(set_attr "length" "8") ;; This length is wrong, but it is + ;; too hard to compute statically. + (set_attr "timings" "33") ;; The timing assumes that the branch is taken. + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "bra\t%0" + [(set_attr "length" "4") + (set_attr "timings" "33") + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp\t%0" + [(set_attr "length" "2") + (set_attr "timings" "33") + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + { return flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0" + : "\n1:\tbra\t%0") + : "jmp\t%0"; + } + [(set_attr "cc" "clobber") ;; FIXME: This clobber is wrong. + (set_attr "timings" "33") + (set_attr "length" "2")] +) + +(define_insn "simple_return" + [(return)] + "" + "rts" + [(set_attr "length" "1") + (set_attr "timings" "55")] +) + +(define_insn "deallocate_and_return" + [(set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 0 "immediate_operand" "i"))) + (return)] + "" + "rtsd\t%0" + [(set_attr "length" "2") + (set_attr "timings" "55")] +) + +(define_insn "pop_and_return" + [(match_parallel 1 "rx_rtsd_vector" + [(set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_popm (operands, false); + return ""; + } + [(set_attr "length" "3") + (set_attr "timings" "56")] +) + +(define_insn "fast_interrupt_return" + [(unspec_volatile [(return)] UNSPEC_RTFI) ] + "" + "rtfi" + [(set_attr "length" "2") + (set_attr "timings" "33")] +) + +(define_insn "exception_return" + [(unspec_volatile [(return)] UNSPEC_RTE) ] + "" + "rte" + [(set_attr "length" "2") + (set_attr "timings" "66")] +) + +(define_insn "naked_return" + [(unspec_volatile [(return)] UNSPEC_NAKED) ] + "" + "; Naked function: epilogue provided by programmer." +) + + +;; Note - the following set of patterns do not use the "memory_operand" +;; predicate or an "m" constraint because we do not allow symbol_refs +;; or label_refs as legitmate memory addresses. This matches the +;; behaviour of most of the RX instructions. Only the call/branch +;; instructions are allowed to refer to symbols/labels directly. +;; The call operands are in QImode because that is the value of +;; FUNCTION_MODE + +(define_expand "call" + [(call (match_operand:QI 0 "general_operand") + (match_operand:SI 1 "general_operand"))] + "" + { + rtx dest = XEXP (operands[0], 0); + + if (! rx_call_operand (dest, Pmode)) + dest = force_reg (Pmode, dest); + emit_call_insn (gen_call_internal (dest, operands[1])); + DONE; + } +) + +(define_insn "call_internal" + [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol")) + (match_operand:SI 1 "general_operand" "g,g"))] + "" + "@ + jsr\t%A0 + bsr\t%A0" + [(set_attr "length" "2,4") + (set_attr "timings" "33")] +) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand") + (call (match_operand:QI 1 "general_operand") + (match_operand:SI 2 "general_operand")))] + "" + { + rtx dest = XEXP (operands[1], 0); + + if (! rx_call_operand (dest, Pmode)) + dest = force_reg (Pmode, dest); + emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2])); + DONE; + } +) + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=r,r") + (call (mem:QI (match_operand:SI 1 "rx_call_operand" "r,Symbol")) + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + jsr\t%A1 + bsr\t%A1" + [(set_attr "length" "2,4") + (set_attr "timings" "33")] +) + +(define_insn "sibcall" + [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 1 "general_operand" "g")) + (return) + (use (match_operand 2 "" ""))] + "" + "bra\t%A0" + [(set_attr "length" "4") + (set_attr "timings" "33")] +) + +(define_insn "sibcall_value" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 2 "general_operand" "g"))) + (return) + (use (match_operand 3 "" ""))] + "" + "bra\t%A1" + [(set_attr "length" "4") + (set_attr "timings" "33")] +) + +;; Function Prologue/Epilogue Instructions + +(define_expand "prologue" + [(const_int 0)] + "" + "rx_expand_prologue (); DONE;" +) + +(define_expand "epilogue" + [(return)] + "" + "rx_expand_epilogue (false); DONE;" +) + +(define_expand "sibcall_epilogue" + [(return)] + "" + "rx_expand_epilogue (true); DONE;" +) + +;; Move Instructions + +;; Note - we do not allow memory to memory moves, even though the ISA +;; supports them. The reason is that the conditions on such moves are +;; too restrictive, specifically the source addressing mode is limited +;; by the destination addressing mode and vice versa. (For example it +;; is not possible to use indexed register indirect addressing for one +;; of the operands if the other operand is anything other than a register, +;; but it is possible to use register relative addressing when the other +;; operand also uses register relative or register indirect addressing). +;; +;; GCC does not support computing legitimate addresses based on the +;; nature of other operands involved in the instruction, and reload is +;; not smart enough to cope with a whole variety of different memory +;; addressing constraints, so it is simpler and safer to just refuse +;; to support memory to memory moves. + +(define_expand "mov<register_modes:mode>" + [(set (match_operand:register_modes 0 "general_operand") + (match_operand:register_modes 1 "general_operand"))] + "" + { + if (MEM_P (operand0) && MEM_P (operand1)) + operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1); + } +) + +(define_insn "*mov<register_modes:mode>_internal" + [(set (match_operand:register_modes + 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q") + (match_operand:register_modes + 1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i"))] + "" + { return rx_gen_move_template (operands, false); } + [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8") + (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11")] +) + +(define_insn "extend<small_int_modes:mode>si2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:small_int_modes + 1 "nonimmediate_operand" "r,m")))] + "" + { return rx_gen_move_template (operands, false); } + [(set_attr "length" "2,6") + (set_attr "timings" "11,12")] +) + +(define_insn "zero_extend<small_int_modes:mode>si2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:small_int_modes + 1 "nonimmediate_operand" "r,m")))] + "" + { return rx_gen_move_template (operands, true); } + [(set_attr "length" "2,4") + (set_attr "timings" "11,12")] +) + +(define_insn "stack_push" + [(set:SI (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (const_int 4))) + (set:SI (mem:SI (reg:SI SP_REG)) + (match_operand:SI 0 "register_operand" "r"))] + "" + "push.l\t%0" + [(set_attr "length" "2")] +) + +(define_insn "stack_pushm" + [(match_parallel 1 "rx_store_multiple_vector" + [(set:SI (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_pushm (operands); + return ""; + } + [(set_attr "length" "2") + (set_attr "timings" "44")] ;; The timing is a guesstimate average timing. +) + +(define_insn "stack_pop" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (mem:SI (reg:SI SP_REG))) + (set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (const_int 4)))] + "" + "pop\t%0" + [(set_attr "length" "2") + (set_attr "timings" "12")] +) + +(define_insn "stack_popm" + [(match_parallel 1 "rx_load_multiple_vector" + [(set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_popm (operands, true); + return ""; + } + [(set_attr "length" "2") + (set_attr "timings" "45")] ;; The timing is a guesstimate average timing. +) + +(define_insn "cstoresi4" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") + (match_operator:SI + 1 "comparison_operator" + [(match_operand:SI + 2 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI + 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")]))] + "" + { + rx_float_compare_mode = false; + return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0"; + } + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,22,22,22,22,22,44") + (set_attr "length" "5,5,6,7,8,9,8")] +) + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand") + (if_then_else:SI (match_operand:SI 1 "comparison_operator") + (match_operand:SI 2 "nonmemory_operand") + (match_operand:SI 3 "immediate_operand")))] + "" + { + if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) + FAIL; + if (! CONST_INT_P (operands[3])) + FAIL; + } +) + +(define_insn "*movsieq" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (if_then_else:SI (eq (match_operand:SI + 3 "register_operand" "r,r,r") + (match_operand:SI + 4 "rx_source_operand" "riQ,riQ,riQ")) + (match_operand:SI + 1 "nonmemory_operand" "0,i,r") + (match_operand:SI + 2 "immediate_operand" "i,i,i")))] + "" + "@ + cmp\t%Q4, %Q3\n\tstnz\t%2, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "13,19,15") + (set_attr "timings" "22,33,33")] +) + +(define_insn "*movsine" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (if_then_else:SI (ne (match_operand:SI 3 "register_operand" "r,r,r") + (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ")) + (match_operand:SI 1 "nonmemory_operand" "0,i,r") + (match_operand:SI 2 "immediate_operand" "i,i,i")))] + "" + "@ + cmp\t%Q4, %Q3\n\tstz\t%2, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "13,19,15") + (set_attr "timings" "22,33,33")] +) + +;; Arithmetic Instructions + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (abs:SI (match_operand:SI 1 "register_operand" "0,r")))] + "" + "@ + abs\t%0 + abs\t%1, %0" + [(set_attr "cc" "set_zso") + (set_attr "length" "2,3")] +) + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" + "=r,r,r,r,r,r,r,r,r,r,r,r") + (plus:SI (match_operand:SI + 1 "register_operand" + "%0,0,0,0,0,0,r,r,r,r,r,0") + (match_operand:SI + 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Sint08,Sint16,Sint24,i,Q")))] + "" + "@ + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%Q2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,3,3,4,5,6,5")] +) + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") + (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:DI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "add\t%L2, %L0\n\tadc\t%H2, %H0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,22,22,22,22,44") + (set_attr "length" "5,7,9,11,13,11")] +) + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,0,Q") + (match_operand:SI + 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))] + "" + "@ + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %1, %0 + and\t%Q2, %0 + and\t%Q1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,3,5,5")] +) + +;; Byte swap (single 32-bit value). +(define_insn "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "+r") + (bswap:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "revl\t%1, %0" + [(set_attr "length" "3")] +) + +;; Byte swap (single 16-bit value). Note - we ignore the swapping of the high 16-bits. +(define_insn "bswaphi2" + [(set (match_operand:HI 0 "register_operand" "+r") + (bswap:HI (match_operand:HI 1 "register_operand" "r")))] + "" + "revw\t%1, %0" + [(set_attr "length" "3")] +) + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (div:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") + (match_operand:SI + 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "div\t%Q2, %0" + [(set_attr "cc" "clobber") + (set_attr "timings" "1111") ;; Strictly speaking the timing should be + ;; 2222, but that is a worst case sceanario. + (set_attr "length" "3,4,5,6,7,6")] +) + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (udiv:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") + (match_operand:SI + 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "divu\t%Q2, %0" + [(set_attr "cc" "clobber") + (set_attr "timings" "1010") ;; Strictly speaking the timing should be + ;; 2020, but that is a worst case sceanario. + (set_attr "length" "3,4,5,6,7,6")] +) + +;; Note - these patterns are suppressed in big-endian mode because they +;; generate a little endian result. ie the most significant word of the +;; result is placed in the higher numbered register of the destination +;; register pair. + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") + (mult:DI (sign_extend:DI (match_operand:SI + 1 "register_operand" "%0,0,0,0,0,0")) + (sign_extend:DI (match_operand:SI + 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q"))))] + "! TARGET_BIG_ENDIAN_DATA" + "@ + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6") + (set_attr "timings" "22,22,22,22,22,44")] +) + +;; See comment for mulsidi3. +;; Note - the zero_extends are to distinguish this pattern from the +;; mulsidi3 pattern. Immediate mode addressing is not supported +;; because gcc cannot handle the expression: (zero_extend (const_int)). +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" + "=r,r") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" + "%0,0")) + (zero_extend:DI (match_operand:SI 2 "rx_compare_operand" + "r,Q"))))] + "! TARGET_BIG_ENDIAN_DATA" + "@ + emulu\t%Q2, %0 + emulu\t%Q2, %0" + [(set_attr "length" "3,6") + (set_attr "timings" "22,44")] +) + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (smax:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "max\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6") + (set_attr "timings" "11,11,11,11,11,33")] +) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") + (smin:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q,r")))] + "" + "@ + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + mov.l\t%1,%0\n\tmin\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6,5") + (set_attr "timings" "11,11,11,11,11,33,22")] +) + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,Q,r") + (match_operand:SI 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,Q,0,r")))] + "" + "@ + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q1, %0 + mul\t%Q2, %1, %0" + [(set_attr "length" "2,2,3,4,5,6,5,5,3") + (set_attr "timings" "11,11,11,11,11,11,33,33,11")] +) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (neg:SI (match_operand:SI 1 "register_operand" "0,r")))] + ;; The NEG instruction does not comply with -fwrapv semantics. + ;; See gcc.c-torture/execute/pr22493-1.c for an example of this. + "! flag_wrapv" + "@ + neg\t%0 + neg\t%1, %0" + [(set_attr "length" "2,3")] +) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (not:SI (match_operand:SI 1 "register_operand" "0,r")))] + "" + "@ + not\t%0 + not\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "2,3")] +) + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,0,Q") + (match_operand:SI 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))] + "" + "@ + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %1, %0 + or\t%Q2, %0 + or\t%Q1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,3,5,5")] +) + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn")))] + "" + "rotl\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "3")] +) + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn")))] + "" + "rotr\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "3")] +) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shar\t%2, %0 + shar\t%2, %0 + shar\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shlr\t%2, %0 + shlr\t%2, %0 + shlr\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shll\t%2, %0 + shll\t%2, %0 + shll\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") + (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))] + "" + "@ + sub\t%2, %0 + sub\t%2, %0 + add\t%N2, %0 + sub\t%2, %1, %0 + sub\t%Q2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,33") + (set_attr "length" "2,2,6,3,5")] +) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (minus:DI (match_operand:DI 1 "register_operand" "0,0") + (match_operand:DI 2 "rx_source_operand" "r,Q")))] + "" + "sub\t%L2, %L0\n\tsbb\t%H2, %H0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,44") + (set_attr "length" "5,11")] +) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "@ + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,33") + (set_attr "length" "3,4,5,6,7,6")] +) + +;; Floating Point Instructions +;; These patterns are only enabled with -ffast-math because the RX FPU +;; cannot handle sub-normal values. + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (plus:SF (match_operand:SF 1 "register_operand" "%0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "@ + fadd\t%2, %0 + fadd\t%2, %0 + fadd\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "44,44,66") + (set_attr "length" "3,7,5")] +) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (div:SF (match_operand:SF 1 "register_operand" "0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "fdiv\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "1616,1616,1818") + (set_attr "length" "3,7,5")] +) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "@ + fmul\t%2, %0 + fmul\t%2, %0 + fmul\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "33,33,55") + (set_attr "length" "3,7,5")] +) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (minus:SF (match_operand:SF 1 "register_operand" "0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "fsub\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "44,44,66") + (set_attr "length" "3,7,5")] +) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))] + "ALLOW_RX_FPU_INSNS" + "ftoi\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,5")] +) + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=r,r") + (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))] + "ALLOW_RX_FPU_INSNS" + "itof\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,6")] +) + +;; Bit manipulation instructions. +;; Note - there are two versions of each pattern because the memory +;; accessing versions use QImode whilst the register accessing +;; versions use SImode. +;; The peephole are here because the combiner only looks at a maximum +;; of three instructions at a time. + +(define_insn "bitset" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (ior:SI (match_operand:SI 1 "register_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri"))))] + "" + "bset\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitset_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (ior:QI (match_operand:QI 1 "memory_operand" "0") + (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri"))))] + "" + "bset\t%2, %0.B" + [(set_attr "length" "3") + (set_attr "timings" "34")] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg C) (ior (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (ior:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (ior:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg A) (ior (reg A) (reg C))) +;; (set (reg C) (reg A) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (ior:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (ior:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] +) + +(define_insn "bitinvert" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (xor:SI (match_operand:SI 1 "register_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri"))))] + "" + "bnot\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitinvert_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (xor:QI (match_operand:QI 1 "register_operand" "0") + (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri"))))] + "" + "bnot\t%2, %0.B" + [(set_attr "length" "5") + (set_attr "timings" "33")] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg C) (xor (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (xor:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (xor:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] + "" +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg A) (xor (reg A) (reg C))) +;; (set (reg C) (reg A)) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (xor:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (xor:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] + "" +) + +(define_insn "bitclr" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (and:SI (match_operand:SI 1 "register_operand" "0") + (not:SI (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri")))))] + "" + "bclr\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitclr_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (and:QI (match_operand:QI 1 "memory_operand" "0") + (not:QI (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri")))))] + "" + "bclr\t%2, %0.B" + [(set_attr "length" "3") + (set_attr "timings" "34")] +) + +;; (set (reg A) (const_int -2)) +;; (set (reg A) (rotate (reg A) (reg B))) +;; (set (reg C) (and (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int -2)) + (set:SI (match_dup 0) + (rotate:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (and:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (and:SI (match_dup 2) + (not:SI (ashift:SI (const_int 1) + (match_dup 1)))))] +) + +;; (set (reg A) (const_int -2)) +;; (set (reg A) (rotate (reg A) (reg B))) +;; (set (reg A) (and (reg A) (reg C))) +;; (set (reg C) (reg A) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int -2)) + (set:SI (match_dup 0) + (rotate:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (and:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (and:SI (match_dup 2) + (not:SI (ashift:SI (const_int 1) + (match_dup 1)))))] +) + +(define_expand "insv" + [(set:SI (zero_extract:SI (match_operand:SI + 0 "nonimmediate_operand") ;; Destination + (match_operand + 1 "immediate_operand") ;; # of bits to set + (match_operand + 2 "immediate_operand")) ;; Starting bit + (match_operand + 3 "immediate_operand"))] ;; Bits to insert + "" + { + if (rx_expand_insv (operands)) + DONE; + FAIL; + } +) + +;; Atomic exchange operation. + +(define_insn "sync_lock_test_and_setsi" + [(set:SI (match_operand:SI 0 "register_operand" "=r,r") + (match_operand:SI 1 "rx_compare_operand" "=r,Q")) + (set:SI (match_dup 1) + (match_operand:SI 2 "register_operand" "0,0"))] + "" + "xchg\t%1, %0" + [(set_attr "length" "3,6") + (set_attr "timings" "22")] +) + + +;; Block move functions. + +(define_expand "movstr" + [(set:SI (match_operand:BLK 1 "memory_operand") ;; Dest + (match_operand:BLK 2 "memory_operand")) ;; Source + (use (match_operand:SI 0 "register_operand")) ;; Updated Dest + ] + "" + { + rtx addr1 = gen_rtx_REG (SImode, 1); + rtx addr2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + rtx dest_copy = gen_reg_rtx (SImode); + + emit_move_insn (len, GEN_INT (-1)); + emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX)); + operands[1] = replace_equiv_address_nv (operands[1], addr1); + operands[2] = replace_equiv_address_nv (operands[2], addr2); + emit_move_insn (dest_copy, addr1); + emit_insn (gen_rx_movstr ()); + emit_move_insn (len, GEN_INT (-1)); + emit_insn (gen_rx_strend (operands[0], dest_copy)); + DONE; + } +) + +(define_insn "rx_movstr" + [(set:SI (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + ] + "" + "smovu" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_insn "rx_strend" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") + (reg:SI 3)] UNSPEC_STRLEN)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + ] + "" + "mov\t%1, r1\n\tmov\t#0, r2\n\tsuntil.b\n\tmov\tr1, %0\n\tsub\t#1, %0" + [(set_attr "length" "10") + (set_attr "cc" "clobber") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "movmemsi" + [(parallel + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:BLK 1 "memory_operand")) ;; Source + (use (match_operand:SI 2 "register_operand")) ;; Length in bytes + (match_operand 3 "immediate_operand") ;; Align + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM)] + )] + "" + { + rtx addr1 = gen_rtx_REG (SImode, 1); + rtx addr2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + if (REG_P (operands[0]) && (REGNO (operands[0]) == 2 + || REGNO (operands[0]) == 3)) + FAIL; + if (REG_P (operands[1]) && (REGNO (operands[1]) == 1 + || REGNO (operands[1]) == 3)) + FAIL; + if (REG_P (operands[2]) && (REGNO (operands[2]) == 1 + || REGNO (operands[2]) == 2)) + FAIL; + emit_move_insn (addr1, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (addr2, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[2], NULL_RTX)); + operands[0] = replace_equiv_address_nv (operands[0], addr1); + operands[1] = replace_equiv_address_nv (operands[1], addr2); + emit_insn (gen_rx_movmem ()); + DONE; + } +) + +(define_insn "rx_movmem" + [(set (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) + (use (reg:SI 3)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "smovf" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "setmemsi" + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:QI 2 "nonmemory_operand")) ;; Value + (use (match_operand:SI 1 "nonmemory_operand")) ;; Length + (match_operand 3 "immediate_operand") ;; Align + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)] + "" + { + rtx addr = gen_rtx_REG (SImode, 1); + rtx val = gen_rtx_REG (QImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (addr, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[1], NULL_RTX)); + emit_move_insn (val, operands[2]); + emit_insn (gen_rx_setmem ()); + DONE; + } +) + +(define_insn "rx_setmem" + [(set:BLK (mem:BLK (reg:SI 1)) (reg 2)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM) + (clobber (reg:SI 1)) + (clobber (reg:SI 3))] + "" + "sstr.b" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "cmpstrnsi" + [(set (match_operand:SI + 0 "register_operand") ;; Result + (unspec_volatile:SI [(match_operand:BLK + 1 "memory_operand") ;; String1 + (match_operand:BLK + 2 "memory_operand")] ;; String2 + UNSPEC_CMPSTRN)) + (use (match_operand:SI + 3 "register_operand")) ;; Max Length + (match_operand:SI + 4 "immediate_operand")] ;; Known Align + "" + { + rtx str1 = gen_rtx_REG (SImode, 1); + rtx str2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[3], NULL_RTX)); + + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_expand "cmpstrsi" + [(set (match_operand:SI + 0 "register_operand") ;; Result + (unspec_volatile:SI [(match_operand:BLK + 1 "memory_operand") ;; String1 + (match_operand:BLK + 2 "memory_operand")] ;; String2 + UNSPEC_CMPSTRN)) + (match_operand:SI + 3 "immediate_operand")] ;; Known Align + "" + { + rtx str1 = gen_rtx_REG (SImode, 1); + rtx str2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (str1, force_reg (SImode, XEXP (operands[1], 0))); + emit_move_insn (str2, force_reg (SImode, XEXP (operands[2], 0))); + emit_move_insn (len, GEN_INT (-1)); + + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_insn "rx_cmpstrn" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)] + UNSPEC_CMPSTRN)) + (use (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:BLK 2 "memory_operand" "m")) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "scmpu ; Perform the string comparison + mov #-1, %0 ; Set up -1 result (which cannot be created + ; by the SC insn) + bnc ?+ ; If Carry is not set skip over + scne.L %0 ; Set result based on Z flag +?: +" + [(set_attr "length" "9") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +;; Builtin Functions +;; +;; GCC does not have the ability to generate the following instructions +;; on its own so they are provided as builtins instead. To use them from +;; a program for example invoke them as __builtin_rx_<insn_name>. For +;; example: +;; +;; int short_byte_swap (int arg) { return __builtin_rx_revw (arg); } + +;;---------- Accumulator Support ------------------------ + +;; Multiply & Accumulate (high) +(define_insn "machi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MACHI)] + "" + "machi\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply & Accumulate (low) +(define_insn "maclo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MACLO)] + "" + "maclo\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply (high) +(define_insn "mulhi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MULHI)] + "" + "mulhi\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply (low) +(define_insn "mullo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MULLO)] + "" + "mullo\t%0, %1" + [(set_attr "length" "3")] +) + +;; Move from Accumulator (high) +(define_insn "mvfachi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] + UNSPEC_BUILTIN_MVFACHI))] + "" + "mvfachi\t%0" + [(set_attr "length" "3")] +) + +;; Move from Accumulator (middle) +(define_insn "mvfacmi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] + UNSPEC_BUILTIN_MVFACMI))] + "" + "mvfacmi\t%0" + [(set_attr "length" "3")] +) + +;; Move to Accumulator (high) +(define_insn "mvtachi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_BUILTIN_MVTACHI)] + "" + "mvtachi\t%0" + [(set_attr "length" "3")] +) + +;; Move to Accumulator (low) +(define_insn "mvtaclo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_BUILTIN_MVTACLO)] + "" + "mvtaclo\t%0" + [(set_attr "length" "3")] +) + +;; Round Accumulator +(define_insn "racw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_RACW)] + "" + "racw\t%0" + [(set_attr "length" "3")] +) + +;; Repeat multiply and accumulate +(define_insn "rmpa" + [(unspec:SI [(const_int 0) (reg:SI 1) (reg:SI 2) (reg:SI 3) + (reg:SI 4) (reg:SI 5) (reg:SI 6)] + UNSPEC_BUILTIN_RMPA) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "rmpa" + [(set_attr "length" "2") + (set_attr "timings" "1010")] +) + +;;---------- Arithmetic ------------------------ + +;; Byte swap (two 16-bit values). +(define_insn "revw" + [(set (match_operand:SI 0 "register_operand" "+r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_REVW))] + "" + "revw\t%1, %0" + [(set_attr "length" "3")] +) + +;; Round to integer. +(define_insn "lrintsf2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(match_operand:SF 1 "rx_compare_operand" "r,Q")] + UNSPEC_BUILTIN_ROUND))] + "" + "round\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,5")] +) + +;; Saturate to 32-bits +(define_insn "sat" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "0")] + UNSPEC_BUILTIN_SAT))] + "" + "sat\t%0" + [(set_attr "length" "2")] +) + +;;---------- Control Registers ------------------------ + +;; Clear Processor Status Word +(define_insn "clrpsw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_CLRPSW) + (clobber (cc0))] + "" + "clrpsw\t%F0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")] +) + +;; Set Processor Status Word +(define_insn "setpsw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_SETPSW) + (clobber (cc0))] + "" + "setpsw\t%F0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")] +) + +;; Move from control register +(define_insn "mvfc" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "immediate_operand" "i")] + UNSPEC_BUILTIN_MVFC))] + "" + "mvfc\t%C1, %0" + [(set_attr "length" "3")] +) + +;; Move to control register +(define_insn "mvtc" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i") + (match_operand:SI 1 "nonmemory_operand" "r,i")] + UNSPEC_BUILTIN_MVTC) + (clobber (cc0))] + "" + "mvtc\t%1, %C0" + [(set_attr "length" "3,7") + (set_attr "cc" "clobber")] ;; Just in case the control + ;; register selected is the psw. +) + +;;---------- Interrupts ------------------------ + +;; Break +(define_insn "brk" + [(unspec_volatile [(const_int 0)] + UNSPEC_BUILTIN_BRK)] + "" + "brk" + [(set_attr "length" "1") + (set_attr "timings" "66")] +) + +;; Interrupt +(define_insn "int" + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_INT)] + "" + "int\t%0" + [(set_attr "length" "3")] +) + +;; Wait +(define_insn "wait" + [(unspec_volatile [(const_int 0)] + UNSPEC_BUILTIN_WAIT)] + "" + "wait" + [(set_attr "length" "2")] +) + +;;---------- CoProcessor Support ------------------------ + +;; FIXME: The instructions are currently commented out because +;; the bit patterns have not been finalized, so the assembler +;; does not support them. Once they are decided and the assembler +;; supports them, enable the instructions here. + +;; Move from co-processor register +(define_insn "mvfcp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_BUILTIN_MVFCP))] + "" + "; mvfcp\t%1, %0, %2" + [(set_attr "length" "5")] +) + +;; Move to co-processor register +(define_insn "mvtcp" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i") + (match_operand:SI 1 "nonmemory_operand" "i,r") + (match_operand:SI 2 "immediate_operand" "i,i")] + UNSPEC_BUILTIN_MVTCP)] + "" + "; mvtcp\t%0, %1, %2" + [(set_attr "length" "7,5")] +) + +;; Co-processor operation +(define_insn "opecp" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i") + (match_operand:SI 1 "immediate_operand" "i")] + UNSPEC_BUILTIN_OPEPC)] + "" + "; opecp\t%0, %1" + [(set_attr "length" "5")] +) + +;;---------- Misc ------------------------ + +;; Required by cfglayout.c... +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "length" "1")] +) diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt new file mode 100644 index 00000000000..83e75bfba76 --- /dev/null +++ b/gcc/config/rx/rx.opt @@ -0,0 +1,74 @@ +; Command line options for the Renesas RX port of GCC. +; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; 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 3, 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 COPYING3. If not see +; <http://www.gnu.org/licenses/>. +;--------------------------------------------------- + +m64bit-doubles +Target RejectNegative Mask(64BIT_DOUBLES) +Store doubles in 64 bits. + +m32bit-doubles +Target RejectNegative InverseMask(64BIT_DOUBLES) +Stores doubles in 32 bits. This is the default. + +;--------------------------------------------------- + +mbig-endian-data +Target RejectNegative Mask(BIG_ENDIAN_DATA) +Data is stored in big-endian format. + +mlittle-endian-data +Target RejectNegative InverseMask(BIG_ENDIAN_DATA) +Data is stored in little-endian format. (Default). + +;--------------------------------------------------- + +msmall-data-limit= +Target RejectNegative Joined UInteger Var(rx_small_data_limit) Init(0) +Maximum size of global and static variables which can be placed into the small data area. + +;--------------------------------------------------- + +msim +Target +Use the simulator runtime. + +;--------------------------------------------------- + +mas100-syntax +Target Mask(AS100_SYNTAX) +Generate assembler output that is compatible with the Renesas AS100 assembler. This may restrict some of the compiler's capabilities. The default is to generate GAS compatable syntax. + +;--------------------------------------------------- + +mrelax +Target +Enable linker relaxation. + +;--------------------------------------------------- + +mmax-constant-size= +Target RejectNegative Joined UInteger Var(rx_max_constant_size) Init(0) +Maximum size in bytes of constant values allowed as operands. + +;--------------------------------------------------- + +mint-register= +Target RejectNegative Joined UInteger Var(rx_interrupt_registers) Init(0) +Specifies the number of registers to reserve for interrupt handlers. diff --git a/gcc/config/rx/t-rx b/gcc/config/rx/t-rx new file mode 100644 index 00000000000..39cda72af57 --- /dev/null +++ b/gcc/config/rx/t-rx @@ -0,0 +1,32 @@ +# Makefile fragment for building GCC for the Renesas RX target. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# Enable multilibs: + +MULTILIB_OPTIONS = m64bit-doubles mbig-endian-data +MULTILIB_DIRNAMES = 64fp big-endian-data +MULTILIB_MATCHES = m64bit-doubles=mieee +MULTILIB_EXCEPTIONS = +MULTILIB_EXTRA_OPTS = + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index f06098bfc1b..9638e8d265d 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -6825,7 +6825,7 @@ label: (define_insn "stuff_delay_slot" [(set (pc) (unspec [(match_operand:SI 0 "const_int_operand" "") (pc)] UNSPEC_BBR)) - (set (reg:SI T_REG) (match_operand:SI 1 "const_int_operand" ""))] + (match_operand:SI 1 "const_int_operand" "")] "TARGET_SH1" "" [(set_attr "length" "0") diff --git a/gcc/config/spu/cache.S b/gcc/config/spu/cache.S new file mode 100644 index 00000000000..9ffb6a0d194 --- /dev/null +++ b/gcc/config/spu/cache.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + + .data + .p2align 7 + .global __cache +__cache: + .rept __CACHE_SIZE__ * 8 + .fill 128 + .endr + + .p2align 7 + .global __cache_tag_array +__cache_tag_array: + .rept __CACHE_SIZE__ * 2 + .long 1, 1, 1, 1 + .fill 128-16 + .endr +__end_cache_tag_array: + + .globl __cache_tag_array_size + .set __cache_tag_array_size, __end_cache_tag_array-__cache_tag_array + diff --git a/gcc/config/spu/cachemgr.c b/gcc/config/spu/cachemgr.c new file mode 100644 index 00000000000..e7abd5e62db --- /dev/null +++ b/gcc/config/spu/cachemgr.c @@ -0,0 +1,438 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#include <spu_mfcio.h> +#include <spu_internals.h> +#include <spu_intrinsics.h> +#include <spu_cache.h> + +extern unsigned long long __ea_local_store; +extern char __cache_tag_array_size; + +#define LINE_SIZE 128 +#define TAG_MASK (LINE_SIZE - 1) + +#define WAYS 4 +#define SET_MASK ((int) &__cache_tag_array_size - LINE_SIZE) + +#define CACHE_LINES ((int) &__cache_tag_array_size / \ + sizeof (struct __cache_tag_array) * WAYS) + +struct __cache_tag_array +{ + unsigned int tag_lo[WAYS]; + unsigned int tag_hi[WAYS]; + void *base[WAYS]; + int reserved[WAYS]; + vector unsigned short dirty_bits[WAYS]; +}; + +extern struct __cache_tag_array __cache_tag_array[]; +extern char __cache[]; + +/* In order to make the code seem a little cleaner, and to avoid having + 64/32 bit ifdefs all over the place, we use macros. */ + +#ifdef __EA64__ +typedef unsigned long long addr; + +#define CHECK_TAG(_entry, _way, _tag) \ + ((_entry)->tag_lo[(_way)] == ((_tag) & 0xFFFFFFFF) \ + && (_entry)->tag_hi[(_way)] == ((_tag) >> 32)) + +#define GET_TAG(_entry, _way) \ + ((unsigned long long)(_entry)->tag_hi[(_way)] << 32 \ + | (unsigned long long)(_entry)->tag_lo[(_way)]) + +#define SET_TAG(_entry, _way, _tag) \ + (_entry)->tag_lo[(_way)] = (_tag) & 0xFFFFFFFF; \ + (_entry)->tag_hi[(_way)] = (_tag) >> 32 + +#else /*__EA32__*/ +typedef unsigned long addr; + +#define CHECK_TAG(_entry, _way, _tag) \ + ((_entry)->tag_lo[(_way)] == (_tag)) + +#define GET_TAG(_entry, _way) \ + ((_entry)->tag_lo[(_way)]) + +#define SET_TAG(_entry, _way, _tag) \ + (_entry)->tag_lo[(_way)] = (_tag) + +#endif + +/* In GET_ENTRY, we cast away the high 32 bits, + as the tag is only in the low 32. */ + +#define GET_ENTRY(_addr) \ + ((struct __cache_tag_array *) \ + si_to_uint (si_a (si_and (si_from_uint ((unsigned int) (addr) (_addr)), \ + si_from_uint (SET_MASK)), \ + si_from_uint ((unsigned int) __cache_tag_array)))) + +#define GET_CACHE_LINE(_addr, _way) \ + ((void *) (__cache + ((_addr) & SET_MASK) * WAYS) + ((_way) * LINE_SIZE)); + +#define CHECK_DIRTY(_vec) (si_to_uint (si_orx ((qword) (_vec)))) +#define SET_EMPTY(_entry, _way) ((_entry)->tag_lo[(_way)] = 1) +#define CHECK_EMPTY(_entry, _way) ((_entry)->tag_lo[(_way)] == 1) + +#define LS_FLAG 0x80000000 +#define SET_IS_LS(_entry, _way) ((_entry)->reserved[(_way)] |= LS_FLAG) +#define CHECK_IS_LS(_entry, _way) ((_entry)->reserved[(_way)] & LS_FLAG) +#define GET_LRU(_entry, _way) ((_entry)->reserved[(_way)] & ~LS_FLAG) + +static int dma_tag = 32; + +static void +__cache_evict_entry (struct __cache_tag_array *entry, int way) +{ + addr tag = GET_TAG (entry, way); + + if (CHECK_DIRTY (entry->dirty_bits[way]) && !CHECK_IS_LS (entry, way)) + { +#ifdef NONATOMIC + /* Non-atomic writes. */ + unsigned int oldmask, mach_stat; + char *line = ((void *) 0); + + /* Enter critical section. */ + mach_stat = spu_readch (SPU_RdMachStat); + spu_idisable (); + + /* Issue DMA request. */ + line = GET_CACHE_LINE (entry->tag_lo[way], way); + mfc_put (line, tag, LINE_SIZE, dma_tag, 0, 0); + + /* Wait for DMA completion. */ + oldmask = mfc_read_tag_mask (); + mfc_write_tag_mask (1 << dma_tag); + mfc_read_tag_status_all (); + mfc_write_tag_mask (oldmask); + + /* Leave critical section. */ + if (__builtin_expect (mach_stat & 1, 0)) + spu_ienable (); +#else + /* Allocate a buffer large enough that we know it has 128 bytes + that are 128 byte aligned (for DMA). */ + + char buffer[LINE_SIZE + 127]; + qword *buf_ptr = (qword *) (((unsigned int) (buffer) + 127) & ~127); + qword *line = GET_CACHE_LINE (entry->tag_lo[way], way); + qword bits; + unsigned int mach_stat; + + /* Enter critical section. */ + mach_stat = spu_readch (SPU_RdMachStat); + spu_idisable (); + + do + { + /* We atomically read the current memory into a buffer + modify the dirty bytes in the buffer, and write it + back. If writeback fails, loop and try again. */ + + mfc_getllar (buf_ptr, tag, 0, 0); + mfc_read_atomic_status (); + + /* The method we're using to write 16 dirty bytes into + the buffer at a time uses fsmb which in turn uses + the least significant 16 bits of word 0, so we + load the bits and rotate so that the first bit of + the bitmap is in the first bit that fsmb will use. */ + + bits = (qword) entry->dirty_bits[way]; + bits = si_rotqbyi (bits, -2); + + /* Si_fsmb creates the mask of dirty bytes. + Use selb to nab the appropriate bits. */ + buf_ptr[0] = si_selb (buf_ptr[0], line[0], si_fsmb (bits)); + + /* Rotate to next 16 byte section of cache. */ + bits = si_rotqbyi (bits, 2); + + buf_ptr[1] = si_selb (buf_ptr[1], line[1], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[2] = si_selb (buf_ptr[2], line[2], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[3] = si_selb (buf_ptr[3], line[3], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[4] = si_selb (buf_ptr[4], line[4], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[5] = si_selb (buf_ptr[5], line[5], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[6] = si_selb (buf_ptr[6], line[6], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[7] = si_selb (buf_ptr[7], line[7], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + + mfc_putllc (buf_ptr, tag, 0, 0); + } + while (mfc_read_atomic_status ()); + + /* Leave critical section. */ + if (__builtin_expect (mach_stat & 1, 0)) + spu_ienable (); +#endif + } + + /* In any case, marking the lo tag with 1 which denotes empty. */ + SET_EMPTY (entry, way); + entry->dirty_bits[way] = (vector unsigned short) si_from_uint (0); +} + +void +__cache_evict (__ea void *ea) +{ + addr tag = (addr) ea & ~TAG_MASK; + struct __cache_tag_array *entry = GET_ENTRY (ea); + int i = 0; + + /* Cycles through all the possible ways an address could be at + and evicts the way if found. */ + + for (i = 0; i < WAYS; i++) + if (CHECK_TAG (entry, i, tag)) + __cache_evict_entry (entry, i); +} + +static void * +__cache_fill (int way, addr tag) +{ + unsigned int oldmask, mach_stat; + char *line = ((void *) 0); + + /* Reserve our DMA tag. */ + if (dma_tag == 32) + dma_tag = mfc_tag_reserve (); + + /* Enter critical section. */ + mach_stat = spu_readch (SPU_RdMachStat); + spu_idisable (); + + /* Issue DMA request. */ + line = GET_CACHE_LINE (tag, way); + mfc_get (line, tag, LINE_SIZE, dma_tag, 0, 0); + + /* Wait for DMA completion. */ + oldmask = mfc_read_tag_mask (); + mfc_write_tag_mask (1 << dma_tag); + mfc_read_tag_status_all (); + mfc_write_tag_mask (oldmask); + + /* Leave critical section. */ + if (__builtin_expect (mach_stat & 1, 0)) + spu_ienable (); + + return (void *) line; +} + +static void +__cache_miss (__ea void *ea, struct __cache_tag_array *entry, int way) +{ + + addr tag = (addr) ea & ~TAG_MASK; + unsigned int lru = 0; + int i = 0; + int idx = 0; + + /* If way > 4, then there are no empty slots, so we must evict + the least recently used entry. */ + if (way >= 4) + { + for (i = 0; i < WAYS; i++) + { + if (GET_LRU (entry, i) > lru) + { + lru = GET_LRU (entry, i); + idx = i; + } + } + __cache_evict_entry (entry, idx); + way = idx; + } + + /* Set the empty entry's tag and fill it's cache line. */ + + SET_TAG (entry, way, tag); + entry->reserved[way] = 0; + + /* Check if the address is just an effective address within the + SPU's local store. */ + + /* Because the LS is not 256k aligned, we can't do a nice and mask + here to compare, so we must check the whole range. */ + + if ((addr) ea >= (addr) __ea_local_store + && (addr) ea < (addr) (__ea_local_store + 0x40000)) + { + SET_IS_LS (entry, way); + entry->base[way] = + (void *) ((unsigned int) ((addr) ea - + (addr) __ea_local_store) & ~0x7f); + } + else + { + entry->base[way] = __cache_fill (way, tag); + } +} + +void * +__cache_fetch_dirty (__ea void *ea, int n_bytes_dirty) +{ +#ifdef __EA64__ + unsigned int tag_hi; + qword etag_hi; +#endif + unsigned int tag_lo; + struct __cache_tag_array *entry; + + qword etag_lo; + qword equal; + qword bit_mask; + qword way; + + /* This first chunk, we merely fill the pointer and tag. */ + + entry = GET_ENTRY (ea); + +#ifndef __EA64__ + tag_lo = + si_to_uint (si_andc + (si_shufb + (si_from_uint ((addr) ea), si_from_uint (0), + si_from_uint (0x00010203)), si_from_uint (TAG_MASK))); +#else + tag_lo = + si_to_uint (si_andc + (si_shufb + (si_from_ullong ((addr) ea), si_from_uint (0), + si_from_uint (0x04050607)), si_from_uint (TAG_MASK))); + + tag_hi = + si_to_uint (si_shufb + (si_from_ullong ((addr) ea), si_from_uint (0), + si_from_uint (0x00010203))); +#endif + + /* Increment LRU in reserved bytes. */ + si_stqd (si_ai (si_lqd (si_from_ptr (entry), 48), 1), + si_from_ptr (entry), 48); + +missreturn: + /* Check if the entry's lo_tag is equal to the address' lo_tag. */ + etag_lo = si_lqd (si_from_ptr (entry), 0); + equal = si_ceq (etag_lo, si_from_uint (tag_lo)); +#ifdef __EA64__ + /* And the high tag too. */ + etag_hi = si_lqd (si_from_ptr (entry), 16); + equal = si_and (equal, (si_ceq (etag_hi, si_from_uint (tag_hi)))); +#endif + + if ((si_to_uint (si_orx (equal)) == 0)) + goto misshandler; + + if (n_bytes_dirty) + { + /* way = 0x40,0x50,0x60,0x70 for each way, which is also the + offset of the appropriate dirty bits. */ + way = si_shli (si_clz (si_gbb (equal)), 2); + + /* To create the bit_mask, we set it to all 1s (uint -1), then we + shift it over (128 - n_bytes_dirty) times. */ + + bit_mask = si_from_uint (-1); + + bit_mask = + si_shlqby (bit_mask, si_from_uint ((LINE_SIZE - n_bytes_dirty) / 8)); + + bit_mask = + si_shlqbi (bit_mask, si_from_uint ((LINE_SIZE - n_bytes_dirty) % 8)); + + /* Rotate it around to the correct offset. */ + bit_mask = + si_rotqby (bit_mask, + si_from_uint (-1 * ((addr) ea & TAG_MASK) / 8)); + + bit_mask = + si_rotqbi (bit_mask, + si_from_uint (-1 * ((addr) ea & TAG_MASK) % 8)); + + /* Update the dirty bits. */ + si_stqx (si_or (si_lqx (si_from_ptr (entry), way), bit_mask), + si_from_ptr (entry), way); + }; + + /* We've definitely found the right entry, set LRU (reserved) to 0 + maintaining the LS flag (MSB). */ + + si_stqd (si_andc + (si_lqd (si_from_ptr (entry), 48), + si_and (equal, si_from_uint (~(LS_FLAG)))), + si_from_ptr (entry), 48); + + return (void *) + si_to_uint (si_a + (si_orx + (si_and (si_lqd (si_from_ptr (entry), 32), equal)), + si_from_uint (((unsigned int) (addr) ea) & TAG_MASK))); + +misshandler: + equal = si_ceqi (etag_lo, 1); + __cache_miss (ea, entry, (si_to_uint (si_clz (si_gbb (equal))) - 16) >> 2); + goto missreturn; +} + +void * +__cache_fetch (__ea void *ea) +{ + return __cache_fetch_dirty (ea, 0); +} + +void +__cache_touch (__ea void *ea __attribute__ ((unused))) +{ + /* NO-OP for now. */ +} + +void __cache_flush (void) __attribute__ ((destructor)); +void +__cache_flush (void) +{ + struct __cache_tag_array *entry = __cache_tag_array; + unsigned int i; + int j; + + /* Cycle through each cache entry and evict all used ways. */ + + for (i = 0; i < CACHE_LINES / WAYS; i++) + { + for (j = 0; j < WAYS; j++) + if (!CHECK_EMPTY (entry, j)) + __cache_evict_entry (entry, j); + + entry++; + } +} diff --git a/gcc/config/spu/spu-c.c b/gcc/config/spu/spu-c.c index fbbbf32e157..380af402c48 100644 --- a/gcc/config/spu/spu-c.c +++ b/gcc/config/spu/spu-c.c @@ -201,6 +201,17 @@ spu_cpu_cpp_builtins (struct cpp_reader *pfile) if (spu_arch == PROCESSOR_CELLEDP) builtin_define_std ("__SPU_EDP__"); builtin_define_std ("__vector=__attribute__((__spu_vector__))"); + switch (spu_ea_model) + { + case 32: + builtin_define_std ("__EA32__"); + break; + case 64: + builtin_define_std ("__EA64__"); + break; + default: + gcc_unreachable (); + } if (!flag_iso) { diff --git a/gcc/config/spu/spu-elf.h b/gcc/config/spu/spu-elf.h index 532313119cb..68982002103 100644 --- a/gcc/config/spu/spu-elf.h +++ b/gcc/config/spu/spu-elf.h @@ -68,8 +68,14 @@ #define LINK_SPEC "%{mlarge-mem: --defsym __stack=0xfffffff0 }" -#define LIB_SPEC \ - "-( %{!shared:%{g*:-lg}} -lc -lgloss -)" +#define LIB_SPEC "-( %{!shared:%{g*:-lg}} -lc -lgloss -) \ + %{mno-atomic-updates:-lgcc_cachemgr_nonatomic; :-lgcc_cachemgr} \ + %{mcache-size=128:-lgcc_cache128k; \ + mcache-size=64 :-lgcc_cache64k; \ + mcache-size=32 :-lgcc_cache32k; \ + mcache-size=16 :-lgcc_cache16k; \ + mcache-size=8 :-lgcc_cache8k; \ + :-lgcc_cache64k}" /* Turn off warnings in the assembler too. */ #undef ASM_SPEC diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c index ed5d6c59345..2888da67281 100644 --- a/gcc/config/spu/spu.c +++ b/gcc/config/spu/spu.c @@ -154,6 +154,8 @@ static tree spu_builtin_decl (unsigned, bool); static unsigned char spu_scalar_mode_supported_p (enum machine_mode mode); static unsigned char spu_vector_mode_supported_p (enum machine_mode mode); static bool spu_legitimate_address_p (enum machine_mode, rtx, bool); +static bool spu_addr_space_legitimate_address_p (enum machine_mode, rtx, + bool, addr_space_t); static rtx adjust_operand (rtx op, HOST_WIDE_INT * start); static rtx get_pic_reg (void); static int need_to_save_reg (int regno, int saving); @@ -203,15 +205,23 @@ static bool spu_return_in_memory (const_tree type, const_tree fntype); static void fix_range (const char *); static void spu_encode_section_info (tree, rtx, int); static rtx spu_legitimize_address (rtx, rtx, enum machine_mode); +static rtx spu_addr_space_legitimize_address (rtx, rtx, enum machine_mode, + addr_space_t); static tree spu_builtin_mul_widen_even (tree); static tree spu_builtin_mul_widen_odd (tree); static tree spu_builtin_mask_for_load (void); static int spu_builtin_vectorization_cost (bool); static bool spu_vector_alignment_reachable (const_tree, bool); static tree spu_builtin_vec_perm (tree, tree *); +static enum machine_mode spu_addr_space_pointer_mode (addr_space_t); +static enum machine_mode spu_addr_space_address_mode (addr_space_t); +static bool spu_addr_space_subset_p (addr_space_t, addr_space_t); +static rtx spu_addr_space_convert (rtx, tree, tree); static int spu_sms_res_mii (struct ddg *g); static void asm_file_start (void); static unsigned int spu_section_type_flags (tree, const char *, int); +static section *spu_select_section (tree, int, unsigned HOST_WIDE_INT); +static void spu_unique_section (tree, int); static rtx spu_expand_load (rtx, rtx, rtx, int); static void spu_trampoline_init (rtx, tree, rtx); @@ -270,6 +280,10 @@ spu_libgcc_cmp_return_mode (void); static enum machine_mode spu_libgcc_shift_count_mode (void); + +/* Pointer mode for __ea references. */ +#define EAmode (spu_ea_model != 32 ? DImode : SImode) + /* Table of machine attributes. */ static const struct attribute_spec spu_attribute_table[] = @@ -282,6 +296,25 @@ static const struct attribute_spec spu_attribute_table[] = /* TARGET overrides. */ +#undef TARGET_ADDR_SPACE_POINTER_MODE +#define TARGET_ADDR_SPACE_POINTER_MODE spu_addr_space_pointer_mode + +#undef TARGET_ADDR_SPACE_ADDRESS_MODE +#define TARGET_ADDR_SPACE_ADDRESS_MODE spu_addr_space_address_mode + +#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ + spu_addr_space_legitimate_address_p + +#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS +#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS spu_addr_space_legitimize_address + +#undef TARGET_ADDR_SPACE_SUBSET_P +#define TARGET_ADDR_SPACE_SUBSET_P spu_addr_space_subset_p + +#undef TARGET_ADDR_SPACE_CONVERT +#define TARGET_ADDR_SPACE_CONVERT spu_addr_space_convert + #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS spu_init_builtins #undef TARGET_BUILTIN_DECL @@ -296,6 +329,15 @@ static const struct attribute_spec spu_attribute_table[] = #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS spu_legitimize_address +/* The current assembler doesn't like .4byte foo@ppu, so use the normal .long + and .quad for the debugger. When it is known that the assembler is fixed, + these can be removed. */ +#undef TARGET_ASM_UNALIGNED_SI_OP +#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" + +#undef TARGET_ASM_ALIGNED_DI_OP +#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" + /* The .8byte directive doesn't seem to work well for a 32 bit architecture. */ #undef TARGET_ASM_UNALIGNED_DI_OP @@ -412,6 +454,12 @@ static const struct attribute_spec spu_attribute_table[] = #undef TARGET_SECTION_TYPE_FLAGS #define TARGET_SECTION_TYPE_FLAGS spu_section_type_flags +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION spu_select_section + +#undef TARGET_ASM_UNIQUE_SECTION +#define TARGET_ASM_UNIQUE_SECTION spu_unique_section + #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P spu_legitimate_address_p @@ -3613,6 +3661,29 @@ exp2_immediate_p (rtx op, enum machine_mode mode, int low, int high) return FALSE; } +/* Return true if X is a SYMBOL_REF to an __ea qualified variable. */ + +static int +ea_symbol_ref (rtx *px, void *data ATTRIBUTE_UNUSED) +{ + rtx x = *px; + tree decl; + + if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) + { + rtx plus = XEXP (x, 0); + rtx op0 = XEXP (plus, 0); + rtx op1 = XEXP (plus, 1); + if (GET_CODE (op1) == CONST_INT) + x = op0; + } + + return (GET_CODE (x) == SYMBOL_REF + && (decl = SYMBOL_REF_DECL (x)) != 0 + && TREE_CODE (decl) == VAR_DECL + && TYPE_ADDR_SPACE (TREE_TYPE (decl))); +} + /* We accept: - any 32-bit constant (SImode, SFmode) - any constant that can be generated with fsmbi (any mode) @@ -3624,6 +3695,12 @@ spu_legitimate_constant_p (rtx x) { if (GET_CODE (x) == HIGH) x = XEXP (x, 0); + + /* Reject any __ea qualified reference. These can't appear in + instructions but must be forced to the constant pool. */ + if (for_each_rtx (&x, ea_symbol_ref, 0)) + return 0; + /* V4SI with all identical symbols is valid. */ if (!flag_pic && GET_MODE (x) == V4SImode @@ -3662,8 +3739,14 @@ spu_legitimate_address_p (enum machine_mode mode, switch (GET_CODE (x)) { case LABEL_REF: + return !TARGET_LARGE_MEM; + case SYMBOL_REF: case CONST: + /* Keep __ea references until reload so that spu_expand_mov can see them + in MEMs. */ + if (ea_symbol_ref (&x, 0)) + return !reload_in_progress && !reload_completed; return !TARGET_LARGE_MEM; case CONST_INT: @@ -3707,6 +3790,20 @@ spu_legitimate_address_p (enum machine_mode mode, return FALSE; } +/* Like spu_legitimate_address_p, except with named addresses. */ +static bool +spu_addr_space_legitimate_address_p (enum machine_mode mode, rtx x, + bool reg_ok_strict, addr_space_t as) +{ + if (as == ADDR_SPACE_EA) + return (REG_P (x) && (GET_MODE (x) == EAmode)); + + else if (as != ADDR_SPACE_GENERIC) + gcc_unreachable (); + + return spu_legitimate_address_p (mode, x, reg_ok_strict); +} + /* When the address is reg + const_int, force the const_int into a register. */ rtx @@ -3738,6 +3835,17 @@ spu_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, return x; } +/* Like spu_legitimate_address, except with named address support. */ +static rtx +spu_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode, + addr_space_t as) +{ + if (as != ADDR_SPACE_GENERIC) + return x; + + return spu_legitimize_address (x, oldx, mode); +} + /* Handle an attribute requiring a FUNCTION_DECL; arguments as in struct attribute_spec.handler. */ static tree @@ -4241,6 +4349,233 @@ address_needs_split (rtx mem) return 0; } +static GTY(()) rtx cache_fetch; /* __cache_fetch function */ +static GTY(()) rtx cache_fetch_dirty; /* __cache_fetch_dirty function */ +static alias_set_type ea_alias_set = -1; /* alias set for __ea memory */ + +/* MEM is known to be an __ea qualified memory access. Emit a call to + fetch the ppu memory to local store, and return its address in local + store. */ + +static void +ea_load_store (rtx mem, bool is_store, rtx ea_addr, rtx data_addr) +{ + if (is_store) + { + rtx ndirty = GEN_INT (GET_MODE_SIZE (GET_MODE (mem))); + if (!cache_fetch_dirty) + cache_fetch_dirty = init_one_libfunc ("__cache_fetch_dirty"); + emit_library_call_value (cache_fetch_dirty, data_addr, LCT_NORMAL, Pmode, + 2, ea_addr, EAmode, ndirty, SImode); + } + else + { + if (!cache_fetch) + cache_fetch = init_one_libfunc ("__cache_fetch"); + emit_library_call_value (cache_fetch, data_addr, LCT_NORMAL, Pmode, + 1, ea_addr, EAmode); + } +} + +/* Like ea_load_store, but do the cache tag comparison and, for stores, + dirty bit marking, inline. + + The cache control data structure is an array of + + struct __cache_tag_array + { + unsigned int tag_lo[4]; + unsigned int tag_hi[4]; + void *data_pointer[4]; + int reserved[4]; + vector unsigned short dirty_bits[4]; + } */ + +static void +ea_load_store_inline (rtx mem, bool is_store, rtx ea_addr, rtx data_addr) +{ + rtx ea_addr_si; + HOST_WIDE_INT v; + rtx tag_size_sym = gen_rtx_SYMBOL_REF (Pmode, "__cache_tag_array_size"); + rtx tag_arr_sym = gen_rtx_SYMBOL_REF (Pmode, "__cache_tag_array"); + rtx index_mask = gen_reg_rtx (SImode); + rtx tag_arr = gen_reg_rtx (Pmode); + rtx splat_mask = gen_reg_rtx (TImode); + rtx splat = gen_reg_rtx (V4SImode); + rtx splat_hi = NULL_RTX; + rtx tag_index = gen_reg_rtx (Pmode); + rtx block_off = gen_reg_rtx (SImode); + rtx tag_addr = gen_reg_rtx (Pmode); + rtx tag = gen_reg_rtx (V4SImode); + rtx cache_tag = gen_reg_rtx (V4SImode); + rtx cache_tag_hi = NULL_RTX; + rtx cache_ptrs = gen_reg_rtx (TImode); + rtx cache_ptrs_si = gen_reg_rtx (SImode); + rtx tag_equal = gen_reg_rtx (V4SImode); + rtx tag_equal_hi = NULL_RTX; + rtx tag_eq_pack = gen_reg_rtx (V4SImode); + rtx tag_eq_pack_si = gen_reg_rtx (SImode); + rtx eq_index = gen_reg_rtx (SImode); + rtx bcomp, hit_label, hit_ref, cont_label, insn; + + if (spu_ea_model != 32) + { + splat_hi = gen_reg_rtx (V4SImode); + cache_tag_hi = gen_reg_rtx (V4SImode); + tag_equal_hi = gen_reg_rtx (V4SImode); + } + + emit_move_insn (index_mask, plus_constant (tag_size_sym, -128)); + emit_move_insn (tag_arr, tag_arr_sym); + v = 0x0001020300010203LL; + emit_move_insn (splat_mask, immed_double_const (v, v, TImode)); + ea_addr_si = ea_addr; + if (spu_ea_model != 32) + ea_addr_si = convert_to_mode (SImode, ea_addr, 1); + + /* tag_index = ea_addr & (tag_array_size - 128) */ + emit_insn (gen_andsi3 (tag_index, ea_addr_si, index_mask)); + + /* splat ea_addr to all 4 slots. */ + emit_insn (gen_shufb (splat, ea_addr_si, ea_addr_si, splat_mask)); + /* Similarly for high 32 bits of ea_addr. */ + if (spu_ea_model != 32) + emit_insn (gen_shufb (splat_hi, ea_addr, ea_addr, splat_mask)); + + /* block_off = ea_addr & 127 */ + emit_insn (gen_andsi3 (block_off, ea_addr_si, spu_const (SImode, 127))); + + /* tag_addr = tag_arr + tag_index */ + emit_insn (gen_addsi3 (tag_addr, tag_arr, tag_index)); + + /* Read cache tags. */ + emit_move_insn (cache_tag, gen_rtx_MEM (V4SImode, tag_addr)); + if (spu_ea_model != 32) + emit_move_insn (cache_tag_hi, gen_rtx_MEM (V4SImode, + plus_constant (tag_addr, 16))); + + /* tag = ea_addr & -128 */ + emit_insn (gen_andv4si3 (tag, splat, spu_const (V4SImode, -128))); + + /* Read all four cache data pointers. */ + emit_move_insn (cache_ptrs, gen_rtx_MEM (TImode, + plus_constant (tag_addr, 32))); + + /* Compare tags. */ + emit_insn (gen_ceq_v4si (tag_equal, tag, cache_tag)); + if (spu_ea_model != 32) + { + emit_insn (gen_ceq_v4si (tag_equal_hi, splat_hi, cache_tag_hi)); + emit_insn (gen_andv4si3 (tag_equal, tag_equal, tag_equal_hi)); + } + + /* At most one of the tags compare equal, so tag_equal has one + 32-bit slot set to all 1's, with the other slots all zero. + gbb picks off low bit from each byte in the 128-bit registers, + so tag_eq_pack is one of 0xf000, 0x0f00, 0x00f0, 0x000f, assuming + we have a hit. */ + emit_insn (gen_spu_gbb (tag_eq_pack, spu_gen_subreg (V16QImode, tag_equal))); + emit_insn (gen_spu_convert (tag_eq_pack_si, tag_eq_pack)); + + /* So counting leading zeros will set eq_index to 16, 20, 24 or 28. */ + emit_insn (gen_clzsi2 (eq_index, tag_eq_pack_si)); + + /* Allowing us to rotate the corresponding cache data pointer to slot0. + (rotating eq_index mod 16 bytes). */ + emit_insn (gen_rotqby_ti (cache_ptrs, cache_ptrs, eq_index)); + emit_insn (gen_spu_convert (cache_ptrs_si, cache_ptrs)); + + /* Add block offset to form final data address. */ + emit_insn (gen_addsi3 (data_addr, cache_ptrs_si, block_off)); + + /* Check that we did hit. */ + hit_label = gen_label_rtx (); + hit_ref = gen_rtx_LABEL_REF (VOIDmode, hit_label); + bcomp = gen_rtx_NE (SImode, tag_eq_pack_si, const0_rtx); + insn = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, + hit_ref, pc_rtx))); + /* Say that this branch is very likely to happen. */ + v = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100 - 1; + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (v), REG_NOTES (insn)); + + ea_load_store (mem, is_store, ea_addr, data_addr); + cont_label = gen_label_rtx (); + emit_jump_insn (gen_jump (cont_label)); + emit_barrier (); + + emit_label (hit_label); + + if (is_store) + { + HOST_WIDE_INT v_hi; + rtx dirty_bits = gen_reg_rtx (TImode); + rtx dirty_off = gen_reg_rtx (SImode); + rtx dirty_128 = gen_reg_rtx (TImode); + rtx neg_block_off = gen_reg_rtx (SImode); + + /* Set up mask with one dirty bit per byte of the mem we are + writing, starting from top bit. */ + v_hi = v = -1; + v <<= (128 - GET_MODE_SIZE (GET_MODE (mem))) & 63; + if ((128 - GET_MODE_SIZE (GET_MODE (mem))) >= 64) + { + v_hi = v; + v = 0; + } + emit_move_insn (dirty_bits, immed_double_const (v, v_hi, TImode)); + + /* Form index into cache dirty_bits. eq_index is one of + 0x10, 0x14, 0x18 or 0x1c. Multiplying by 4 gives us + 0x40, 0x50, 0x60 or 0x70 which just happens to be the + offset to each of the four dirty_bits elements. */ + emit_insn (gen_ashlsi3 (dirty_off, eq_index, spu_const (SImode, 2))); + + emit_insn (gen_spu_lqx (dirty_128, tag_addr, dirty_off)); + + /* Rotate bit mask to proper bit. */ + emit_insn (gen_negsi2 (neg_block_off, block_off)); + emit_insn (gen_rotqbybi_ti (dirty_bits, dirty_bits, neg_block_off)); + emit_insn (gen_rotqbi_ti (dirty_bits, dirty_bits, neg_block_off)); + + /* Or in the new dirty bits. */ + emit_insn (gen_iorti3 (dirty_128, dirty_bits, dirty_128)); + + /* Store. */ + emit_insn (gen_spu_stqx (dirty_128, tag_addr, dirty_off)); + } + + emit_label (cont_label); +} + +static rtx +expand_ea_mem (rtx mem, bool is_store) +{ + rtx ea_addr; + rtx data_addr = gen_reg_rtx (Pmode); + rtx new_mem; + + ea_addr = force_reg (EAmode, XEXP (mem, 0)); + if (optimize_size || optimize == 0) + ea_load_store (mem, is_store, ea_addr, data_addr); + else + ea_load_store_inline (mem, is_store, ea_addr, data_addr); + + if (ea_alias_set == -1) + ea_alias_set = new_alias_set (); + + /* We generate a new MEM RTX to refer to the copy of the data + in the cache. We do not copy memory attributes (except the + alignment) from the original MEM, as they may no longer apply + to the cache copy. */ + new_mem = gen_rtx_MEM (GET_MODE (mem), data_addr); + set_mem_alias_set (new_mem, ea_alias_set); + set_mem_align (new_mem, MIN (MEM_ALIGN (mem), 128 * 8)); + + return new_mem; +} + int spu_expand_mov (rtx * ops, enum machine_mode mode) { @@ -4298,9 +4633,17 @@ spu_expand_mov (rtx * ops, enum machine_mode mode) } } if (MEM_P (ops[0])) - return spu_split_store (ops); + { + if (MEM_ADDR_SPACE (ops[0])) + ops[0] = expand_ea_mem (ops[0], true); + return spu_split_store (ops); + } if (MEM_P (ops[1])) - return spu_split_load (ops); + { + if (MEM_ADDR_SPACE (ops[1])) + ops[1] = expand_ea_mem (ops[1], false); + return spu_split_load (ops); + } return 0; } @@ -6442,6 +6785,113 @@ spu_builtin_vec_perm (tree type, tree *mask_element_type) return d->fndecl; } +/* Return the appropriate mode for a named address pointer. */ +static enum machine_mode +spu_addr_space_pointer_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return ptr_mode; + case ADDR_SPACE_EA: + return EAmode; + default: + gcc_unreachable (); + } +} + +/* Return the appropriate mode for a named address address. */ +static enum machine_mode +spu_addr_space_address_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return Pmode; + case ADDR_SPACE_EA: + return EAmode; + default: + gcc_unreachable (); + } +} + +/* Determine if one named address space is a subset of another. */ + +static bool +spu_addr_space_subset_p (addr_space_t subset, addr_space_t superset) +{ + gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_EA); + gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_EA); + + if (subset == superset) + return true; + + /* If we have -mno-address-space-conversion, treat __ea and generic as not + being subsets but instead as disjoint address spaces. */ + else if (!TARGET_ADDRESS_SPACE_CONVERSION) + return false; + + else + return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_EA); +} + +/* Convert from one address space to another. */ +static rtx +spu_addr_space_convert (rtx op, tree from_type, tree to_type) +{ + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); + + gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_EA); + gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_EA); + + if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_EA) + { + rtx result, ls; + + ls = gen_const_mem (DImode, + gen_rtx_SYMBOL_REF (Pmode, "__ea_local_store")); + set_mem_align (ls, 128); + + result = gen_reg_rtx (Pmode); + ls = force_reg (Pmode, convert_modes (Pmode, DImode, ls, 1)); + op = force_reg (Pmode, convert_modes (Pmode, EAmode, op, 1)); + ls = emit_conditional_move (ls, NE, op, const0_rtx, Pmode, + ls, const0_rtx, Pmode, 1); + + emit_insn (gen_subsi3 (result, op, ls)); + + return result; + } + + else if (to_as == ADDR_SPACE_EA && from_as == ADDR_SPACE_GENERIC) + { + rtx result, ls; + + ls = gen_const_mem (DImode, + gen_rtx_SYMBOL_REF (Pmode, "__ea_local_store")); + set_mem_align (ls, 128); + + result = gen_reg_rtx (EAmode); + ls = force_reg (EAmode, convert_modes (EAmode, DImode, ls, 1)); + op = force_reg (Pmode, op); + ls = emit_conditional_move (ls, NE, op, const0_rtx, Pmode, + ls, const0_rtx, EAmode, 1); + op = force_reg (EAmode, convert_modes (EAmode, Pmode, op, 1)); + + if (EAmode == SImode) + emit_insn (gen_addsi3 (result, op, ls)); + else + emit_insn (gen_adddi3 (result, op, ls)); + + return result; + } + + else + gcc_unreachable (); +} + + /* Count the total number of instructions in each pipe and return the maximum, which is used as the Minimum Iteration Interval (MII) in the modulo scheduler. get_pipe() will return -2, -1, 0, or 1. @@ -6534,9 +6984,46 @@ spu_section_type_flags (tree decl, const char *name, int reloc) /* .toe needs to have type @nobits. */ if (strcmp (name, ".toe") == 0) return SECTION_BSS; + /* Don't load _ea into the current address space. */ + if (strcmp (name, "._ea") == 0) + return SECTION_WRITE | SECTION_DEBUG; return default_section_type_flags (decl, name, reloc); } +/* Implement targetm.select_section. */ +static section * +spu_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) +{ + /* Variables and constants defined in the __ea address space + go into a special section named "._ea". */ + if (TREE_TYPE (decl) != error_mark_node + && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_EA) + { + /* We might get called with string constants, but get_named_section + doesn't like them as they are not DECLs. Also, we need to set + flags in that case. */ + if (!DECL_P (decl)) + return get_section ("._ea", SECTION_WRITE | SECTION_DEBUG, NULL); + + return get_named_section (decl, "._ea", reloc); + } + + return default_elf_select_section (decl, reloc, align); +} + +/* Implement targetm.unique_section. */ +static void +spu_unique_section (tree decl, int reloc) +{ + /* We don't support unique section names in the __ea address + space for now. */ + if (TREE_TYPE (decl) != error_mark_node + && TYPE_ADDR_SPACE (TREE_TYPE (decl)) != 0) + return; + + default_unique_section (decl, reloc); +} + /* Generate a constant or register which contains 2^SCALE. We assume the result is valid for MODE. Currently, MODE must be V4SFmode and SCALE must be SImode. */ diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h index 67011a62126..369e6d76e9d 100644 --- a/gcc/config/spu/spu.h +++ b/gcc/config/spu/spu.h @@ -51,7 +51,7 @@ extern GTY(()) int spu_tune; /* Default target_flags if no switches specified. */ #ifndef TARGET_DEFAULT #define TARGET_DEFAULT (MASK_ERROR_RELOC | MASK_SAFE_DMA | MASK_BRANCH_HINTS \ - | MASK_SAFE_HINTS) + | MASK_SAFE_HINTS | MASK_ADDRESS_SPACE_CONVERSION) #endif @@ -469,6 +469,17 @@ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \ #define ASM_OUTPUT_LABELREF(FILE, NAME) \ asm_fprintf (FILE, "%U%s", default_strip_name_encoding (NAME)) +#define ASM_OUTPUT_SYMBOL_REF(FILE, X) \ + do \ + { \ + tree decl; \ + assemble_name (FILE, XSTR ((X), 0)); \ + if ((decl = SYMBOL_REF_DECL ((X))) != 0 \ + && TREE_CODE (decl) == VAR_DECL \ + && TYPE_ADDR_SPACE (TREE_TYPE (decl))) \ + fputs ("@ppu", FILE); \ + } while (0) + /* Instruction Output */ #define REGISTER_NAMES \ @@ -590,6 +601,13 @@ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \ } while (0) +/* Address spaces. */ +#define ADDR_SPACE_EA 1 + +/* Named address space keywords. */ +#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__ea", ADDR_SPACE_EA) + + /* Builtins. */ enum spu_builtin_type diff --git a/gcc/config/spu/spu.opt b/gcc/config/spu/spu.opt index 1589199b60b..4ad7128de51 100644 --- a/gcc/config/spu/spu.opt +++ b/gcc/config/spu/spu.opt @@ -82,3 +82,24 @@ Generate code for given CPU mtune= Target RejectNegative Joined Var(spu_tune_string) Schedule code for given CPU + +mea32 +Target Report RejectNegative Var(spu_ea_model,32) Init(32) +Access variables in 32-bit PPU objects (default) + +mea64 +Target Report RejectNegative Var(spu_ea_model,64) VarExists +Access variables in 64-bit PPU objects + +maddress-space-conversion +Target Report Mask(ADDRESS_SPACE_CONVERSION) +Allow conversions between __ea and generic pointers (default) + +mcache-size= +Target Report RejectNegative Joined UInteger +Size (in KB) of software data cache + +matomic-updates +Target Report +Atomically write back software data cache lines (default) + diff --git a/gcc/config/spu/spu_cache.h b/gcc/config/spu/spu_cache.h new file mode 100644 index 00000000000..66a679be5a0 --- /dev/null +++ b/gcc/config/spu/spu_cache.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SPU_CACHE_H +#define _SPU_CACHE_H + +void *__cache_fetch_dirty (__ea void *ea, int n_bytes_dirty); +void *__cache_fetch (__ea void *ea); +void __cache_evict (__ea void *ea); +void __cache_flush (void); +void __cache_touch (__ea void *ea); + +#define cache_fetch_dirty(_ea, _n_bytes_dirty) \ + __cache_fetch_dirty(_ea, _n_bytes_dirty) + +#define cache_fetch(_ea) __cache_fetch(_ea) +#define cache_touch(_ea) __cache_touch(_ea) +#define cache_evict(_ea) __cache_evict(_ea) +#define cache_flush() __cache_flush() + +#endif diff --git a/gcc/config/spu/t-spu-elf b/gcc/config/spu/t-spu-elf index 0c9236fa89f..a54ede9fa25 100644 --- a/gcc/config/spu/t-spu-elf +++ b/gcc/config/spu/t-spu-elf @@ -66,14 +66,39 @@ fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/spu/t-spu-elf # Don't let CTOR_LIST end up in sdata section. CRTSTUFF_T_CFLAGS = -#MULTILIB_OPTIONS=mlarge-mem/mtest-abi -#MULTILIB_DIRNAMES=large-mem test-abi -#MULTILIB_MATCHES= +# Multi-lib support. +MULTILIB_OPTIONS=mea64 # Neither gcc or newlib seem to have a standard way to generate multiple # crt*.o files. So we don't use the standard crt0.o name anymore. -EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o libgcc_cachemgr.a libgcc_cachemgr_nonatomic.a \ + libgcc_cache8k.a libgcc_cache16k.a libgcc_cache32k.a libgcc_cache64k.a libgcc_cache128k.a + +$(T)cachemgr.o: $(srcdir)/config/spu/cachemgr.c + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(MULTILIB_CFLAGS) -c $< -o $@ + +# Specialised rule to add a -D flag. +$(T)cachemgr_nonatomic.o: $(srcdir)/config/spu/cachemgr.c + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(MULTILIB_CFLAGS) -DNONATOMIC -c $< -o $@ + +$(T)libgcc_%.a: $(T)%.o + $(AR_FOR_TARGET) -rcs $@ $< + +$(T)cache8k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=8 -o $@ -c $< + +$(T)cache16k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=16 -o $@ -c $< + +$(T)cache32k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=32 -o $@ -c $< + +$(T)cache64k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=64 -o $@ -c $< + +$(T)cache128k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=128 -o $@ -c $< LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib diff --git a/gcc/convert.c b/gcc/convert.c index a833418d273..453f5ed873c 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -54,7 +54,17 @@ convert_to_pointer (tree type, tree expr) { case POINTER_TYPE: case REFERENCE_TYPE: - return fold_build1_loc (loc, NOP_EXPR, type, expr); + { + /* If the pointers point to different address spaces, conversion needs + to be done via a ADDR_SPACE_CONVERT_EXPR instead of a NOP_EXPR. */ + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr))); + + if (to_as == from_as) + return fold_build1_loc (loc, NOP_EXPR, type, expr); + else + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr); + } case INTEGER_TYPE: case ENUMERAL_TYPE: diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 11583fffe44..0b8261fc614 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -69,6 +69,13 @@ struct gimple_seq_node_d; typedef struct gimple_seq_node_d *gimple_seq_node; typedef const struct gimple_seq_node_d *const_gimple_seq_node; +/* Address space number for named address space support. */ +typedef unsigned char addr_space_t; + +/* The value of addr_space_t that represents the generic address space. */ +#define ADDR_SPACE_GENERIC 0 +#define ADDR_SPACE_GENERIC_P(AS) ((AS) == ADDR_SPACE_GENERIC) + /* The major intermediate representations of GCC. */ enum ir_type { IR_GIMPLE, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3ce735b3fe9..e7229587878 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,38 @@ +2009-10-26 Jakub Jelinek <jakub@redhat.com> + + PR debug/41828 + * cp-lang.c (cxx_dwarf_name): Return NULL instead of + <anonymous ...> for anonymous aggregate names. + +2009-10-26 Jason Merrill <jason@redhat.com> + + PR c++/38796, Core issue 906 + * cp-tree.h (DECL_DEFAULTED_OUTSIDE_CLASS_P): New. + (DECL_DEFAULTED_IN_CLASS_P): New. + * class.c (user_provided_p): Non-static. + (check_methods): Use it. + (check_bases_and_members): Check defaulted fns. + (defaultable_fn_p): Move and rename to... + * method.c (defaultable_fn_check): ...this. + (defaulted_late_check): New. + * pt.c (tsubst_decl): Call it. + * decl2.c (grokfield): Adjust. + * decl.c (cp_finish_decl): Adjust. + (grok_special_member_properties): Use user_provided_p. + +2009-10-26 Dodji Seketeli <dodji@redhat.com> + + PR c++/41785 + * pt.c (template_args_equal): Handle comparison of + an ARGUMENT_PACK_SELECT node with the arguments node it selects into. + * cp-tree.def: Fix a typo in the description of TYPE_PACK_EXPANSION. + +2009-10-26 Dodji Seketeli <dodji@redhat.com> + + PR c++/41020 + * decl.c (decls_match): Use DECL_IS_BUILTIN instead of + DECL_BUILT_IN. + 2009-10-23 Dodji Seketeli <dodji@redhat.com> PR c++/40808 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d29d6615f33..d737bdf7055 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3843,7 +3843,7 @@ check_methods (tree t) VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x); } /* All user-provided destructors are non-trivial. */ - if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x)) + if (DECL_DESTRUCTOR_P (x) && user_provided_p (x)) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1; } } @@ -4174,17 +4174,17 @@ type_has_user_nondefault_constructor (tree t) } /* Returns true iff FN is a user-provided function, i.e. user-declared - and not defaulted at its first declaration. */ + and not defaulted at its first declaration; or explicit, private, + protected, or non-const. */ -static bool +bool user_provided_p (tree fn) { if (TREE_CODE (fn) == TEMPLATE_DECL) return true; else return (!DECL_ARTIFICIAL (fn) - && !(DECL_DEFAULTED_FN (fn) - && DECL_INITIALIZED_IN_CLASS_P (fn))); + && !DECL_DEFAULTED_IN_CLASS_P (fn)); } /* Returns true iff class T has a user-provided constructor. */ @@ -4238,31 +4238,6 @@ type_has_user_provided_default_constructor (tree t) return false; } -/* Returns true if FN can be explicitly defaulted. */ - -bool -defaultable_fn_p (tree fn) -{ - if (DECL_CONSTRUCTOR_P (fn)) - { - if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node) - return true; - else if (copy_fn_p (fn) > 0 - && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn)) - == void_list_node)) - return true; - else - return false; - } - else if (DECL_DESTRUCTOR_P (fn)) - return true; - else if (DECL_ASSIGNMENT_OPERATOR_P (fn) - && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR) - return copy_fn_p (fn); - else - return false; -} - /* Remove all zero-width bit-fields from T. */ static void @@ -4356,6 +4331,7 @@ check_bases_and_members (tree t) tree access_decls; bool saved_complex_asn_ref; bool saved_nontrivial_dtor; + tree fn; /* By default, we use const reference arguments and generate default constructors. */ @@ -4453,6 +4429,31 @@ check_bases_and_members (tree t) cant_have_const_ctor, no_const_asn_ref); + /* Check defaulted declarations here so we have cant_have_const_ctor + and don't need to worry about clones. */ + for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn)) + if (DECL_DEFAULTED_IN_CLASS_P (fn)) + { + int copy = copy_fn_p (fn); + if (copy > 0) + { + bool imp_const_p + = (DECL_CONSTRUCTOR_P (fn) ? !cant_have_const_ctor + : !no_const_asn_ref); + bool fn_const_p = (copy == 2); + + if (fn_const_p && !imp_const_p) + /* If the function is defaulted outside the class, we just + give the synthesis error. */ + error ("%q+D declared to take const reference, but implicit " + "declaration would take non-const", fn); + else if (imp_const_p && !fn_const_p) + error ("%q+D declared to take non-const reference cannot be " + "defaulted in the class body", fn); + } + defaulted_late_check (fn); + } + if (LAMBDA_TYPE_P (t)) { /* "The closure type associated with a lambda-expression has a deleted diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index d84325d291b..8aa01e24d39 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -137,6 +137,9 @@ cxx_dwarf_name (tree t, int verbosity) { gcc_assert (DECL_P (t)); + if (DECL_NAME (t) + && (ANON_AGGRNAME_P (DECL_NAME (t)) || LAMBDANAME_P (DECL_NAME (t)))) + return NULL; if (verbosity >= 2) return decl_as_string (t, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 4df01a8e205..28ecc5bf681 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -393,7 +393,7 @@ DEFTREECODE (NONTYPE_ARGUMENT_PACK, "nontype_argument_pack", tcc_expression, 1) }; The derivation from tuple contains a TYPE_PACK_EXPANSION for the - template arguments. Its EXPR_PACK_EXPANSION is "Values&" and its + template arguments. Its PACK_EXPANSION_PATTERN is "Values&" and its PACK_EXPANSION_PARAMETER_PACKS will contain "Values". */ DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", tcc_type, 0) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 3d826b9ad92..ea28e9fadaa 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2815,10 +2815,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_DELETED_FN(DECL) \ (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->u.base.threadprivate_or_deleted_p) -/* Nonzero if DECL was declared with '= default'. */ +/* Nonzero if DECL was declared with '= default' (maybe implicitly). */ #define DECL_DEFAULTED_FN(DECL) \ (LANG_DECL_FN_CHECK (DECL)->defaulted_p) +/* Nonzero if DECL is explicitly defaulted in the class body. */ +#define DECL_DEFAULTED_IN_CLASS_P(DECL) \ + (DECL_DEFAULTED_FN (DECL) && DECL_INITIALIZED_IN_CLASS_P (DECL)) +/* Nonzero if DECL was defaulted outside the class body. */ +#define DECL_DEFAULTED_OUTSIDE_CLASS_P(DECL) \ + (DECL_DEFAULTED_FN (DECL) \ + && !(DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL))) + /* Record whether a typedef for type `int' was actually `signed int'. */ #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP) @@ -4483,9 +4491,11 @@ extern void check_for_override (tree, tree); extern void push_class_stack (void); extern void pop_class_stack (void); extern bool type_has_user_nondefault_constructor (tree); +extern bool user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_default_constructor (tree); -extern bool defaultable_fn_p (tree); +extern void defaulted_late_check (tree); +extern bool defaultable_fn_check (tree); extern void fixup_type_variants (tree); extern tree* decl_cloned_function_p (const_tree, bool); extern void clone_function_decl (tree, int); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5eb389fe7e3..ead3f335c8a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -935,7 +935,7 @@ decls_match (tree newdecl, tree olddecl) #ifdef NO_IMPLICIT_EXTERN_C /* A new declaration doesn't match a built-in one unless it is also extern "C". */ - if (DECL_BUILT_IN (olddecl) + if (DECL_IS_BUILTIN (olddecl) && DECL_EXTERN_C_P (olddecl) && !DECL_EXTERN_C_P (newdecl)) return 0; #endif @@ -5603,17 +5603,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, } else if (init == ridpointers[(int)RID_DEFAULT]) { - if (!defaultable_fn_p (decl)) - { - error ("%qD cannot be defaulted", decl); - DECL_INITIAL (decl) = NULL_TREE; - } + if (defaultable_fn_check (decl)) + DECL_DEFAULTED_FN (decl) = 1; else - { - DECL_DEFAULTED_FN (decl) = 1; - FOR_EACH_CLONE (clone, decl) - DECL_DEFAULTED_FN (clone) = 1; - } + DECL_INITIAL (decl) = NULL_TREE; } } @@ -9866,9 +9859,9 @@ grokparms (tree parmlist, tree *parms) 0 if D is not a copy constructor or copy assignment operator. 1 if D is a copy constructor or copy assignment operator whose - first parameter is a reference to const qualified T. - 2 if D is a copy constructor or copy assignment operator whose first parameter is a reference to non-const qualified T. + 2 if D is a copy constructor or copy assignment operator whose + first parameter is a reference to const qualified T. This function can be used as a predicate. Positive values indicate a copy constructor and nonzero values indicate a copy assignment @@ -9977,10 +9970,6 @@ move_fn_p (const_tree d) /* Remember any special properties of member function DECL. */ -#define DECL_DEFAULTED_IN_CLASS_P(DECL) \ - (DECL_DEFAULTED_FN (DECL) \ - && (DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL))) - void grok_special_member_properties (tree decl) { @@ -10007,7 +9996,7 @@ grok_special_member_properties (tree decl) are no other parameters or else all other parameters have default arguments. */ TYPE_HAS_INIT_REF (class_type) = 1; - if (!DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1; if (ctor > 1) TYPE_HAS_CONST_INIT_REF (class_type) = 1; @@ -10015,8 +10004,7 @@ grok_special_member_properties (tree decl) else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) { TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; - if (TREE_CODE (decl) == TEMPLATE_DECL - || !DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_DFLT (class_type) = 1; } else if (is_list_ctor (decl)) @@ -10035,7 +10023,7 @@ grok_special_member_properties (tree decl) if (assop) { TYPE_HAS_ASSIGN_REF (class_type) = 1; - if (!DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_ASSIGN_REF (class_type) = 1; if (assop != 1) TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 3e8c0d7a99c..592ee086961 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -862,9 +862,7 @@ grokfield (const cp_declarator *declarator, } else if (init == ridpointers[(int)RID_DEFAULT]) { - if (!defaultable_fn_p (value)) - error ("%qD cannot be defaulted", value); - else + if (defaultable_fn_check (value)) { DECL_DEFAULTED_FN (value) = 1; DECL_INITIALIZED_IN_CLASS_P (value) = 1; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index e8b28d877d7..266406c7cd0 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1130,6 +1130,88 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) return fn; } +/* Gives any errors about defaulted functions which need to be deferred + until the containing class is complete. */ + +void +defaulted_late_check (tree fn) +{ + /* Complain about invalid signature for defaulted fn. */ + tree ctx = DECL_CONTEXT (fn); + special_function_kind kind = special_function_p (fn); + bool fn_const_p = (copy_fn_p (fn) == 2); + tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p); + + if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)), + TREE_TYPE (TREE_TYPE (implicit_fn))) + || !compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), + TYPE_ARG_TYPES (TREE_TYPE (implicit_fn)))) + { + error ("defaulted declaration %q+D", fn); + error_at (DECL_SOURCE_LOCATION (fn), + "does not match expected signature %qD", implicit_fn); + } +} + +/* Returns true iff FN can be explicitly defaulted, and gives any + errors if defaulting FN is ill-formed. */ + +bool +defaultable_fn_check (tree fn) +{ + special_function_kind kind = sfk_none; + + if (DECL_CONSTRUCTOR_P (fn)) + { + if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node) + kind = sfk_constructor; + else if (copy_fn_p (fn) > 0 + && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn)) + == void_list_node)) + kind = sfk_copy_constructor; + else if (move_fn_p (fn)) + kind = sfk_move_constructor; + } + else if (DECL_DESTRUCTOR_P (fn)) + kind = sfk_destructor; + else if (DECL_ASSIGNMENT_OPERATOR_P (fn) + && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR + && copy_fn_p (fn)) + kind = sfk_assignment_operator; + + if (kind == sfk_none) + { + error ("%qD cannot be defaulted", fn); + return false; + } + else + { + tree t = FUNCTION_FIRST_USER_PARMTYPE (fn); + for (; t && t != void_list_node; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t)) + { + error ("defaulted function %q+D with default argument", fn); + break; + } + if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn))) + { + if (DECL_NONCONVERTING_P (fn)) + error ("%qD declared explicit cannot be defaulted in the class " + "body", fn); + if (current_access_specifier != access_public_node) + error ("%qD declared with non-public access cannot be defaulted " + "in the class body", fn); + if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) + error ("function %q+D defaulted on its first declaration " + "must not have an exception-specification", fn); + } + else if (!processing_template_decl) + defaulted_late_check (fn); + + return true; + } +} + /* Add an implicit declaration to TYPE for the kind of function indicated by SFK. Return the FUNCTION_DECL for the new implicit declaration. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 084ad1cb09f..f4806828cc4 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5818,6 +5818,18 @@ template_args_equal (tree ot, tree nt) return 0; return 1; } + else if (ot && TREE_CODE (ot) == ARGUMENT_PACK_SELECT) + { + /* We get here probably because we are in the middle of substituting + into the pattern of a pack expansion. In that case the + ARGUMENT_PACK_SELECT temporarily replaces the pack argument we are + interested in. So we want to use the initial pack argument for + the comparison. */ + ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot); + if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT) + nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt); + return template_args_equal (ot, nt); + } else if (TYPE_P (nt)) return TYPE_P (ot) && same_type_p (ot, nt); else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot)) @@ -8836,6 +8848,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); } determine_visibility (r); + if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) + && !processing_template_decl) + defaulted_late_check (r); apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0, args, complain, in_decl); diff --git a/gcc/cse.c b/gcc/cse.c index 8f49a9af9f5..05f6ed6e0fe 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -2623,6 +2623,10 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + switch (code) { case PC: diff --git a/gcc/cselib.c b/gcc/cselib.c index 7065429be8b..0aa22a4fe1b 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -1890,7 +1890,13 @@ cselib_record_sets (rtx insn) src = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond, src, dest); sets[i].src_elt = cselib_lookup (src, GET_MODE (dest), 1); if (MEM_P (dest)) - sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), Pmode, 1); + { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest)); + + sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), + address_mode, 1); + } else sets[i].dest_addr_elt = 0; } diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi index d2d1673cc3b..ca86f28dd39 100644 --- a/gcc/doc/contrib.texi +++ b/gcc/doc/contrib.texi @@ -173,8 +173,8 @@ The @uref{http://www.gnu.org/software/classpath/,,GNU Classpath project} for all of their merged runtime code. @item -Nick Clifton for arm, mcore, fr30, v850, m32r work, @option{--help}, and -other random hacking. +Nick Clifton for arm, mcore, fr30, v850, m32r, rx work, +@option{--help}, and other random hacking. @item Michael Cook for libstdc++ cleanup patches to reduce warnings. diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index a0f66214e3f..cb764c600eb 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -39,6 +39,7 @@ extensions, accepted by GCC in C89 mode and in C++. * Decimal Float:: Decimal Floating Types. * Hex Floats:: Hexadecimal floating-point constants. * Fixed-Point:: Fixed-Point Types. +* Named Address Spaces::Named address spaces. * Zero Length:: Zero-length arrays. * Variable Length:: Arrays whose length is computed at run time. * Empty Structures:: Structures with no members. @@ -1197,6 +1198,31 @@ Pragmas to control overflow and rounding behaviors are not implemented. Fixed-point types are supported by the DWARF2 debug information format. +@node Named Address Spaces +@section Named address spaces +@cindex named address spaces + +As an extension, the GNU C compiler supports named address spaces as +defined in the N1275 draft of ISO/IEC DTR 18037. Support for named +address spaces in GCC will evolve as the draft technical report changes. +Calling conventions for any target might also change. At present, only +the SPU target supports other address spaces. On the SPU target, for +example, variables may be declared as belonging to another address space +by qualifying the type with the @code{__ea} address space identifier: + +@smallexample +extern int __ea i; +@end smallexample + +When the variable @code{i} is accessed, the compiler will generate +special code to access this variable. It may use runtime library +support, or generate special machine instructions to access that address +space. + +The @code{__ea} identifier may be used exactly like any other C type +qualifier (e.g., @code{const} or @code{volatile}). See the N1275 +document for more details. + @node Zero Length @section Arrays of Length Zero @cindex arrays of length zero @@ -2244,6 +2270,13 @@ on data in the eight bit data area. Note the eight bit data area is limited to You must use GAS and GLD from GNU binutils version 2.7 or later for this attribute to work correctly. +@item exception +@cindex exception handler functions on the RX processor +Use this attribute on the RX to indicate that the specified function +is an exception handler. The compiler will generate function entry and +exit sequences suitable for use in an exception handler when this +attribute is present. + @item exception_handler @cindex exception handler functions on the Blackfin processor Use this attribute on the Blackfin to indicate that the specified function @@ -2280,7 +2313,7 @@ addressing modes. @item fast_interrupt @cindex interrupt handler functions -Use this attribute on the M32C port to indicate that the specified +Use this attribute on the M32C and RX ports to indicate that the specified function is a fast interrupt handler. This is just like the @code{interrupt} attribute, except that @code{freit} is used to return instead of @code{reit}. @@ -2472,8 +2505,8 @@ This attribute is ignored for R8C target. @item interrupt @cindex interrupt handler functions -Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, MeP, MIPS -and Xstormy16 ports to indicate that the specified function is an +Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, MeP, MIPS, +RX and Xstormy16 ports to indicate that the specified function is an interrupt handler. The compiler will generate function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. @@ -2689,7 +2722,7 @@ support for the swap suffix in the assembler. (GNU Binutils 2.19.51 or later) @item naked @cindex function without a prologue/epilogue code -Use this attribute on the ARM, AVR, IP2K and SPU ports to indicate that +Use this attribute on the ARM, AVR, IP2K, RX and SPU ports to indicate that the specified function does not need prologue/epilogue sequences generated by the compiler. It is up to the programmer to provide these sequences. The only statements that can be safely included in naked functions are @@ -7460,6 +7493,7 @@ instructions, but allow the compiler to schedule those calls. * Other MIPS Built-in Functions:: * picoChip Built-in Functions:: * PowerPC AltiVec/VSX Built-in Functions:: +* RX Built-in Functions:: * SPARC VIS Built-in Functions:: * SPU Built-in Functions:: @end menu @@ -11754,6 +11788,121 @@ long __builtin_bpermd (long, long); int __builtin_bswap16 (int); @end smallexample +@node RX Built-in Functions +@subsection RX Built-in Functions +GCC supports some of the RX instructions which cannot be expressed in +the C programming language via the use of built-in functions. The +following functions are supported: + +@deftypefn {Built-in Function} void __builtin_rx_brk (void) +Generates the @code{brk} machine instruction. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_clrpsw (int) +Generates the @code{clrpsw} machine instruction to clear the specified +bit in the processor status word. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_int (int) +Generates the @code{int} machine instruction to generate an interrupt +with the specified value. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_machi (int, int) +Generates the @code{machi} machine instruction to add the result of +multiplying the top 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_maclo (int, int) +Generates the @code{maclo} machine instruction to add the result of +multiplying the bottom 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mulhi (int, int) +Generates the @code{mulhi} machine instruction to place the result of +multiplying the top 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mullo (int, int) +Generates the @code{mullo} machine instruction to place the result of +multiplying the bottom 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfachi (void) +Generates the @code{mvfachi} machine instruction to read the top +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfacmi (void) +Generates the @code{mvfacmi} machine instruction to read the middle +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfc (int) +Generates the @code{mvfc} machine instruction which reads the control +register specified in its argument and returns its value. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtachi (int) +Generates the @code{mvtachi} machine instruction to set the top +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtaclo (int) +Generates the @code{mvtaclo} machine instruction to set the bottom +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtc (int reg, int val) +Generates the @code{mvtc} machine instruction which sets control +register number @code{reg} to @code{val}. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtipl (int) +Generates the @code{mvtipl} machine instruction set the interrupt +priority level. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_racw (int) +Generates the @code{racw} machine instruction to round the accumulator +according to the specified mode. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_revw (int) +Generates the @code{revw} machine instruction which swaps the bytes in +the argument so that bits 0--7 now occupy bits 8--15 and vice versa, +and also bits 16--23 occupy bits 24--31 and vice versa. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_rmpa (void) +Generates the @code{rmpa} machine instruction which initiates a +repeated multiply and accumulate sequence. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_round (float) +Generates the @code{round} machine instruction which returns the +floating point argument rounded according to the current rounding mode +set in the floating point status word register. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_sat (int) +Generates the @code{sat} machine instruction which returns the +saturated value of the argument. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_setpsw (int) +Generates the @code{setpsw} machine instruction to set the specified +bit in the processor status word. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_wait (void) +Generates the @code{wait} machine instruction. +@end deftypefn + @node SPARC VIS Built-in Functions @subsection SPARC VIS Built-in Functions @@ -12003,7 +12152,6 @@ extern int foo (); @end table - @node RS/6000 and PowerPC Pragmas @subsection RS/6000 and PowerPC Pragmas diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index c04f9cb65d5..0fd68244ea7 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -4004,6 +4004,14 @@ Embedded PowerPC system in little endian mode. @html <hr /> @end html +@heading @anchor{rx-x-elf}rx-*-elf +The Renesas RX processor. See +@uref{http://eu.renesas.com/fmwk.jsp?cnt=rx600_series_landing.jsp&fp=/products/mpumcu/rx_family/rx600_series} +for more information about this processor. + +@html +<hr /> +@end html @heading @anchor{s390-x-linux}s390-*-linux* S/390 system running GNU/Linux for S/390@. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 81569194d9d..39fee86ca80 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -784,6 +784,16 @@ See RS/6000 and PowerPC Options. -msim -mmvme -mads -myellowknife -memb -msdata @gol -msdata=@var{opt} -mvxworks -G @var{num} -pthread} +@emph{RX Options} +@gccoptlist{-m64bit-doubles -m32bit-doubles -mieee -mno-ieee@gol +-mbig-endian-data -mlittle-endian-data @gol +-msmall-data @gol +-msim -mno-sim@gol +-mas100-syntax -mno-as100-syntax@gol +-mrelax@gol +-mmax-constant-size=@gol +-mint-register=} + @emph{S/390 and zSeries Options} @gccoptlist{-mtune=@var{cpu-type} -march=@var{cpu-type} @gol -mhard-float -msoft-float -mhard-dfp -mno-hard-dfp @gol @@ -837,7 +847,11 @@ See RS/6000 and PowerPC Options. -msafe-dma -munsafe-dma @gol -mbranch-hints @gol -msmall-mem -mlarge-mem -mstdmain @gol --mfixed-range=@var{register-range}} +-mfixed-range=@var{register-range} @gol +-mea32 -mea64 @gol +-maddress-space-conversion -mno-address-space-conversion @gol +-mcache-size=@var{cache-size} @gol +-matomic-updates -mno-atomic-updates} @emph{System V Options} @gccoptlist{-Qy -Qn -YP,@var{paths} -Ym,@var{dir}} @@ -9535,6 +9549,7 @@ platform. * picoChip Options:: * PowerPC Options:: * RS/6000 and PowerPC Options:: +* RX Options:: * S/390 and zSeries Options:: * Score Options:: * SH Options:: @@ -10948,7 +10963,7 @@ These @samp{-m} options are defined for the DEC Alpha/VMS implementations: @table @gcctabopt @item -mvms-return-codes @opindex mvms-return-codes -Return VMS condition codes from main. The default is to return POSIX +Return VMS condition codes from main. The default is to return POSIX style condition (e.g.@: error) codes. @item -mdebug-main=@var{prefix} @@ -15367,6 +15382,112 @@ This option sets flags for both the preprocessor and linker. @end table +@node RX Options +@subsection RX Options +@cindex RX Options + +These @option{-m} options are defined for RX implementations: + +@table @gcctabopt +@item -m64bit-doubles +@itemx -m32bit-doubles +@opindex m64bit-doubles +@opindex m32bit-doubles +Make the @code{double} data type be 64-bits (@option{-m64bit-doubles}) +or 32-bits (@option{-m32bit-doubles}) in size. The default is +@option{-m32bit-doubles}. @emph{Note} the RX's hardware floating +point instructions are only used for 32-bit floating point values, and +then only if @option{-ffast-math} has been specified on the command +line. This is because the RX FPU instructions do not properly support +denormal (or sub-normal) values. + +@item -mbig-endian-data +@itemx -mlittle-endian-data +@opindex mbig-endian-data +@opindex mlittle-endian-data +Store data (but not code) in the big-endian format. The default is +@option{-mlittle-endian-data}, ie to store data in the little endian +format. + +@item -msmall-data-limit=@var{N} +@opindex msmall-data-limit +Specifies the maximum size in bytes of global and static variables +which can be placed into the small data area. Using the small data +area can lead to smaller and faster code, but the size of area is +limited and it is up to the programmer to ensure that the area does +not overflow. Also when the small data area is used one of the RX's +registers (@code{r13}) is reserved for use pointing to this area, so +it is no longer available for use by the compiler. This could result +in slower and/or larger code if variables which once could have been +held in @code{r13} are now pushed onto the stack. + +Note, common variables (variables which have not been initialised) and +constants are not placed into the small data area as they are assigned +to other sections in the output executeable. + +The default value is zero, which disables this feature. Note, this +feature is not enabled by default with higher optimization levels +(@option{-O2} etc) because of the potentially deterimental effects of +reserving register @code{r13}. It is up to the programmer to +experiment and discover whether this feature is of benefit to their +program. + +@item -msim +@item -mno-sim +@opindex msim +@opindex mno-sim +Use the simulator runtime. The default is to use the libgloss board +specific runtime. + +@item -mas100-syntax +@item -mno-as100-syntax +@opindex mas100-syntax +@opindex mno-as100-syntax +When generating assembler output use a syntax that is compatible with +Renesas's AS100 assembler. This syntax can also be handled by the GAS +assembler but it has some restrictions so generating it is not the +default option. + +@item -mmax-constant-size=@var{N} +@opindex mmax-constant-size +Specifies the maxium size, in bytes, of a constant that can be used as +an operand in a RX instruction. Although the RX instruction set does +allow consants of up to 4 bytes in length to be used in instructions, +a longer value equates to a longer instruction. Thus in some +circumstances it can be beneficial to restrict the size of constants +that are used in instructions. Constants that are too big are instead +placed into a constant pool and referenced via register indirection. + +The value @var{N} can be between 0 and 3. A value of 0, the default, +means that constants of any size are allowed. + +@item -mrelax +@opindex mrelax +Enable linker relaxation. Linker relaxation is a process whereby the +linker will attempt to reduce the size of a program by finding shorter +versions of various instructions. Disabled by default. + +@item -mint-register=@var{N} +@opindex mint-register +Specify the number of registers to reserve for fast interrupt handler +functions. The value @var{N} can be between 0 and 4. A value of 1 +means that register @code{r13} will be reserved for ther exclusive use +of fast interrupt handlers. A value of 2 reserves @code{r13} and +@code{r12}. A value of 3 reserves @code{r13}, @code{r12} and +@code{r11}, and a value of 4 reserves @code{r13} through @code{r10}. +A value of 0, the default, does not reserve any registers. +@end table + +@emph{Note:} The generic GCC command line @option{-ffixed-@var{reg}} +has special significance to the RX port when used with the +@code{interrupt} function attribute. This attribute indicates a +function intended to process fast interrupts. GCC will will ensure +that it only uses the registers @code{r10}, @code{r11}, @code{r12} +and/or @code{r13} and only provided that the normal use of the +corresponding registers have been restricted via the +@option{-ffixed-@var{reg}} or @option{-mint-register} command line +options. + @node S/390 and zSeries Options @subsection S/390 and zSeries Options @cindex S/390 and zSeries Options @@ -16246,6 +16367,46 @@ useful when compiling kernel code. A register range is specified as two registers separated by a dash. Multiple register ranges can be specified separated by a comma. +@item -mea32 +@itemx -mea64 +@opindex mea32 +@opindex mea64 +Compile code assuming that pointers to the PPU address space accessed +via the @code{__ea} named address space qualifier are either 32 or 64 +bits wide. The default is 32 bits. As this is an ABI changing option, +all object code in an executable must be compiled with the same setting. + +@item -maddress-space-conversion +@itemx -mno-address-space-conversion +@opindex maddress-space-conversion +@opindex mno-address-space-conversion +Allow/disallow treating the @code{__ea} address space as superset +of the generic address space. This enables explicit type casts +between @code{__ea} and generic pointer as well as implicit +conversions of generic pointers to @code{__ea} pointers. The +default is to allow address space pointer conversions. + +@item -mcache-size=@var{cache-size} +@opindex mcache-size +This option controls the version of libgcc that the compiler links to an +executable and selects a software-managed cache for accessing variables +in the @code{__ea} address space with a particular cache size. Possible +options for @var{cache-size} are @samp{8}, @samp{16}, @samp{32}, @samp{64} +and @samp{128}. The default cache size is 64KB. + +@item -matomic-updates +@itemx -mno-atomic-updates +@opindex matomic-updates +@opindex mno-atomic-updates +This option controls the version of libgcc that the compiler links to an +executable and selects whether atomic updates to the software-managed +cache of PPU-side variables are used. If you use atomic updates, changes +to a PPU variable from SPU code using the @code{__ea} named address space +qualifier will not interfere with changes to other PPU variables residing +in the same cache line from PPU code. If you do not use atomic updates, +such interference may occur; however, writing back cache lines will be +more efficient. The default behavior is to use atomic updates. + @item -mdual-nops @itemx -mdual-nops=@var{n} @opindex mdual-nops diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 8a1a389924c..dcfba921207 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -2897,6 +2897,32 @@ A constant in the range of 0 to @minus{}255. @end table +@item RX---@file{config/rx/constraints.md} +@table @code +@item Q +An address which does not involve register indirect addressing or +pre/post increment/decrement addressing. + +@item Symbol +A symbol reference. + +@item Int08 +A constant in the range @minus{}256 to 255, inclusive. + +@item Sint08 +A constant in the range @minus{}128 to 127, inclusive. + +@item Sint16 +A constant in the range @minus{}32768 to 32767, inclusive. + +@item Sint24 +A constant in the range @minus{}8388608 to 8388607, inclusive. + +@item Uint04 +A constant in the range 0 to 15, inclusive. + +@end table + @need 1000 @item SPARC---@file{config/sparc/sparc.h} @table @code diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index e28ba032cdd..4888eb3f1e1 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -420,6 +420,11 @@ the size is implied by the mode. @findex MEM_ALIGN @item MEM_ALIGN (@var{x}) The known alignment in bits of the memory reference. + +@findex MEM_ADDR_SPACE +@item MEM_ADDR_SPACE (@var{x}) +The address space of the memory reference. This will commonly be zero +for the generic address space. @end table @item REG diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 805ebf2b3ab..8df014dad99 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -55,6 +55,7 @@ through the macros defined in the @file{.h} file. * MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * PCH Target:: Validity checking for precompiled headers. * C++ ABI:: Controlling C++ ABI changes. +* Named Address Spaces:: Adding support for named address spaces * Misc:: Everything else. @end menu @@ -3529,7 +3530,7 @@ dynamically if their size exceeds @code{STACK_CHECK_MAX_VAR_SIZE} bytes. @defmac STACK_CHECK_BUILTIN A nonzero value if stack checking is done by the configuration files in a machine-dependent manner. You should define this macro if stack checking -is require by the ABI of your machine or if you would like to do stack +is required by the ABI of your machine or if you would like to do stack checking in some more efficient way than the generic approach. The default value of this macro is zero. @end defmac @@ -3788,7 +3789,7 @@ registers @code{regs_ever_live} and @code{call_used_regs}. If @code{ELIMINABLE_REGS} is defined, this macro will be not be used and need not be defined. Otherwise, it must be defined even if -@code{TARGET_FRAME_POINTER_REQUIRED} is always return true; in that +@code{TARGET_FRAME_POINTER_REQUIRED} always returns true; in that case, you may set @var{depth-var} to anything. @end defmac @@ -4205,7 +4206,6 @@ on the stack. The compiler knows how to track the amount of stack space used for arguments without any special help. @end defmac - @defmac FUNCTION_ARG_OFFSET (@var{mode}, @var{type}) If defined, a C expression that is the number of bytes to add to the offset of the argument passed in memory. This is needed for the SPU, @@ -5370,9 +5370,10 @@ post-address side-effect generation involving a register displacement. @defmac CONSTANT_ADDRESS_P (@var{x}) A C expression that is 1 if the RTX @var{x} is a constant which -is a valid address. On most machines, this can be defined as -@code{CONSTANT_P (@var{x})}, but a few machines are more restrictive -in which constant addresses are supported. +is a valid address. On most machines the default definition of +@code{(CONSTANT_P (@var{x}) && GET_CODE (@var{x}) != CONST_DOUBLE)} +is acceptable, but a few machines are more restrictive as to which +constant addresses are supported. @end defmac @defmac CONSTANT_P (@var{x}) @@ -6127,7 +6128,7 @@ this macro is defined, it should produce a nonzero value when @code{STRICT_ALIGNMENT} is nonzero. @end defmac -@defmac MOVE_RATIO +@defmac MOVE_RATIO (@var{speed}) The threshold of number of scalar memory-to-memory move insns, @emph{below} which a sequence of insns should be generated instead of a string move insn or a library call. Increasing the value will always @@ -6137,6 +6138,9 @@ Note that on machines where the corresponding move insn is a @code{define_expand} that emits a sequence of insns, this macro counts the number of such sequences. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, a reasonable default is used. @end defmac @@ -6152,12 +6156,15 @@ A C expression used by @code{move_by_pieces} to determine the largest unit a load or store used to copy memory is. Defaults to @code{MOVE_MAX}. @end defmac -@defmac CLEAR_RATIO +@defmac CLEAR_RATIO (@var{speed}) The threshold of number of scalar move insns, @emph{below} which a sequence of insns should be generated to clear memory instead of a string clear insn or a library call. Increasing the value will always make code faster, but eventually incurs high cost in increased code size. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, a reasonable default is used. @end defmac @@ -6168,13 +6175,16 @@ will be used. Defaults to 1 if @code{move_by_pieces_ninsns} returns less than @code{CLEAR_RATIO}. @end defmac -@defmac SET_RATIO +@defmac SET_RATIO (@var{speed}) The threshold of number of scalar move insns, @emph{below} which a sequence of insns should be generated to set memory to a constant value, instead of a block set insn or a library call. Increasing the value will always make code faster, but eventually incurs high cost in increased code size. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, it defaults to the value of @code{MOVE_RATIO}. @end defmac @@ -6189,7 +6199,7 @@ than @code{SET_RATIO}. @defmac STORE_BY_PIECES_P (@var{size}, @var{alignment}) A C expression used to determine whether @code{store_by_pieces} will be -used to set a chunk of memory to a constant string value, or whether some +used to set a chunk of memory to a constant string value, or whether some other mechanism will be used. Used by @code{__builtin_strcpy} when called with a constant source string. Defaults to 1 if @code{move_by_pieces_ninsns} returns less @@ -6255,7 +6265,7 @@ Define this macro if a non-short-circuit operation produced by @code{BRANCH_COST} is greater than or equal to the value 2. @end defmac -@deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, int @var{code}, int @var{outer_code}, int *@var{total}) +@deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, int @var{code}, int @var{outer_code}, int *@var{total}, bool @var{speed}) This target hook describes the relative costs of RTL expressions. The cost may depend on the precise form of the expression, which is @@ -6274,15 +6284,15 @@ necessary. Traditionally, the default costs are @code{COSTS_N_INSNS (5)} for multiplications, @code{COSTS_N_INSNS (7)} for division and modulus operations, and @code{COSTS_N_INSNS (1)} for all other operations. -When optimizing for code size, i.e.@: when @code{optimize_size} is -nonzero, this target hook should be used to estimate the relative +When optimizing for code size, i.e.@: when @code{speed} is +false, this target hook should be used to estimate the relative size cost of an expression, again relative to @code{COSTS_N_INSNS}. The hook returns true when all subexpressions of @var{x} have been processed, and false when @code{rtx_cost} should recurse. @end deftypefn -@deftypefn {Target Hook} int TARGET_ADDRESS_COST (rtx @var{address}) +@deftypefn {Target Hook} int TARGET_ADDRESS_COST (rtx @var{address}, bool @var{speed}) This hook computes the cost of an addressing mode that contains @var{address}. If not defined, the cost is computed from the @var{address} expression and the @code{TARGET_RTX_COST} hook. @@ -6384,7 +6394,7 @@ debug output to. @var{verbose} is the verbose level provided by list of instructions that are ready to be scheduled. @var{n_readyp} is a pointer to the number of elements in the ready list. The scheduler reads the ready list in reverse order, starting with -@var{ready}[@var{*n_readyp}-1] and going to @var{ready}[0]. @var{clock} +@var{ready}[@var{*n_readyp} @minus{} 1] and going to @var{ready}[0]. @var{clock} is the timer tick of the scheduler. You may modify the ready list and the number of ready insns. The return value is the number of insns that can issue this cycle; normally this is just @code{issue_rate}. See also @@ -9516,7 +9526,7 @@ attributes, or a copy of the list may be made if further changes are needed. @end deftypefn -@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (tree @var{fndecl}) +@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (const_tree @var{fndecl}) @cindex inlining This target hook returns @code{true} if it is ok to inline @var{fndecl} into the current function, despite its having target-specific @@ -9816,6 +9826,105 @@ defined. Use this hook to make adjustments to the class (eg, tweak visibility or perform any other required target modifications). @end deftypefn +@node Named Address Spaces +@section Adding support for named address spaces +@cindex named address spaces + +The draft technical report of the ISO/IEC JTC1 S22 WG14 N1275 +standards committee, @cite{Programming Languages - C - Extensions to +support embedded processors}, specifies a syntax for embedded +processors to specify alternate address spaces. You can configure a +GCC port to support section 5.1 of the draft report to add support for +address spaces other than the default address space. These address +spaces are new keywords that are similar to the @code{volatile} and +@code{const} type attributes. + +Pointers to named address spaces can a a different size than +pointers to the generic address space. + +For example, the SPU port uses the @code{__ea} address space to refer +to memory in the host processor, rather than memory local to the SPU +processor. Access to memory in the @code{__ea} address space involves +issuing DMA operations to move data between the host processor and the +local processor memory address space. Pointers in the @code{__ea} +address space are either 32 bits or 64 bits based on the +@option{-mea32} or @option{-mea64} switches (native SPU pointers are +always 32 bits). + +Internally, address spaces are represented as a small integer in the +range 0 to 15 with address space 0 being reserved for the generic +address space. + +@defmac TARGET_ADDR_SPACE_KEYWORDS +A list of @code{ADDR_SPACE_KEYWORD} macros to define each named +address keyword. The @code{ADDR_SPACE_KEYWORD} macro takes two +arguments, the keyword string and the number of the named address +space. For example, the SPU port uses the following to declare +@code{__ea} as the keyword for named address space #1: +@smallexample +#define ADDR_SPACE_EA 1 +#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__ea", ADDR_SPACE_EA) +@end smallexample +@end defmac + +@deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_POINTER_MODE (addr_space_t @var{address_space}) +Define this to return the machine mode to use for pointers to +@var{address_space} if the target supports named address spaces. +The default version of this hook returns @code{ptr_mode} for the +generic address space only. +@end deftypefn + +@deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_ADDRESS_MODE (addr_space_t @var{address_space}) +Define this to return the machine mode to use for addresses in +@var{address_space} if the target supports named address spaces. +The default version of this hook returns @code{Pmode} for the +generic address space only. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_ADDR_SPACE_VALID_POINTER_MODE (enum machine_mode @var{mode}, addr_space_t @var{as}) +Define this to return nonzero if the port can handle pointers +with machine mode @var{mode} to address space @var{as}. This target +hook is the same as the @code{TARGET_VALID_POINTER_MODE} target hook, +except that it includes explicit named address space support. The default +version of this hook returns true for the modes returned by either the +@code{TARGET_ADDR_SPACE_POINTER_MODE} or @code{TARGET_ADDR_SPACE_ADDRESS_MODE} +target hooks for the given address space. +@end deftypefn + +@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P (enum machine_mode @var{mode}, rtx @var{exp}, bool @var{strict}, addr_space_t @var{as}) +Define this to return true if @var{exp} is a valid address for mode +@var{mode} in the named address space @var{as}. The @var{strict} +parameter says whether strict addressing is in effect after reload has +finished. This target hook is the same as the +@code{TARGET_LEGITIMATE_ADDRESS_P} target hook, except that it includes +explicit named address space support. +@end deftypefn + +@deftypefn {Target Hook} {rtx} TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS (rtx @var{x}, rtx @var{oldx}, enum machine_mode @var{mode}, addr_space_t @var{as}) +Define this to modify an invalid address @var{x} to be a valid address +with mode @var{mode} in the named address space @var{as}. This target +hook is the same as the @code{TARGET_LEGITIMIZE_ADDRESS} target hook, +except that it includes explicit named address space support. +@end deftypefn + +@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_SUBSET_P (addr_space_t @var{superset}, addr_space_t @var{subset}) +Define this to return whether the @var{subset} named address space is +contained within the @var{superset} named address space. Pointers to +a named address space that is a subset of another named address space +will be converted automatically without a cast if used together in +arithmetic operations. Pointers to a superset address space can be +converted to pointers to a subset address space via explict casts. +@end deftypefn + +@deftypefn {Target Hook} {rtx} TARGET_ADDR_SPACE_CONVERT (rtx @var{op}, tree @var{from_type}, tree @var{to_type}) +Define this to convert the pointer expression represented by the RTL +@var{op} with type @var{from_type} that points to a named address +space to a new pointer expression with type @var{to_type} that points +to a different named address space. When this hook it called, it is +guaranteed that one of the two address spaces is a subset of the other, +as determined by the @code{TARGET_ADDR_SPACE_SUBSET_P} target hook. +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous @@ -10910,7 +11019,6 @@ to the stack. Therefore, this hook should return true in general, but false for naked functions. The default implementation always returns true. @end deftypefn - @deftypevr {Target Hook} {unsigned HOST_WIDE_INT} TARGET_CONST_ANCHOR On some architectures it can take multiple instructions to synthesize a constant. If there is another constant already in a register that diff --git a/gcc/dse.c b/gcc/dse.c index 9d3e2c07ed6..a883bcd3d69 100644 --- a/gcc/dse.c +++ b/gcc/dse.c @@ -826,9 +826,9 @@ replace_inc_dec (rtx *r, void *d) case POST_INC: { rtx r1 = XEXP (x, 0); - rtx c = gen_int_mode (data->size, Pmode); - emit_insn_before (gen_rtx_SET (Pmode, r1, - gen_rtx_PLUS (Pmode, r1, c)), + rtx c = gen_int_mode (data->size, GET_MODE (r1)); + emit_insn_before (gen_rtx_SET (VOIDmode, r1, + gen_rtx_PLUS (GET_MODE (r1), r1, c)), data->insn); return -1; } @@ -837,9 +837,9 @@ replace_inc_dec (rtx *r, void *d) case POST_DEC: { rtx r1 = XEXP (x, 0); - rtx c = gen_int_mode (-data->size, Pmode); - emit_insn_before (gen_rtx_SET (Pmode, r1, - gen_rtx_PLUS (Pmode, r1, c)), + rtx c = gen_int_mode (-data->size, GET_MODE (r1)); + emit_insn_before (gen_rtx_SET (VOIDmode, r1, + gen_rtx_PLUS (GET_MODE (r1), r1, c)), data->insn); return -1; } @@ -851,7 +851,7 @@ replace_inc_dec (rtx *r, void *d) insn that contained it. */ rtx add = XEXP (x, 0); rtx r1 = XEXP (add, 0); - emit_insn_before (gen_rtx_SET (Pmode, r1, add), data->insn); + emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn); return -1; } @@ -1068,6 +1068,8 @@ canon_address (rtx mem, HOST_WIDE_INT *offset, cselib_val **base) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); rtx mem_address = XEXP (mem, 0); rtx expanded_address, address; int expanded; @@ -1107,7 +1109,7 @@ canon_address (rtx mem, *alias_set_out = 0; - cselib_lookup (mem_address, Pmode, 1); + cselib_lookup (mem_address, address_mode, 1); if (dump_file) { @@ -1173,7 +1175,8 @@ canon_address (rtx mem, address = XEXP (address, 0); } - if (const_or_frame_p (address)) + if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (mem)) + && const_or_frame_p (address)) { group_info_t group = get_group_info (address); @@ -1186,7 +1189,7 @@ canon_address (rtx mem, } } - *base = cselib_lookup (address, Pmode, true); + *base = cselib_lookup (address, address_mode, true); *group_id = -1; if (*base == NULL) diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index ba59251d66b..129ba7de927 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -10781,7 +10781,11 @@ static void add_pubname (tree decl, dw_die_ref die) { if (TREE_PUBLIC (decl)) - add_pubname_string (dwarf2_name (decl, 1), die); + { + const char *name = dwarf2_name (decl, 1); + if (name) + add_pubname_string (name, die); + } } /* Add a new entry to .debug_pubtypes if appropriate. */ @@ -10811,7 +10815,11 @@ add_pubtype (tree decl, dw_die_ref die) } } else - e.name = xstrdup (dwarf2_name (decl, 1)); + { + e.name = dwarf2_name (decl, 1); + if (e.name) + e.name = xstrdup (e.name); + } /* If we don't have a name for the type, there's no point in adding it to the table. */ @@ -12150,6 +12158,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, add_AT_unsigned (mod_type_die, DW_AT_byte_size, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type))) + add_AT_unsigned (mod_type_die, DW_AT_address_class, + TYPE_ADDR_SPACE (item_type)); } else if (code == REFERENCE_TYPE) { @@ -12157,6 +12168,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, add_AT_unsigned (mod_type_die, DW_AT_byte_size, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type))) + add_AT_unsigned (mod_type_die, DW_AT_address_class, + TYPE_ADDR_SPACE (item_type)); } else if (code == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE @@ -12359,7 +12373,8 @@ generic_parameter_die (tree parm, tree arg, /* The DW_AT_GNU_template_name attribute of the DIE must be set to the name of the argument. */ name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1); - add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); + if (name) + add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); } if (TREE_CODE (parm) == PARM_DECL) @@ -16464,7 +16479,9 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl) decl_name = DECL_NAME (decl); if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) { - add_name_attribute (die, dwarf2_name (decl, 0)); + const char *name = dwarf2_name (decl, 0); + if (name) + add_name_attribute (die, name); if (! DECL_ARTIFICIAL (decl)) add_src_coords_attributes (die, decl); @@ -19222,7 +19239,11 @@ gen_namespace_die (tree decl, dw_die_ref context_die) context_die, decl); /* For Fortran modules defined in different CU don't add src coords. */ if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl)) - add_name_attribute (namespace_die, dwarf2_name (decl, 0)); + { + const char *name = dwarf2_name (decl, 0); + if (name) + add_name_attribute (namespace_die, name); + } else add_name_and_src_coords_attributes (namespace_die, decl); if (DECL_EXTERNAL (decl)) @@ -19910,23 +19931,28 @@ dwarf2out_set_name (tree decl, tree name) { dw_die_ref die; dw_attr_ref attr; + const char *dname; die = TYPE_SYMTAB_DIE (decl); if (!die) return; + dname = dwarf2_name (name, 0); + if (!dname) + return; + attr = get_AT (die, DW_AT_name); if (attr) { struct indirect_string_node *node; - node = find_AT_string (dwarf2_name (name, 0)); + node = find_AT_string (dname); /* replace the string. */ attr->dw_attr_val.v.val_str = node; } else - add_name_attribute (die, dwarf2_name (name, 0)); + add_name_attribute (die, dname); } /* Called by the final INSN scan whenever we see a direct function call. diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index b8682984eca..d7600bccc26 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "df.h" #include "params.h" +#include "target.h" /* Commonly used modes. */ @@ -193,7 +194,7 @@ static rtx lookup_const_fixed (rtx); static hashval_t mem_attrs_htab_hash (const void *); static int mem_attrs_htab_eq (const void *, const void *); static mem_attrs *get_mem_attrs (alias_set_type, tree, rtx, rtx, unsigned int, - enum machine_mode); + addr_space_t, enum machine_mode); static hashval_t reg_attrs_htab_hash (const void *); static int reg_attrs_htab_eq (const void *, const void *); static reg_attrs *get_reg_attrs (tree, int); @@ -292,6 +293,7 @@ mem_attrs_htab_hash (const void *x) const mem_attrs *const p = (const mem_attrs *) x; return (p->alias ^ (p->align * 1000) + ^ (p->addrspace * 4000) ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000) ^ ((p->size ? INTVAL (p->size) : 0) * 2500000) ^ (size_t) iterative_hash_expr (p->expr, 0)); @@ -309,6 +311,7 @@ mem_attrs_htab_eq (const void *x, const void *y) return (p->alias == q->alias && p->offset == q->offset && p->size == q->size && p->align == q->align + && p->addrspace == q->addrspace && (p->expr == q->expr || (p->expr != NULL_TREE && q->expr != NULL_TREE && operand_equal_p (p->expr, q->expr, 0)))); @@ -320,7 +323,7 @@ mem_attrs_htab_eq (const void *x, const void *y) static mem_attrs * get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, - unsigned int align, enum machine_mode mode) + unsigned int align, addr_space_t addrspace, enum machine_mode mode) { mem_attrs attrs; void **slot; @@ -328,7 +331,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, /* If everything is the default, we can just return zero. This must match what the corresponding MEM_* macros return when the field is not present. */ - if (alias == 0 && expr == 0 && offset == 0 + if (alias == 0 && expr == 0 && offset == 0 && addrspace == 0 && (size == 0 || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size))) && (STRICT_ALIGNMENT && mode != BLKmode @@ -340,6 +343,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, attrs.offset = offset; attrs.size = size; attrs.align = align; + attrs.addrspace = addrspace; slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT); if (*slot == 0) @@ -1386,7 +1390,9 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine else if (reload_completed) { - if (! strict_memory_address_p (word_mode, XEXP (new_rtx, 0))) + if (! strict_memory_address_addr_space_p (word_mode, + XEXP (new_rtx, 0), + MEM_ADDR_SPACE (op))) return 0; } else @@ -1795,7 +1801,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* Now set the attributes we computed above. */ MEM_ATTRS (ref) - = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref)); + = get_mem_attrs (alias, expr, offset, size, align, + TYPE_ADDR_SPACE (type), GET_MODE (ref)); /* If this is already known to be a scalar or aggregate, we are done. */ if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref)) @@ -1827,7 +1834,17 @@ set_mem_alias_set (rtx mem, alias_set_type set) MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem), MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); +} + +/* Set the address space of MEM to ADDRSPACE (target-defined). */ + +void +set_mem_addr_space (rtx mem, addr_space_t addrspace) +{ + MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), + MEM_OFFSET (mem), MEM_SIZE (mem), + MEM_ALIGN (mem), addrspace, GET_MODE (mem)); } /* Set the alignment of MEM to ALIGN bits. */ @@ -1837,7 +1854,7 @@ set_mem_align (rtx mem, unsigned int align) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), MEM_OFFSET (mem), MEM_SIZE (mem), align, - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the expr for MEM to EXPR. */ @@ -1847,7 +1864,8 @@ set_mem_expr (rtx mem, tree expr) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem), - MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); + MEM_SIZE (mem), MEM_ALIGN (mem), + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the offset of MEM to OFFSET. */ @@ -1857,7 +1875,7 @@ set_mem_offset (rtx mem, rtx offset) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), offset, MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the size of MEM to SIZE. */ @@ -1867,7 +1885,7 @@ set_mem_size (rtx mem, rtx size) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), MEM_OFFSET (mem), size, MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Return a memory reference like MEMREF, but with its mode changed to MODE @@ -1879,23 +1897,25 @@ set_mem_size (rtx mem, rtx size) static rtx change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) { + addr_space_t as; rtx new_rtx; gcc_assert (MEM_P (memref)); + as = MEM_ADDR_SPACE (memref); if (mode == VOIDmode) mode = GET_MODE (memref); if (addr == 0) addr = XEXP (memref, 0); if (mode == GET_MODE (memref) && addr == XEXP (memref, 0) - && (!validate || memory_address_p (mode, addr))) + && (!validate || memory_address_addr_space_p (mode, addr, as))) return memref; if (validate) { if (reload_in_progress || reload_completed) - gcc_assert (memory_address_p (mode, addr)); + gcc_assert (memory_address_addr_space_p (mode, addr, as)); else - addr = memory_address (mode, addr); + addr = memory_address_addr_space (mode, addr, as); } if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref)) @@ -1934,7 +1954,8 @@ change_address (rtx memref, enum machine_mode mode, rtx addr) } MEM_ATTRS (new_rtx) - = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode); + = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, + MEM_ADDR_SPACE (memref), mmode); return new_rtx; } @@ -1954,11 +1975,13 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, rtx memoffset = MEM_OFFSET (memref); rtx size = 0; unsigned int memalign = MEM_ALIGN (memref); + addr_space_t as = MEM_ADDR_SPACE (memref); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); int pbits; /* If there are no changes, just return the original memory reference. */ if (mode == GET_MODE (memref) && !offset - && (!validate || memory_address_p (mode, addr))) + && (!validate || memory_address_addr_space_p (mode, addr, as))) return memref; /* ??? Prefer to create garbage instead of creating shared rtl. @@ -1968,7 +1991,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, /* Convert a possibly large offset to a signed value within the range of the target address space. */ - pbits = GET_MODE_BITSIZE (Pmode); + pbits = GET_MODE_BITSIZE (address_mode); if (HOST_BITS_PER_WIDE_INT > pbits) { int shift = HOST_BITS_PER_WIDE_INT - pbits; @@ -1984,7 +2007,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, && offset >= 0 && (unsigned HOST_WIDE_INT) offset < GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT) - addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0), + addr = gen_rtx_LO_SUM (address_mode, XEXP (addr, 0), plus_constant (XEXP (addr, 1), offset)); else addr = plus_constant (addr, offset); @@ -2017,7 +2040,8 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, size = plus_constant (MEM_SIZE (memref), -offset); MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), - memoffset, size, memalign, GET_MODE (new_rtx)); + memoffset, size, memalign, as, + GET_MODE (new_rtx)); /* At some point, we should validate that this offset is within the object, if all the appropriate values are known. */ @@ -2045,8 +2069,10 @@ rtx offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) { rtx new_rtx, addr = XEXP (memref, 0); + addr_space_t as = MEM_ADDR_SPACE (memref); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); - new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, address_mode, addr, offset); /* At this point we don't know _why_ the address is invalid. It could have secondary memory references, multiplies or anything. @@ -2055,12 +2081,12 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) being able to recognize the magic around pic_offset_table_rtx. This stuff is fragile, and is yet another example of why it is bad to expose PIC machinery too early. */ - if (! memory_address_p (GET_MODE (memref), new_rtx) + if (! memory_address_addr_space_p (GET_MODE (memref), new_rtx, as) && GET_CODE (addr) == PLUS && XEXP (addr, 0) == pic_offset_table_rtx) { addr = force_reg (GET_MODE (addr), addr); - new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, address_mode, addr, offset); } update_temp_slot_address (XEXP (memref, 0), new_rtx); @@ -2075,7 +2101,7 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0, MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT), - GET_MODE (new_rtx)); + as, GET_MODE (new_rtx)); return new_rtx; } @@ -2179,7 +2205,8 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) /* ??? Maybe use get_alias_set on any remaining expression. */ MEM_ATTRS (new_rtx) = get_mem_attrs (0, expr, memoffset, GEN_INT (size), - MEM_ALIGN (new_rtx), mode); + MEM_ALIGN (new_rtx), + MEM_ADDR_SPACE (new_rtx), mode); return new_rtx; } @@ -2207,7 +2234,7 @@ get_spill_slot_decl (bool force_build_p) rd = gen_rtx_MEM (BLKmode, frame_pointer_rtx); MEM_NOTRAP_P (rd) = 1; MEM_ATTRS (rd) = get_mem_attrs (new_alias_set (), d, const0_rtx, - NULL_RTX, 0, BLKmode); + NULL_RTX, 0, ADDR_SPACE_GENERIC, BLKmode); SET_DECL_RTL (d, rd); return d; @@ -2240,7 +2267,7 @@ set_mem_attrs_for_spill (rtx mem) MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset, MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + ADDR_SPACE_GENERIC, GET_MODE (mem)); MEM_NOTRAP_P (mem) = 1; } diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h index ad96181af40..01479e1eb5f 100644 --- a/gcc/emit-rtl.h +++ b/gcc/emit-rtl.h @@ -26,6 +26,9 @@ extern void set_mem_alias_set (rtx, alias_set_type); /* Set the alignment of MEM to ALIGN bits. */ extern void set_mem_align (rtx, unsigned int); +/* Set the address space of MEM to ADDRSPACE. */ +extern void set_mem_addr_space (rtx, addr_space_t); + /* Set the expr for MEM to EXPR. */ extern void set_mem_expr (rtx, tree); diff --git a/gcc/explow.c b/gcc/explow.c index 3073ff0eb91..c38682d4ce5 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -306,27 +306,27 @@ break_out_memory_refs (rtx x) rtx op1 = break_out_memory_refs (XEXP (x, 1)); if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1)) - x = simplify_gen_binary (GET_CODE (x), Pmode, op0, op1); + x = simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1); } return x; } -/* Given X, a memory address in ptr_mode, convert it to an address - in Pmode, or vice versa (TO_MODE says which way). We take advantage of - the fact that pointers are not allowed to overflow by commuting arithmetic - operations over conversions so that address arithmetic insns can be - used. */ +/* Given X, a memory address in address space AS' pointer mode, convert it to + an address in the address space's address mode, or vice versa (TO_MODE says + which way). We take advantage of the fact that pointers are not allowed to + overflow by commuting arithmetic operations over conversions so that address + arithmetic insns can be used. */ rtx -convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, - rtx x) +convert_memory_address_addr_space (enum machine_mode to_mode ATTRIBUTE_UNUSED, + rtx x, addr_space_t as ATTRIBUTE_UNUSED) { #ifndef POINTERS_EXTEND_UNSIGNED gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode); return x; #else /* defined(POINTERS_EXTEND_UNSIGNED) */ - enum machine_mode from_mode; + enum machine_mode pointer_mode, address_mode, from_mode; rtx temp; enum rtx_code code; @@ -334,7 +334,9 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, if (GET_MODE (x) == to_mode) return x; - from_mode = to_mode == ptr_mode ? Pmode : ptr_mode; + pointer_mode = targetm.addr_space.pointer_mode (as); + address_mode = targetm.addr_space.address_mode (as); + from_mode = to_mode == pointer_mode ? address_mode : pointer_mode; /* Here we handle some special cases. If none of them apply, fall through to the default case. */ @@ -375,7 +377,8 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, case CONST: return gen_rtx_CONST (to_mode, - convert_memory_address (to_mode, XEXP (x, 0))); + convert_memory_address_addr_space + (to_mode, XEXP (x, 0), as)); break; case PLUS: @@ -389,10 +392,12 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode) || (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) - && (XEXP (x, 1) == convert_memory_address (to_mode, XEXP (x, 1)) + && (XEXP (x, 1) == convert_memory_address_addr_space + (to_mode, XEXP (x, 1), as) || POINTERS_EXTEND_UNSIGNED < 0))) return gen_rtx_fmt_ee (GET_CODE (x), to_mode, - convert_memory_address (to_mode, XEXP (x, 0)), + convert_memory_address_addr_space + (to_mode, XEXP (x, 0), as), XEXP (x, 1)); break; @@ -405,21 +410,22 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, #endif /* defined(POINTERS_EXTEND_UNSIGNED) */ } -/* Return something equivalent to X but valid as a memory address - for something of mode MODE. When X is not itself valid, this - works by copying X or subexpressions of it into registers. */ +/* Return something equivalent to X but valid as a memory address for something + of mode MODE in the named address space AS. When X is not itself valid, + this works by copying X or subexpressions of it into registers. */ rtx -memory_address (enum machine_mode mode, rtx x) +memory_address_addr_space (enum machine_mode mode, rtx x, addr_space_t as) { rtx oldx = x; + enum machine_mode address_mode = targetm.addr_space.address_mode (as); - x = convert_memory_address (Pmode, x); + x = convert_memory_address_addr_space (address_mode, x, as); /* By passing constant addresses through registers we get a chance to cse them. */ if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x)) - x = force_reg (Pmode, x); + x = force_reg (address_mode, x); /* We get better cse by rejecting indirect addressing at this stage. Let the combiner create indirect addresses where appropriate. @@ -431,12 +437,12 @@ memory_address (enum machine_mode mode, rtx x) x = break_out_memory_refs (x); /* At this point, any valid address is accepted. */ - if (memory_address_p (mode, x)) + if (memory_address_addr_space_p (mode, x, as)) goto done; /* If it was valid before but breaking out memory refs invalidated it, use it the old way. */ - if (memory_address_p (mode, oldx)) + if (memory_address_addr_space_p (mode, oldx, as)) { x = oldx; goto done; @@ -447,9 +453,9 @@ memory_address (enum machine_mode mode, rtx x) below can handle all possible cases, but machine-dependent transformations can make better code. */ { - rtx orig_x = x; - x = targetm.legitimize_address (x, oldx, mode); - if (orig_x != x && memory_address_p (mode, x)) + rtx orig_x = x; + x = targetm.addr_space.legitimize_address (x, oldx, mode, as); + if (orig_x != x && memory_address_addr_space_p (mode, x, as)) goto done; } @@ -467,12 +473,12 @@ memory_address (enum machine_mode mode, rtx x) rtx constant_term = const0_rtx; rtx y = eliminate_constant_term (x, &constant_term); if (constant_term == const0_rtx - || ! memory_address_p (mode, y)) + || ! memory_address_addr_space_p (mode, y, as)) x = force_operand (x, NULL_RTX); else { y = gen_rtx_PLUS (GET_MODE (x), copy_to_reg (y), constant_term); - if (! memory_address_p (mode, y)) + if (! memory_address_addr_space_p (mode, y, as)) x = force_operand (x, NULL_RTX); else x = y; @@ -490,12 +496,12 @@ memory_address (enum machine_mode mode, rtx x) /* Last resort: copy the value to a register, since the register is a valid address. */ else - x = force_reg (Pmode, x); + x = force_reg (address_mode, x); } done: - gcc_assert (memory_address_p (mode, x)); + gcc_assert (memory_address_addr_space_p (mode, x, as)); /* If we didn't change the address, we are done. Otherwise, mark a reg as a pointer if we have REG or REG + CONST_INT. */ if (oldx == x) @@ -523,7 +529,8 @@ validize_mem (rtx ref) if (!MEM_P (ref)) return ref; ref = use_anchored_address (ref); - if (memory_address_p (GET_MODE (ref), XEXP (ref, 0))) + if (memory_address_addr_space_p (GET_MODE (ref), XEXP (ref, 0), + MEM_ADDR_SPACE (ref))) return ref; /* Don't alter REF itself, since that is probably a stack slot. */ @@ -800,7 +807,8 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, enum machine_mode mode, case REFERENCE_TYPE: case POINTER_TYPE: *punsignedp = POINTERS_EXTEND_UNSIGNED; - return Pmode; + return targetm.addr_space.address_mode + (TYPE_ADDR_SPACE (TREE_TYPE (type))); break; #endif diff --git a/gcc/expmed.c b/gcc/expmed.c index 98a99a2b5f1..12370d07333 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -5089,10 +5089,11 @@ make_tree (tree type, rtx x) default: t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type); - /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being - ptr_mode. So convert. */ + /* If TYPE is a POINTER_TYPE, we might need to convert X from + address mode to pointer mode. */ if (POINTER_TYPE_P (type)) - x = convert_memory_address (TYPE_MODE (type), x); + x = convert_memory_address_addr_space + (TYPE_MODE (type), x, TYPE_ADDR_SPACE (TREE_TYPE (type))); /* Note that we do *not* use SET_DECL_RTL here, because we do not want set_decl_rtl to go adjusting REG_ATTRS for this temporary. */ diff --git a/gcc/expr.c b/gcc/expr.c index 5d18435a99a..e62b5302114 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -877,6 +877,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, unsigned int align, int endp) { struct move_by_pieces_d data; + enum machine_mode to_addr_mode, from_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (from)); rtx to_addr, from_addr = XEXP (from, 0); unsigned int max_size = MOVE_MAX_PIECES + 1; enum machine_mode mode = VOIDmode, tmode; @@ -888,6 +890,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, data.from_addr = from_addr; if (to) { + to_addr_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to)); to_addr = XEXP (to, 0); data.to = to; data.autinc_to @@ -898,6 +901,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, } else { + to_addr_mode = VOIDmode; to_addr = NULL_RTX; data.to = NULL_RTX; data.autinc_to = 1; @@ -933,32 +937,34 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from) { - data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len)); + data.from_addr = copy_to_mode_reg (from_addr_mode, + plus_constant (from_addr, len)); data.autinc_from = 1; data.explicit_inc_from = -1; } if (USE_LOAD_POST_INCREMENT (mode) && ! data.autinc_from) { - data.from_addr = copy_addr_to_reg (from_addr); + data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr); data.autinc_from = 1; data.explicit_inc_from = 1; } if (!data.autinc_from && CONSTANT_P (from_addr)) - data.from_addr = copy_addr_to_reg (from_addr); + data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr); if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to) { - data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); + data.to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (to_addr, len)); data.autinc_to = 1; data.explicit_inc_to = -1; } if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse && ! data.autinc_to) { - data.to_addr = copy_addr_to_reg (to_addr); + data.to_addr = copy_to_mode_reg (to_addr_mode, to_addr); data.autinc_to = 1; data.explicit_inc_to = 1; } if (!data.autinc_to && CONSTANT_P (to_addr)) - data.to_addr = copy_addr_to_reg (to_addr); + data.to_addr = copy_to_mode_reg (to_addr_mode, to_addr); } tmode = mode_for_size (MOVE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1); @@ -1013,7 +1019,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0) emit_insn (gen_add2_insn (data.to_addr, constm1_rtx)); else - data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr, + data.to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (data.to_addr, -1)); } to1 = adjust_automodify_address (data.to, QImode, data.to_addr, @@ -1215,7 +1222,9 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, else if (emit_block_move_via_movmem (x, y, size, align, expected_align, expected_size)) ; - else if (may_use_call) + else if (may_use_call + && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) + && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y))) retval = emit_block_move_via_libcall (x, y, size, method == BLOCK_OP_TAILCALL); else @@ -1466,6 +1475,10 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, unsigned int align ATTRIBUTE_UNUSED) { rtx cmp_label, top_label, iter, x_addr, y_addr, tmp; + enum machine_mode x_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + enum machine_mode y_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (y)); enum machine_mode iter_mode; iter_mode = GET_MODE (size); @@ -1485,9 +1498,13 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, emit_jump (cmp_label); emit_label (top_label); - tmp = convert_modes (Pmode, iter_mode, iter, true); - x_addr = gen_rtx_PLUS (Pmode, x_addr, tmp); - y_addr = gen_rtx_PLUS (Pmode, y_addr, tmp); + tmp = convert_modes (x_addr_mode, iter_mode, iter, true); + x_addr = gen_rtx_PLUS (x_addr_mode, x_addr, tmp); + + if (x_addr_mode != y_addr_mode) + tmp = convert_modes (y_addr_mode, iter_mode, iter, true); + y_addr = gen_rtx_PLUS (y_addr_mode, y_addr, tmp); + x = change_address (x, QImode, x_addr); y = change_address (y, QImode, y_addr); @@ -2382,6 +2399,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len, rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode), void *constfundata, unsigned int align, bool memsetp, int endp) { + enum machine_mode to_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to)); struct store_by_pieces_d data; if (len == 0) @@ -2410,7 +2429,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len, if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0) emit_insn (gen_add2_insn (data.to_addr, constm1_rtx)); else - data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr, + data.to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (data.to_addr, -1)); } to1 = adjust_automodify_address (data.to, QImode, data.to_addr, @@ -2465,6 +2485,8 @@ static void store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, unsigned int align ATTRIBUTE_UNUSED) { + enum machine_mode to_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (data->to)); rtx to_addr = XEXP (data->to, 0); unsigned int max_size = STORE_MAX_PIECES + 1; enum machine_mode mode = VOIDmode, tmode; @@ -2496,7 +2518,8 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to) { - data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len)); + data->to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (to_addr, data->len)); data->autinc_to = 1; data->explicit_inc_to = -1; } @@ -2504,13 +2527,13 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse && ! data->autinc_to) { - data->to_addr = copy_addr_to_reg (to_addr); + data->to_addr = copy_to_mode_reg (to_addr_mode, to_addr); data->autinc_to = 1; data->explicit_inc_to = 1; } if ( !data->autinc_to && CONSTANT_P (to_addr)) - data->to_addr = copy_addr_to_reg (to_addr); + data->to_addr = copy_to_mode_reg (to_addr_mode, to_addr); } tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1); @@ -2641,9 +2664,11 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method, else if (set_storage_via_setmem (object, size, const0_rtx, align, expected_align, expected_size)) ; - else + else if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (object))) return set_storage_via_libcall (object, size, const0_rtx, method == BLOCK_OP_TAILCALL); + else + gcc_unreachable (); return NULL; } @@ -3432,12 +3457,14 @@ emit_move_insn (rtx x, rtx y) /* If X or Y are memory references, verify that their addresses are valid for the machine. */ if (MEM_P (x) - && (! memory_address_p (GET_MODE (x), XEXP (x, 0)) + && (! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), + MEM_ADDR_SPACE (x)) && ! push_operand (x, GET_MODE (x)))) x = validize_mem (x); if (MEM_P (y) - && ! memory_address_p (GET_MODE (y), XEXP (y, 0))) + && ! memory_address_addr_space_p (GET_MODE (y), XEXP (y, 0), + MEM_ADDR_SPACE (y))) y = validize_mem (y); gcc_assert (mode != BLKmode); @@ -4208,6 +4235,7 @@ expand_assignment (tree to, tree from, bool nontemporal) if (offset != 0) { + enum machine_mode address_mode; rtx offset_rtx; if (!MEM_P (to_rtx)) @@ -4220,13 +4248,10 @@ expand_assignment (tree to, tree from, bool nontemporal) } offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); -#else - if (GET_MODE (offset_rtx) != ptr_mode) - offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); -#endif + address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx)); + if (GET_MODE (offset_rtx) != address_mode) + offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); /* A constant address in TO_RTX can have VOIDmode, we must not try to call force_reg for that case. Avoid that case. */ @@ -4298,20 +4323,25 @@ expand_assignment (tree to, tree from, bool nontemporal) else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF) { + addr_space_t as = ADDR_SPACE_GENERIC; enum machine_mode mode, op_mode1; enum insn_code icode; rtx reg, addr, mem, insn; + if (POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (to, 0)))) + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0)))); + reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL); reg = force_not_mem (reg); mode = TYPE_MODE (TREE_TYPE (to)); addr = expand_expr (TREE_OPERAND (to, 0), NULL_RTX, VOIDmode, EXPAND_SUM); - addr = memory_address (mode, addr); + addr = memory_address_addr_space (mode, addr, as); mem = gen_rtx_MEM (mode, addr); set_mem_attributes (mem, to, 0); + set_mem_addr_space (mem, as); icode = movmisalign_optab->handlers[mode].insn_code; gcc_assert (icode != CODE_FOR_nothing); @@ -4360,7 +4390,10 @@ expand_assignment (tree to, tree from, bool nontemporal) else { if (POINTER_TYPE_P (TREE_TYPE (to))) - value = convert_memory_address (GET_MODE (to_rtx), value); + value = convert_memory_address_addr_space + (GET_MODE (to_rtx), value, + TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (to)))); + emit_move_insn (to_rtx, value); } preserve_temp_slots (to_rtx); @@ -4400,6 +4433,8 @@ expand_assignment (tree to, tree from, bool nontemporal) the place the value is being stored, use a safe function when copying a value through a pointer into a structure value return block. */ if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF + && ADDR_SPACE_GENERIC_P + (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (from, 0))))) && cfun->returns_struct && !cfun->returns_pcc_struct) { @@ -4718,6 +4753,11 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); else { + enum machine_mode pointer_mode + = targetm.addr_space.pointer_mode (MEM_ADDR_SPACE (target)); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (target)); + /* Compute the size of the data to copy from the string. */ tree copy_size = size_binop_loc (loc, MIN_EXPR, @@ -4730,14 +4770,14 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) rtx label = 0; /* Copy that much. */ - copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, + copy_size_rtx = convert_to_mode (pointer_mode, copy_size_rtx, TYPE_UNSIGNED (sizetype)); emit_block_move (target, temp, copy_size_rtx, (call_param_p ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); /* Figure out how much is left in TARGET that we have to clear. - Do all calculations in ptr_mode. */ + Do all calculations in pointer_mode. */ if (CONST_INT_P (copy_size_rtx)) { size = plus_constant (size, -INTVAL (copy_size_rtx)); @@ -4750,11 +4790,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) copy_size_rtx, NULL_RTX, 0, OPTAB_LIB_WIDEN); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (copy_size_rtx) != Pmode) - copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx, + if (GET_MODE (copy_size_rtx) != address_mode) + copy_size_rtx = convert_to_mode (address_mode, + copy_size_rtx, TYPE_UNSIGNED (sizetype)); -#endif target = offset_address (target, copy_size_rtx, highest_pow2_factor (copy_size)); @@ -5244,6 +5283,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (offset) { + enum machine_mode address_mode; rtx offset_rtx; offset @@ -5254,13 +5294,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) offset_rtx = expand_normal (offset); gcc_assert (MEM_P (to_rtx)); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); -#else - if (GET_MODE (offset_rtx) != ptr_mode) - offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); -#endif + address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx)); + if (GET_MODE (offset_rtx) != address_mode) + offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); to_rtx = offset_address (to_rtx, offset_rtx, highest_pow2_factor (offset)); @@ -6783,7 +6820,7 @@ expand_expr_constant (tree exp, int defer, enum expand_modifier modifier) static rtx expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, - enum expand_modifier modifier) + enum expand_modifier modifier, addr_space_t as) { rtx result, subtarget; tree inner, offset; @@ -6810,7 +6847,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, case CONST_DECL: /* Recurse and make the output_constant_def clause above handle this. */ return expand_expr_addr_expr_1 (DECL_INITIAL (exp), target, - tmode, modifier); + tmode, modifier, as); case REALPART_EXPR: /* The real part of the complex number is always first, therefore @@ -6900,7 +6937,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, TYPE_ALIGN (TREE_TYPE (inner)) = TYPE_ALIGN (TREE_TYPE (exp)); TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1; } - result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier); + result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier, as); if (offset) { @@ -6912,8 +6949,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, modifier == EXPAND_INITIALIZER ? EXPAND_INITIALIZER : EXPAND_NORMAL); - result = convert_memory_address (tmode, result); - tmp = convert_memory_address (tmode, tmp); + result = convert_memory_address_addr_space (tmode, result, as); + tmp = convert_memory_address_addr_space (tmode, tmp, as); if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER) result = gen_rtx_PLUS (tmode, result, tmp); @@ -6946,6 +6983,9 @@ static rtx expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier) { + addr_space_t as = ADDR_SPACE_GENERIC; + enum machine_mode address_mode = Pmode; + enum machine_mode pointer_mode = ptr_mode; enum machine_mode rmode; rtx result; @@ -6953,14 +6993,21 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, if (tmode == VOIDmode) tmode = TYPE_MODE (TREE_TYPE (exp)); + if (POINTER_TYPE_P (TREE_TYPE (exp))) + { + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.addr_space.pointer_mode (as); + } + /* We can get called with some Weird Things if the user does silliness like "(short) &a". In that case, convert_memory_address won't do the right thing, so ignore the given target mode. */ - if (tmode != Pmode && tmode != ptr_mode) - tmode = Pmode; + if (tmode != address_mode && tmode != pointer_mode) + tmode = address_mode; result = expand_expr_addr_expr_1 (TREE_OPERAND (exp, 0), target, - tmode, modifier); + tmode, modifier, as); /* Despite expand_expr claims concerning ignoring TMODE when not strictly convenient, stuff breaks if we don't honor it. Note @@ -6969,7 +7016,7 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, if (rmode == VOIDmode) rmode = tmode; if (rmode != tmode) - result = convert_memory_address (tmode, result); + result = convert_memory_address_addr_space (tmode, result, as); return result; } @@ -7343,6 +7390,39 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, return REDUCE_BIT_FIELD (op0); + case ADDR_SPACE_CONVERT_EXPR: + { + tree treeop0_type = TREE_TYPE (treeop0); + addr_space_t as_to; + addr_space_t as_from; + + gcc_assert (POINTER_TYPE_P (type)); + gcc_assert (POINTER_TYPE_P (treeop0_type)); + + as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + as_from = TYPE_ADDR_SPACE (TREE_TYPE (treeop0_type)); + + /* Conversions between pointers to the same address space should + have been implemented via CONVERT_EXPR / NOP_EXPR. */ + gcc_assert (as_to != as_from); + + /* Ask target code to handle conversion between pointers + to overlapping address spaces. */ + if (targetm.addr_space.subset_p (as_to, as_from) + || targetm.addr_space.subset_p (as_from, as_to)) + { + op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier); + op0 = targetm.addr_space.convert (op0, treeop0_type, type); + gcc_assert (op0); + return op0; + } + + /* For disjoint address spaces, converting anything but + a null pointer invokes undefined behaviour. We simply + always return a null pointer here. */ + return CONST0_RTX (mode); + } + case POINTER_PLUS_EXPR: /* Even though the sizetype mode and the pointer's mode can be different expand is able to handle this correctly and get the correct result out @@ -8431,7 +8511,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, decl_rtl = use_anchored_address (decl_rtl); if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_SUM - && !memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0))) + && !memory_address_addr_space_p (DECL_MODE (exp), + XEXP (decl_rtl, 0), + MEM_ADDR_SPACE (decl_rtl))) temp = replace_equiv_address (decl_rtl, copy_rtx (XEXP (decl_rtl, 0))); } @@ -8551,7 +8633,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER && modifier != EXPAND_SUM - && ! memory_address_p (mode, XEXP (temp, 0))) + && ! memory_address_addr_space_p (mode, XEXP (temp, 0), + MEM_ADDR_SPACE (temp))) return replace_equiv_address (temp, copy_rtx (XEXP (temp, 0))); return temp; @@ -8607,6 +8690,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case INDIRECT_REF: { tree exp1 = treeop0; + addr_space_t as = ADDR_SPACE_GENERIC; + enum machine_mode address_mode = Pmode; if (modifier != EXPAND_WRITE) { @@ -8617,19 +8702,26 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return expand_expr (t, target, tmode, modifier); } + if (POINTER_TYPE_P (TREE_TYPE (exp1))) + { + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1))); + address_mode = targetm.addr_space.address_mode (as); + } + op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM); - op0 = memory_address (mode, op0); + op0 = memory_address_addr_space (mode, op0, as); if (code == ALIGN_INDIRECT_REF) { int align = TYPE_ALIGN_UNIT (type); - op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align)); - op0 = memory_address (mode, op0); + op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align)); + op0 = memory_address_addr_space (mode, op0, as); } temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); + set_mem_addr_space (temp, as); /* Resolve the misalignment now, so that we don't have to remember to resolve it later. Of course, this only works for reads. */ @@ -8661,13 +8753,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case TARGET_MEM_REF: { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); struct mem_address addr; get_address_description (exp, &addr); - op0 = addr_for_mem_ref (&addr, true); - op0 = memory_address (mode, op0); + op0 = addr_for_mem_ref (&addr, as, true); + op0 = memory_address_addr_space (mode, op0, as); temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, TMR_ORIGINAL (exp), 0); + set_mem_addr_space (temp, as); } return temp; @@ -8955,18 +9049,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (offset) { + enum machine_mode address_mode; rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); gcc_assert (MEM_P (op0)); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); -#else - if (GET_MODE (offset_rtx) != ptr_mode) - offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); -#endif + address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (op0)); + if (GET_MODE (offset_rtx) != address_mode) + offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); if (GET_MODE (op0) == BLKmode /* A constant address in OP0 can have VOIDmode, we must diff --git a/gcc/expr.h b/gcc/expr.h index 4e02c24b75f..0eceb6e45be 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -650,9 +650,15 @@ extern rtx force_label_rtx (tree); The constant terms are added and stored via a second arg. */ extern rtx eliminate_constant_term (rtx, rtx *); -/* Convert arg to a valid memory address for specified machine mode, - by emitting insns to perform arithmetic if nec. */ -extern rtx memory_address (enum machine_mode, rtx); +/* Convert arg to a valid memory address for specified machine mode that points + to a specific named address space, by emitting insns to perform arithmetic + if necessary. */ +extern rtx memory_address_addr_space (enum machine_mode, rtx, addr_space_t); + +/* Like memory_address_addr_space, except assume the memory address points to + the generic named address space. */ +#define memory_address(MODE,RTX) \ + memory_address_addr_space ((MODE), (RTX), ADDR_SPACE_GENERIC) /* Return a memory reference like MEMREF, but with its mode changed to MODE and its address changed to ADDR. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 1539ad21387..102929d1e20 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -206,15 +206,9 @@ fit_double_type (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, { unsigned HOST_WIDE_INT low0 = l1; HOST_WIDE_INT high0 = h1; - unsigned int prec; + unsigned int prec = int_or_pointer_precision (type); int sign_extended_type; - if (POINTER_TYPE_P (type) - || TREE_CODE (type) == OFFSET_TYPE) - prec = POINTER_SIZE; - else - prec = TYPE_PRECISION (type); - /* Size types *are* sign extended. */ sign_extended_type = (!TYPE_UNSIGNED (type) || (TREE_CODE (type) == INTEGER_TYPE @@ -2647,8 +2641,16 @@ fold_convert_loc (location_t loc, tree type, tree arg) switch (TREE_CODE (type)) { + case POINTER_TYPE: + case REFERENCE_TYPE: + /* Handle conversions between pointers to different address spaces. */ + if (POINTER_TYPE_P (orig) + && (TYPE_ADDR_SPACE (TREE_TYPE (type)) + != TYPE_ADDR_SPACE (TREE_TYPE (orig)))) + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, arg); + /* fall through */ + case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: - case POINTER_TYPE: case REFERENCE_TYPE: case OFFSET_TYPE: if (TREE_CODE (arg) == INTEGER_CST) { @@ -3179,6 +3181,12 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE (arg1))) return 0; + /* We cannot consider pointers to different address space equal. */ + if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE (arg1)) + && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0))) + != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1))))) + return 0; + /* If both types don't have the same precision, then it is not safe to strip NOPs. */ if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE (arg1))) @@ -8682,6 +8690,11 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) tem = fold_convert_const (code, type, op0); return tem ? tem : NULL_TREE; + case ADDR_SPACE_CONVERT_EXPR: + if (integer_zerop (arg0)) + return fold_convert_const (code, type, arg0); + return NULL_TREE; + case FIXED_CONVERT_EXPR: tem = fold_convert_const (code, type, arg0); return tem ? tem : NULL_TREE; diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index cf6c8cd2dcb..8c333d8ca18 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,19 @@ +2009-10-26 Janus Weil <janus@gcc.gnu.org> + + PR fortran/41714 + * trans.c (gfc_trans_code): Remove call to + 'tree_annotate_all_with_location'. Location should already be set. + * trans-openmp.c (gfc_trans_omp_workshare): Ditto. + * trans-stmt.c (gfc_trans_allocate): Do correct data initialization for + CLASS variables with SOURCE tag, plus some cleanup. + +2009-10-24 Janus Weil <janus@gcc.gnu.org> + Paul Thomas <pault@gcc.gnu.org> + + PR fortran/41784 + * module.c (load_derived_extensions): Skip symbols which are not being + loaded. + 2009-10-24 Paul Thomas <pault@gcc.gnu.org> PR fortran/41772 diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c index 2112d3e82b1..b2ad6ecc477 100644 --- a/gcc/fortran/module.c +++ b/gcc/fortran/module.c @@ -3994,6 +3994,14 @@ load_derived_extensions (void) info = get_integer (symbol); derived = info->u.rsym.sym; + /* This one is not being loaded. */ + if (!info || !derived) + { + while (peek_atom () != ATOM_RPAREN) + skip_list (); + continue; + } + gcc_assert (derived->attr.flavor == FL_DERIVED); if (derived->f2k_derived == NULL) derived->f2k_derived = gfc_get_namespace (NULL, 0); @@ -4008,16 +4016,19 @@ load_derived_extensions (void) nuse = number_use_names (name, false); j = 1; p = find_use_name_n (name, &j, false); - st = gfc_find_symtree (gfc_current_ns->sym_root, p); - dt = st->n.sym; - st = gfc_find_symtree (derived->f2k_derived->sym_root, name); - if (st == NULL) + if (p) { - /* Only use the real name in f2k_derived to ensure a single - symtree. */ - st = gfc_new_symtree (&derived->f2k_derived->sym_root, name); - st->n.sym = dt; - st->n.sym->refs++; + st = gfc_find_symtree (gfc_current_ns->sym_root, p); + dt = st->n.sym; + st = gfc_find_symtree (derived->f2k_derived->sym_root, name); + if (st == NULL) + { + /* Only use the real name in f2k_derived to ensure a single + symtree. */ + st = gfc_new_symtree (&derived->f2k_derived->sym_root, name); + st->n.sym = dt; + st->n.sym->refs++; + } } mio_rparen (); } diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 56534ccdd38..4d461cfa488 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -1641,11 +1641,6 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { - if (TREE_CODE (res) == STATEMENT_LIST) - tree_annotate_all_with_location (&res, input_location); - else - SET_EXPR_LOCATION (res, input_location); - if (prev_singleunit) { if (ompws_flags & OMPWS_CURR_SINGLEUNIT) diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 7dc7405c67f..9b2a6230853 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -3983,12 +3983,13 @@ gfc_trans_allocate (gfc_code * code) tree stat; tree pstat; tree error_label; + tree memsz; stmtblock_t block; if (!code->ext.alloc.list) return NULL_TREE; - pstat = stat = error_label = tmp = NULL_TREE; + pstat = stat = error_label = tmp = memsz = NULL_TREE; gfc_start_block (&block); @@ -4032,19 +4033,19 @@ gfc_trans_allocate (gfc_code * code) gfc_init_se (&se_sz, NULL); gfc_conv_expr (&se_sz, sz); gfc_free_expr (sz); - tmp = se_sz.expr; + memsz = se_sz.expr; } else if (code->expr3 && code->expr3->ts.type != BT_CLASS) - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr3->ts)); + memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr3->ts)); else if (code->ext.alloc.ts.type != BT_UNKNOWN) - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts)); + memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts)); else - tmp = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr))); + memsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr))); - if (expr->ts.type == BT_CHARACTER && tmp == NULL_TREE) - tmp = se.string_length; + if (expr->ts.type == BT_CHARACTER && memsz == NULL_TREE) + memsz = se.string_length; - tmp = gfc_allocate_with_status (&se.pre, tmp, pstat); + tmp = gfc_allocate_with_status (&se.pre, memsz, pstat); tmp = fold_build2 (MODIFY_EXPR, void_type_node, se.expr, fold_convert (TREE_TYPE (se.expr), tmp)); gfc_add_expr_to_block (&se.pre, tmp); @@ -4075,21 +4076,17 @@ gfc_trans_allocate (gfc_code * code) if (code->expr3) { gfc_expr *rhs = gfc_copy_expr (code->expr3); - if (rhs->ts.type == BT_CLASS) + if (al->expr->ts.type == BT_CLASS) { - gfc_se dst,src,len; - gfc_expr *sz; - gfc_add_component_ref (rhs, "$data"); - sz = gfc_copy_expr (code->expr3); - gfc_add_component_ref (sz, "$size"); + gfc_se dst,src; + if (rhs->ts.type == BT_CLASS) + gfc_add_component_ref (rhs, "$data"); gfc_init_se (&dst, NULL); gfc_init_se (&src, NULL); - gfc_init_se (&len, NULL); gfc_conv_expr (&dst, expr); gfc_conv_expr (&src, rhs); - gfc_conv_expr (&len, sz); - gfc_free_expr (sz); - tmp = gfc_build_memcpy_call (dst.expr, src.expr, len.expr); + gfc_add_block_to_block (&block, &src.pre); + tmp = gfc_build_memcpy_call (dst.expr, src.expr, memsz); } else tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), @@ -4108,8 +4105,7 @@ gfc_trans_allocate (gfc_code * code) gfc_conv_expr (&dst, expr); gfc_conv_expr (&src, init_e); gfc_add_block_to_block (&block, &src.pre); - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts)); - tmp = gfc_build_memcpy_call (dst.expr, src.expr, tmp); + tmp = gfc_build_memcpy_call (dst.expr, src.expr, memsz); gfc_add_expr_to_block (&block, tmp); } /* Add default initializer for those derived types that need them. */ @@ -4127,6 +4123,7 @@ gfc_trans_allocate (gfc_code * code) if (expr->ts.type == BT_CLASS) { gfc_expr *lhs,*rhs; + gfc_se lse; /* Initialize VINDEX for CLASS objects. */ lhs = gfc_expr_to_initialize (expr); gfc_add_component_ref (lhs, "$vindex"); @@ -4158,36 +4155,11 @@ gfc_trans_allocate (gfc_code * code) /* Initialize SIZE for CLASS objects. */ lhs = gfc_expr_to_initialize (expr); gfc_add_component_ref (lhs, "$size"); - rhs = NULL; - if (code->expr3 && code->expr3->ts.type == BT_CLASS) - { - /* Size must be determined at run time. */ - rhs = gfc_copy_expr (code->expr3); - gfc_add_component_ref (rhs, "$size"); - tmp = gfc_trans_assignment (lhs, rhs, false); - gfc_add_expr_to_block (&block, tmp); - } - else - { - /* Size is fixed at compile time. */ - gfc_typespec *ts; - gfc_se lse; - gfc_init_se (&lse, NULL); - gfc_conv_expr (&lse, lhs); - if (code->expr3) - ts = &code->expr3->ts; - else if (code->ext.alloc.ts.type == BT_DERIVED) - ts = &code->ext.alloc.ts; - else if (expr->ts.type == BT_CLASS) - ts = &expr->ts.u.derived->components->ts; - else - ts = &expr->ts; - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (ts)); - gfc_add_modify (&block, lse.expr, - fold_convert (TREE_TYPE (lse.expr), tmp)); - } + gfc_init_se (&lse, NULL); + gfc_conv_expr (&lse, lhs); + gfc_add_modify (&block, lse.expr, + fold_convert (TREE_TYPE (lse.expr), memsz)); gfc_free_expr (lhs); - gfc_free_expr (rhs); } } diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index 22c3e076085..42d22388105 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -1281,9 +1281,7 @@ gfc_trans_code (gfc_code * code) if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { - if (TREE_CODE (res) == STATEMENT_LIST) - tree_annotate_all_with_location (&res, input_location); - else + if (TREE_CODE (res) != STATEMENT_LIST) SET_EXPR_LOCATION (res, input_location); /* Add the new statement to the block. */ diff --git a/gcc/fwprop.c b/gcc/fwprop.c index d3ed74298c0..75a354ea54d 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -375,11 +375,12 @@ canonicalize_address (rtx x) static bool should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode, - bool speed) + addr_space_t as, bool speed) { int gain; - if (rtx_equal_p (old_rtx, new_rtx) || !memory_address_p (mode, new_rtx)) + if (rtx_equal_p (old_rtx, new_rtx) + || !memory_address_addr_space_p (mode, new_rtx, as)) return false; /* Copy propagation is always ok. */ @@ -387,7 +388,8 @@ should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode, return true; /* Prefer the new address if it is less expensive. */ - gain = address_cost (old_rtx, mode, speed) - address_cost (new_rtx, mode, speed); + gain = (address_cost (old_rtx, mode, as, speed) + - address_cost (new_rtx, mode, as, speed)); /* If the addresses have equivalent cost, prefer the new address if it has the highest `rtx_cost'. That has the potential of @@ -555,6 +557,7 @@ propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags) /* Copy propagations are always ok. Otherwise check the costs. */ if (!(REG_P (old_rtx) && REG_P (new_rtx)) && !should_replace_address (op0, new_op0, GET_MODE (x), + MEM_ADDR_SPACE (x), flags & PR_OPTIMIZE_FOR_SPEED)) return true; diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 3d3134beaa6..4f6c4470c9d 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -254,6 +254,7 @@ dump_unary_rhs (pretty_printer *buffer, gimple gs, int spc, int flags) break; case FIXED_CONVERT_EXPR: + case ADDR_SPACE_CONVERT_EXPR: case FIX_TRUNC_EXPR: case FLOAT_EXPR: CASE_CONVERT: diff --git a/gcc/gimple.h b/gcc/gimple.h index 87309b694d4..8f6b3522098 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -939,7 +939,6 @@ extern tree create_tmp_var (tree, const char *); extern tree get_initialized_tmp_var (tree, gimple_seq *, gimple_seq *); extern tree get_formal_tmp_var (tree, gimple_seq *); extern void declare_vars (tree, gimple, bool); -extern void tree_annotate_all_with_location (tree *, location_t); extern void annotate_all_with_location (gimple_seq, location_t); /* Validation of GIMPLE expressions. Note that these predicates only check diff --git a/gcc/gimplify.c b/gcc/gimplify.c index c0cab205613..d68aacd04f3 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -777,23 +777,6 @@ should_carry_location_p (gimple gs) return true; } -/* Same, but for a tree. */ - -static bool -tree_should_carry_location_p (const_tree stmt) -{ - /* Don't emit a line note for a label. We particularly don't want to - emit one for the break label, since it doesn't actually correspond - to the beginning of the loop/switch. */ - if (TREE_CODE (stmt) == LABEL_EXPR) - return false; - - /* Do not annotate empty statements, since it confuses gcov. */ - if (!TREE_SIDE_EFFECTS (stmt)) - return false; - - return true; -} /* Return true if a location should not be emitted for this statement by annotate_one_with_location. */ @@ -826,16 +809,6 @@ annotate_one_with_location (gimple gs, location_t location) gimple_set_location (gs, location); } -/* Same, but for tree T. */ - -static void -tree_annotate_one_with_location (tree t, location_t location) -{ - if (CAN_HAVE_LOCATION_P (t) - && ! EXPR_HAS_LOCATION (t) && tree_should_carry_location_p (t)) - SET_EXPR_LOCATION (t, location); -} - /* Set LOCATION for all the statements after iterator GSI in sequence SEQ. If GSI is pointing to the end of the sequence, start with the @@ -872,29 +845,6 @@ annotate_all_with_location (gimple_seq stmt_p, location_t location) } } -/* Same, but for statement or statement list in *STMT_P. */ - -void -tree_annotate_all_with_location (tree *stmt_p, location_t location) -{ - tree_stmt_iterator i; - - if (!*stmt_p) - return; - - for (i = tsi_start (*stmt_p); !tsi_end_p (i); tsi_next (&i)) - { - tree t = tsi_stmt (i); - - /* Assuming we've already been gimplified, we shouldn't - see nested chaining constructs anymore. */ - gcc_assert (TREE_CODE (t) != STATEMENT_LIST - && TREE_CODE (t) != COMPOUND_EXPR); - - tree_annotate_one_with_location (t, location); - } -} - /* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes. These nodes model computations that should only be done once. If we diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c index ccf539eb0dc..2eb50df2575 100644 --- a/gcc/graphite-sese-to-poly.c +++ b/gcc/graphite-sese-to-poly.c @@ -2084,7 +2084,7 @@ build_poly_scop (scop_p scop) /* Always return false. Exercise the scop_to_clast function. */ void -check_poly_representation (scop_p scop) +check_poly_representation (scop_p scop ATTRIBUTE_UNUSED) { #ifdef ENABLE_CHECKING cloog_prog_clast pc = scop_to_clast (scop); diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 1ef2d21f903..d8d15a59be1 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1329,11 +1329,15 @@ noce_try_cmove_arith (struct noce_if_info *if_info) /* ??? FIXME: Magic number 5. */ if (cse_not_expected && MEM_P (a) && MEM_P (b) + && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b) && if_info->branch_cost >= 5) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (a)); + a = XEXP (a, 0); b = XEXP (b, 0); - x = gen_reg_rtx (Pmode); + x = gen_reg_rtx (address_mode); is_mem = 1; } @@ -1482,6 +1486,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info) set_mem_align (tmp, MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b))); + gcc_assert (MEM_ADDR_SPACE (if_info->a) == MEM_ADDR_SPACE (if_info->b)); + set_mem_addr_space (tmp, MEM_ADDR_SPACE (if_info->a)); + noce_emit_move_insn (if_info->x, tmp); } else if (target != x) diff --git a/gcc/jump.c b/gcc/jump.c index a12d0404500..6ebc7ef1cd7 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -1695,6 +1695,10 @@ rtx_renumbered_equal_p (const_rtx x, const_rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + /* For commutative operations, the RTX match if the operand match in any order. Also handle the simple binary and unary cases without a loop. */ if (targetm.commutative_p (x, UNKNOWN)) diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c index 901ce51ac89..37f88f2fcbd 100644 --- a/gcc/loop-invariant.c +++ b/gcc/loop-invariant.c @@ -715,7 +715,7 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on, invariants). See http://gcc.gnu.org/ml/gcc-patches/2009-10/msg01210.html . */ inv->cheap_address = address_cost (SET_SRC (set), word_mode, - speed) < 3; + ADDR_SPACE_GENERIC, speed) < 3; } else { diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index 000be331a94..f7c793647bc 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -1650,6 +1650,7 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) if (TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == PARM_DECL) DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1); } } diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index d593aacc4fc..1ed1939b2b2 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -433,6 +433,7 @@ pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) if (TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == PARM_DECL) bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1); + bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1); } } diff --git a/gcc/output.h b/gcc/output.h index 9e2b704920a..5d771d7d06f 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -626,7 +626,6 @@ extern void default_emit_except_table_label (FILE *); extern void default_internal_label (FILE *, const char *, unsigned long); extern void default_file_start (void); extern void file_end_indicate_exec_stack (void); -extern bool default_valid_pointer_mode (enum machine_mode); extern void default_elf_asm_output_external (FILE *file, tree, const char *); diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index cb3f7dae31f..bc2854d9179 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -562,6 +562,9 @@ print_rtx (const_rtx in_rtx) if (MEM_ALIGN (in_rtx) != 1) fprintf (outfile, " A%u", MEM_ALIGN (in_rtx)); + if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (in_rtx))) + fprintf (outfile, " AS%u", MEM_ADDR_SPACE (in_rtx)); + fputc (']', outfile); break; diff --git a/gcc/print-tree.c b/gcc/print-tree.c index ded9ea84308..f0a3294263a 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -111,6 +111,8 @@ print_node_brief (FILE *file, const char *prefix, const_tree node, int indent) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) + fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); } if (TREE_CODE (node) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); @@ -300,6 +302,9 @@ print_node (FILE *file, const char *prefix, tree node, int indent) else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) fputs (" sizes-gimplified", file); + if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) + fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); + if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) diff --git a/gcc/recog.c b/gcc/recog.c index 6874d6c5c60..b03324146f1 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -376,7 +376,9 @@ verify_changes (int num) if (MEM_P (object)) { - if (! memory_address_p (GET_MODE (object), XEXP (object, 0))) + if (! memory_address_addr_space_p (GET_MODE (object), + XEXP (object, 0), + MEM_ADDR_SPACE (object))) break; } else if (REG_P (changes[i].old) @@ -978,7 +980,7 @@ general_operand (rtx op, enum machine_mode mode) return 0; /* Use the mem's mode, since it will be reloaded thus. */ - if (memory_address_p (GET_MODE (op), y)) + if (memory_address_addr_space_p (GET_MODE (op), y, MEM_ADDR_SPACE (op))) return 1; } @@ -1262,19 +1264,22 @@ pop_operand (rtx op, enum machine_mode mode) return XEXP (op, 0) == stack_pointer_rtx; } -/* Return 1 if ADDR is a valid memory address for mode MODE. */ +/* Return 1 if ADDR is a valid memory address + for mode MODE in address space AS. */ int -memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr) +memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx addr, addr_space_t as) { #ifdef GO_IF_LEGITIMATE_ADDRESS + gcc_assert (ADDR_SPACE_GENERIC_P (as)); GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); return 0; win: return 1; #else - return targetm.legitimate_address_p (mode, addr, 0); + return targetm.addr_space.legitimate_address_p (mode, addr, 0, as); #endif } @@ -1871,7 +1876,8 @@ int offsettable_memref_p (rtx op) { return ((MEM_P (op)) - && offsettable_address_p (1, GET_MODE (op), XEXP (op, 0))); + && offsettable_address_addr_space_p (1, GET_MODE (op), XEXP (op, 0), + MEM_ADDR_SPACE (op))); } /* Similar, but don't require a strictly valid mem ref: @@ -1881,12 +1887,13 @@ int offsettable_nonstrict_memref_p (rtx op) { return ((MEM_P (op)) - && offsettable_address_p (0, GET_MODE (op), XEXP (op, 0))); + && offsettable_address_addr_space_p (0, GET_MODE (op), XEXP (op, 0), + MEM_ADDR_SPACE (op))); } /* Return 1 if Y is a memory address which contains no side effects - and would remain valid after the addition of a positive integer - less than the size of that mode. + and would remain valid for address space AS after the addition of + a positive integer less than the size of that mode. We assume that the original address is valid and do not check it. We do check that it is valid for narrower modes. @@ -1895,14 +1902,16 @@ offsettable_nonstrict_memref_p (rtx op) for the sake of use in reload.c. */ int -offsettable_address_p (int strictp, enum machine_mode mode, rtx y) +offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y, + addr_space_t as) { enum rtx_code ycode = GET_CODE (y); rtx z; rtx y1 = y; rtx *y2; - int (*addressp) (enum machine_mode, rtx) = - (strictp ? strict_memory_address_p : memory_address_p); + int (*addressp) (enum machine_mode, rtx, addr_space_t) = + (strictp ? strict_memory_address_addr_space_p + : memory_address_addr_space_p); unsigned int mode_sz = GET_MODE_SIZE (mode); if (CONSTANT_ADDRESS_P (y)) @@ -1932,7 +1941,7 @@ offsettable_address_p (int strictp, enum machine_mode mode, rtx y) *y2 = plus_constant (*y2, mode_sz - 1); /* Use QImode because an odd displacement may be automatically invalid for any wider mode. But it should be valid for a single byte. */ - good = (*addressp) (QImode, y); + good = (*addressp) (QImode, y, as); /* In any case, restore old contents of memory. */ *y2 = y1; @@ -1957,7 +1966,7 @@ offsettable_address_p (int strictp, enum machine_mode mode, rtx y) /* Use QImode because an odd displacement may be automatically invalid for any wider mode. But it should be valid for a single byte. */ - return (*addressp) (QImode, z); + return (*addressp) (QImode, z, as); } /* Return 1 if ADDR is an address-expression whose effect depends @@ -2502,11 +2511,14 @@ constrain_operands (int strict) if (MEM_P (op)) { if (strict > 0 - && !strict_memory_address_p (GET_MODE (op), - XEXP (op, 0))) + && !strict_memory_address_addr_space_p + (GET_MODE (op), XEXP (op, 0), + MEM_ADDR_SPACE (op))) break; if (strict == 0 - && !memory_address_p (GET_MODE (op), XEXP (op, 0))) + && !memory_address_addr_space_p + (GET_MODE (op), XEXP (op, 0), + MEM_ADDR_SPACE (op))) break; win = 1; } diff --git a/gcc/recog.h b/gcc/recog.h index 4dce8d9a5ee..3354a66496a 100644 --- a/gcc/recog.h +++ b/gcc/recog.h @@ -84,8 +84,13 @@ extern int num_validated_changes (void); extern void cancel_changes (int); extern int constrain_operands (int); extern int constrain_operands_cached (int); -extern int memory_address_p (enum machine_mode, rtx); -extern int strict_memory_address_p (enum machine_mode, rtx); +extern int memory_address_addr_space_p (enum machine_mode, rtx, addr_space_t); +#define memory_address_p(mode,addr) \ + memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC) +extern int strict_memory_address_addr_space_p (enum machine_mode, rtx, + addr_space_t); +#define strict_memory_address_p(mode,addr) \ + strict_memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC) extern int validate_replace_rtx_subexp (rtx, rtx, rtx, rtx *); extern int validate_replace_rtx (rtx, rtx, rtx); extern int validate_replace_rtx_part (rtx, rtx, rtx *, rtx); @@ -101,7 +106,11 @@ extern int reg_fits_class_p (rtx, enum reg_class, int, enum machine_mode); extern int offsettable_memref_p (rtx); extern int offsettable_nonstrict_memref_p (rtx); -extern int offsettable_address_p (int, enum machine_mode, rtx); +extern int offsettable_address_addr_space_p (int, enum machine_mode, rtx, + addr_space_t); +#define offsettable_address_p(strict,mode,addr) \ + offsettable_address_addr_space_p ((strict), (mode), (addr), \ + ADDR_SPACE_GENERIC) extern int mode_dependent_address_p (rtx); extern int recog (rtx, rtx, int *); diff --git a/gcc/regcprop.c b/gcc/regcprop.c index 893751886eb..ac8350d1f4e 100644 --- a/gcc/regcprop.c +++ b/gcc/regcprop.c @@ -247,7 +247,7 @@ kill_autoinc_value (rtx *px, void *data) { x = XEXP (x, 0); kill_value (x, vd); - set_value_regno (REGNO (x), Pmode, vd); + set_value_regno (REGNO (x), GET_MODE (x), vd); return -1; } diff --git a/gcc/regmove.c b/gcc/regmove.c index 4d45d5d1beb..581af4c7edc 100644 --- a/gcc/regmove.c +++ b/gcc/regmove.c @@ -185,7 +185,9 @@ try_auto_increment (rtx insn, rtx inc_insn, rtx inc_insn_set, rtx reg, &SET_SRC (inc_insn_set), XEXP (SET_SRC (inc_insn_set), 0), 1); validate_change (insn, &XEXP (use, 0), - gen_rtx_fmt_e (inc_code, Pmode, reg), 1); + gen_rtx_fmt_e (inc_code, + GET_MODE (XEXP (use, 0)), reg), + 1); if (apply_change_group ()) { /* If there is a REG_DEAD note on this insn, we must diff --git a/gcc/reload.c b/gcc/reload.c index 1435945d62c..3333697f2e0 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -268,7 +268,8 @@ static bool alternative_allows_const_pool_ref (rtx, const char *, int); static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, rtx, int *); static rtx make_memloc (rtx, int); -static int maybe_memory_address_p (enum machine_mode, rtx, rtx *); +static int maybe_memory_address_addr_space_p (enum machine_mode, rtx, + addr_space_t, rtx *); static int find_reloads_address (enum machine_mode, rtx *, rtx, rtx *, int, enum reload_type, int, rtx); static rtx subst_reg_equivs (rtx, rtx); @@ -612,7 +613,8 @@ get_secondary_mem (rtx x ATTRIBUTE_UNUSED, enum machine_mode mode, didn't give us a new MEM, make a new one if it isn't valid. */ loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX); - mem_valid = strict_memory_address_p (mode, XEXP (loc, 0)); + mem_valid = strict_memory_address_addr_space_p (mode, XEXP (loc, 0), + MEM_ADDR_SPACE (loc)); if (! mem_valid && loc == secondary_memlocs[(int) mode]) loc = copy_rtx (loc); @@ -2129,21 +2131,23 @@ hard_reg_set_here_p (unsigned int beg_regno, unsigned int end_regno, rtx x) return 0; } -/* Return 1 if ADDR is a valid memory address for mode MODE, - and check that each pseudo reg has the proper kind of - hard reg. */ +/* Return 1 if ADDR is a valid memory address for mode MODE + in address space AS, and check that each pseudo reg has the + proper kind of hard reg. */ int -strict_memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr) +strict_memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx addr, addr_space_t as) { #ifdef GO_IF_LEGITIMATE_ADDRESS + gcc_assert (ADDR_SPACE_GENERIC_P (as)); GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); return 0; win: return 1; #else - return targetm.legitimate_address_p (mode, addr, 1); + return targetm.addr_space.legitimate_address_p (mode, addr, 1, as); #endif } @@ -2247,6 +2251,10 @@ operands_match_p (rtx x, rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + switch (code) { case CONST_INT: @@ -3979,12 +3987,15 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known, && MEM_P (recog_data.operand[i])) { /* If the address to be reloaded is a VOIDmode constant, - use Pmode as mode of the reload register, as would have - been done by find_reloads_address. */ + use the default address mode as mode of the reload register, + as would have been done by find_reloads_address. */ enum machine_mode address_mode; address_mode = GET_MODE (XEXP (recog_data.operand[i], 0)); if (address_mode == VOIDmode) - address_mode = Pmode; + { + addr_space_t as = MEM_ADDR_SPACE (recog_data.operand[i]); + address_mode = targetm.addr_space.address_mode (as); + } operand_reloadnum[i] = push_reload (XEXP (recog_data.operand[i], 0), NULL_RTX, @@ -4760,8 +4771,9 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type, #endif && (reg_equiv_address[regno] != 0 || (reg_equiv_mem[regno] != 0 - && (! strict_memory_address_p (GET_MODE (x), - XEXP (reg_equiv_mem[regno], 0)) + && (! strict_memory_address_addr_space_p + (GET_MODE (x), XEXP (reg_equiv_mem[regno], 0), + MEM_ADDR_SPACE (reg_equiv_mem[regno])) || ! offsettable_memref_p (reg_equiv_mem[regno]) || num_not_at_initial_offset)))) x = find_reloads_subreg_address (x, 1, opnum, type, ind_levels, @@ -4819,18 +4831,19 @@ make_memloc (rtx ad, int regno) } /* Returns true if AD could be turned into a valid memory reference - to mode MODE by reloading the part pointed to by PART into a - register. */ + to mode MODE in address space AS by reloading the part pointed to + by PART into a register. */ static int -maybe_memory_address_p (enum machine_mode mode, rtx ad, rtx *part) +maybe_memory_address_addr_space_p (enum machine_mode mode, rtx ad, + addr_space_t as, rtx *part) { int retv; rtx tem = *part; rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ()); *part = reg; - retv = memory_address_p (mode, ad); + retv = memory_address_addr_space_p (mode, ad, as); *part = tem; return retv; @@ -4866,6 +4879,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, rtx *loc, int opnum, enum reload_type type, int ind_levels, rtx insn) { + addr_space_t as = memrefloc? MEM_ADDR_SPACE (*memrefloc) + : ADDR_SPACE_GENERIC; int regno; int removed_and = 0; int op_index; @@ -4893,7 +4908,9 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset) { tem = make_memloc (ad, regno); - if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0))) + if (! strict_memory_address_addr_space_p (GET_MODE (tem), + XEXP (tem, 0), + MEM_ADDR_SPACE (tem))) { rtx orig = tem; @@ -4909,7 +4926,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, address: only reg or reg+constant. */ if (ind_levels > 0 - && strict_memory_address_p (mode, tem) + && strict_memory_address_addr_space_p (mode, tem, as) && (REG_P (XEXP (tem, 0)) || (GET_CODE (XEXP (tem, 0)) == PLUS && REG_P (XEXP (XEXP (tem, 0), 0)) @@ -4953,7 +4970,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, return 1; } - if (strict_memory_address_p (mode, ad)) + if (strict_memory_address_addr_space_p (mode, ad, as)) { /* The address appears valid, so reloads are not needed. But the address may contain an eliminable register. @@ -4976,14 +4993,14 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, return 0; /* Check result for validity after substitution. */ - if (strict_memory_address_p (mode, ad)) + if (strict_memory_address_addr_space_p (mode, ad, as)) return 0; } #ifdef LEGITIMIZE_RELOAD_ADDRESS do { - if (memrefloc) + if (memrefloc && ADDR_SPACE_GENERIC_P (as)) { LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type, ind_levels, win); @@ -5099,7 +5116,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, That will at least work. */ find_reloads_address_part (ad, loc, base_reg_class (mode, MEM, SCRATCH), - Pmode, opnum, type, ind_levels); + GET_MODE (ad), opnum, type, ind_levels); } return ! removed_and; } @@ -5160,8 +5177,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, || operand == arg_pointer_rtx #endif || operand == stack_pointer_rtx) - && ! maybe_memory_address_p (mode, ad, - &XEXP (XEXP (ad, 0), 1 - op_index))) + && ! maybe_memory_address_addr_space_p + (mode, ad, as, &XEXP (XEXP (ad, 0), 1 - op_index))) { rtx offset_reg; enum reg_class cls; @@ -5199,7 +5216,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, tem = ad; if (GET_CODE (ad) == PLUS) tem = subst_indexed_address (ad); - if (tem != ad && strict_memory_address_p (mode, tem)) + if (tem != ad && strict_memory_address_addr_space_p (mode, tem, as)) { /* Ok, we win that way. Replace any additional eliminable registers. */ @@ -5209,7 +5226,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, /* Make sure that didn't make the address invalid again. */ - if (! subst_reg_equivs_changed || strict_memory_address_p (mode, tem)) + if (! subst_reg_equivs_changed + || strict_memory_address_addr_space_p (mode, tem, as)) { *loc = tem; return 0; @@ -5218,8 +5236,12 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, /* If constants aren't valid addresses, reload the constant address into a register. */ - if (CONSTANT_P (ad) && ! strict_memory_address_p (mode, ad)) + if (CONSTANT_P (ad) && ! strict_memory_address_addr_space_p (mode, ad, as)) { + enum machine_mode address_mode = GET_MODE (ad); + if (ad == VOIDmode) + address_mode = targetm.addr_space.address_mode (as); + /* If AD is an address in the constant pool, the MEM rtx may be shared. Unshare it so we can safely alter it. */ if (memrefloc && GET_CODE (ad) == SYMBOL_REF @@ -5232,7 +5254,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad, } find_reloads_address_part (ad, loc, base_reg_class (mode, MEM, SCRATCH), - Pmode, opnum, type, ind_levels); + address_mode, opnum, type, ind_levels); return ! removed_and; } @@ -5319,16 +5341,12 @@ subst_reg_equivs (rtx ad, rtx insn) This routine assumes both inputs are already in canonical form. */ rtx -form_sum (rtx x, rtx y) +form_sum (enum machine_mode mode, rtx x, rtx y) { rtx tem; - enum machine_mode mode = GET_MODE (x); - - if (mode == VOIDmode) - mode = GET_MODE (y); - if (mode == VOIDmode) - mode = Pmode; + gcc_assert (GET_MODE (x) == mode || GET_MODE (x) == VOIDmode); + gcc_assert (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode); if (CONST_INT_P (x)) return plus_constant (y, INTVAL (x)); @@ -5338,12 +5356,12 @@ form_sum (rtx x, rtx y) tem = x, x = y, y = tem; if (GET_CODE (x) == PLUS && CONSTANT_P (XEXP (x, 1))) - return form_sum (XEXP (x, 0), form_sum (XEXP (x, 1), y)); + return form_sum (mode, XEXP (x, 0), form_sum (mode, XEXP (x, 1), y)); /* Note that if the operands of Y are specified in the opposite order in the recursive calls below, infinite recursion will occur. */ if (GET_CODE (y) == PLUS && CONSTANT_P (XEXP (y, 1))) - return form_sum (form_sum (x, XEXP (y, 0)), XEXP (y, 1)); + return form_sum (mode, form_sum (mode, x, XEXP (y, 0)), XEXP (y, 1)); /* If both constant, encapsulate sum. Otherwise, just form sum. A constant will have been placed second. */ @@ -5410,9 +5428,9 @@ subst_indexed_address (rtx addr) /* Compute the sum. */ if (op2 != 0) - op1 = form_sum (op1, op2); + op1 = form_sum (GET_MODE (addr), op1, op2); if (op1 != 0) - op0 = form_sum (op0, op1); + op0 = form_sum (GET_MODE (addr), op0, op1); return op0; } @@ -5812,7 +5830,8 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, rtx equiv = (MEM_P (XEXP (x, 0)) ? XEXP (x, 0) : reg_equiv_mem[regno]); - int icode = (int) optab_handler (add_optab, Pmode)->insn_code; + int icode + = (int) optab_handler (add_optab, GET_MODE (x))->insn_code; if (insn && NONJUMP_INSN_P (insn) && equiv && memory_operand (equiv, GET_MODE (equiv)) #ifdef HAVE_cc0 @@ -5820,9 +5839,9 @@ find_reloads_address_1 (enum machine_mode mode, rtx x, int context, #endif && ! (icode != CODE_FOR_nothing && ((*insn_data[icode].operand[0].predicate) - (equiv, Pmode)) + (equiv, GET_MODE (x))) && ((*insn_data[icode].operand[1].predicate) - (equiv, Pmode)))) + (equiv, GET_MODE (x))))) { /* We use the original pseudo for loc, so that emit_reload_insns() knows which pseudo this @@ -6180,8 +6199,9 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, the address, there is nothing further to do. */ if (reloaded == 0 && reg_equiv_mem[regno] != 0 - && !strict_memory_address_p (GET_MODE (x), - XEXP (reg_equiv_mem[regno], 0))) + && !strict_memory_address_addr_space_p + (GET_MODE (x), XEXP (reg_equiv_mem[regno], 0), + MEM_ADDR_SPACE (reg_equiv_mem[regno]))) push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0, base_reg_class (GET_MODE (tem), MEM, SCRATCH), GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0, diff --git a/gcc/reload.h b/gcc/reload.h index 3789680f7ca..5d8375b9589 100644 --- a/gcc/reload.h +++ b/gcc/reload.h @@ -289,7 +289,7 @@ extern int find_reloads (rtx, int, int, int, short *); address, namely: sum constant integers, surround the sum of two constants with a CONST, put the constant as the second operand, and group the constant on the outermost sum. */ -extern rtx form_sum (rtx, rtx); +extern rtx form_sum (enum machine_mode, rtx, rtx); /* Substitute into the current INSN the registers into which we have reloaded the things that need reloading. */ diff --git a/gcc/reload1.c b/gcc/reload1.c index e9a0aba83bc..ce049220608 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -1000,8 +1000,9 @@ reload (rtx first, int global) rtx x = eliminate_regs (reg_equiv_memory_loc[i], VOIDmode, NULL_RTX); - if (strict_memory_address_p (GET_MODE (regno_reg_rtx[i]), - XEXP (x, 0))) + if (strict_memory_address_addr_space_p + (GET_MODE (regno_reg_rtx[i]), XEXP (x, 0), + MEM_ADDR_SPACE (x))) reg_equiv_mem[i] = x, reg_equiv_address[i] = 0; else if (CONSTANT_P (XEXP (x, 0)) || (REG_P (XEXP (x, 0)) @@ -2657,7 +2658,7 @@ eliminate_regs_1 (rtx x, enum machine_mode mem_mode, rtx insn, && reg_equiv_constant[REGNO (new0)] != 0) new0 = reg_equiv_constant[REGNO (new0)]; - new_rtx = form_sum (new0, new1); + new_rtx = form_sum (GET_MODE (x), new0, new1); /* As above, if we are not inside a MEM we do not want to turn a PLUS into something else. We might try to do so here diff --git a/gcc/rtl.c b/gcc/rtl.c index aefbbf347d9..58867aec7cc 100644 --- a/gcc/rtl.c +++ b/gcc/rtl.c @@ -385,6 +385,10 @@ rtx_equal_p_cb (const_rtx x, const_rtx y, rtx_equal_p_callback_function cb) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + /* Some RTL can be compared nonrecursively. */ switch (code) { @@ -501,6 +505,10 @@ rtx_equal_p (const_rtx x, const_rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + /* Some RTL can be compared nonrecursively. */ switch (code) { diff --git a/gcc/rtl.h b/gcc/rtl.h index 0f7044e5e1a..7cf3a7fe2e0 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -146,6 +146,7 @@ typedef struct GTY(()) mem_attrs rtx size; /* Size in bytes, as a CONST_INT. */ alias_set_type alias; /* Memory alias set. */ unsigned int align; /* Alignment of MEM in bits. */ + unsigned char addrspace; /* Address space (0 for generic). */ } mem_attrs; /* Structure used to describe the attributes of a REG in similar way as @@ -1122,7 +1123,7 @@ rhs_regno (const_rtx x) extern void init_rtlanal (void); extern int rtx_cost (rtx, enum rtx_code, bool); -extern int address_cost (rtx, enum machine_mode, bool); +extern int address_cost (rtx, enum machine_mode, addr_space_t, bool); extern unsigned int subreg_lsb (const_rtx); extern unsigned int subreg_lsb_1 (enum machine_mode, enum machine_mode, unsigned int); @@ -1269,6 +1270,10 @@ do { \ RTX that is always a CONST_INT. */ #define MEM_OFFSET(RTX) (MEM_ATTRS (RTX) == 0 ? 0 : MEM_ATTRS (RTX)->offset) +/* For a MEM rtx, the address space. */ +#define MEM_ADDR_SPACE(RTX) (MEM_ATTRS (RTX) == 0 ? ADDR_SPACE_GENERIC \ + : MEM_ATTRS (RTX)->addrspace) + /* For a MEM rtx, the size in bytes of the MEM, if known, as an RTX that is always a CONST_INT. */ #define MEM_SIZE(RTX) \ @@ -1608,7 +1613,10 @@ extern unsigned int subreg_highpart_offset (enum machine_mode, enum machine_mode); extern int byte_lowpart_offset (enum machine_mode, enum machine_mode); extern rtx make_safe_from (rtx, rtx); -extern rtx convert_memory_address (enum machine_mode, rtx); +extern rtx convert_memory_address_addr_space (enum machine_mode, rtx, + addr_space_t); +#define convert_memory_address(to_mode,x) \ + convert_memory_address_addr_space ((to_mode), (x), ADDR_SPACE_GENERIC) extern rtx get_insns (void); extern const char *get_insn_name (int); extern rtx get_last_insn (void); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 7a734eb66e5..d14bbe58bf7 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3603,13 +3603,13 @@ rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed) be returned. */ int -address_cost (rtx x, enum machine_mode mode, bool speed) +address_cost (rtx x, enum machine_mode mode, addr_space_t as, bool speed) { /* We may be asked for cost of various unusual addresses, such as operands of push instruction. It is not worthwhile to complicate writing of the target hook by such cases. */ - if (!memory_address_p (mode, x)) + if (!memory_address_addr_space_p (mode, x, as)) return 1000; return targetm.address_cost (x, speed); @@ -3748,7 +3748,11 @@ nonzero_bits1 (const_rtx x, enum machine_mode mode, const_rtx known_x, #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) /* If pointers extend unsigned and this is a pointer in Pmode, say that all the bits above ptr_mode are known to be zero. */ - if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode + /* As we do not know which address space the pointer is refering to, + we can do this only if the target does not support different pointer + or address modes depending on the address space. */ + if (target_default_pointer_address_modes_p () + && POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && REG_POINTER (x)) nonzero &= GET_MODE_MASK (ptr_mode); #endif @@ -3985,7 +3989,11 @@ nonzero_bits1 (const_rtx x, enum machine_mode mode, const_rtx known_x, /* If pointers extend unsigned and this is an addition or subtraction to a pointer in Pmode, all the bits above ptr_mode are known to be zero. */ - if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode + /* As we do not know which address space the pointer is refering to, + we can do this only if the target does not support different pointer + or address modes depending on the address space. */ + if (target_default_pointer_address_modes_p () + && POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode && (code == PLUS || code == MINUS) && REG_P (XEXP (x, 0)) && REG_POINTER (XEXP (x, 0))) nonzero &= GET_MODE_MASK (ptr_mode); @@ -4259,8 +4267,12 @@ num_sign_bit_copies1 (const_rtx x, enum machine_mode mode, const_rtx known_x, #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) /* If pointers extend signed and this is a pointer in Pmode, say that all the bits above ptr_mode are known to be sign bit copies. */ - if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode - && REG_POINTER (x)) + /* As we do not know which address space the pointer is refering to, + we can do this only if the target does not support different pointer + or address modes depending on the address space. */ + if (target_default_pointer_address_modes_p () + && ! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode + && mode == Pmode && REG_POINTER (x)) return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1; #endif @@ -4456,7 +4468,11 @@ num_sign_bit_copies1 (const_rtx x, enum machine_mode mode, const_rtx known_x, /* If pointers extend signed and this is an addition or subtraction to a pointer in Pmode, all the bits above ptr_mode are known to be sign bit copies. */ - if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode + /* As we do not know which address space the pointer is refering to, + we can do this only if the target does not support different pointer + or address modes depending on the address space. */ + if (target_default_pointer_address_modes_p () + && ! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && (code == PLUS || code == MINUS) && REG_P (XEXP (x, 0)) && REG_POINTER (XEXP (x, 0))) result = MAX ((int) (GET_MODE_BITSIZE (Pmode) diff --git a/gcc/rtlhooks.c b/gcc/rtlhooks.c index 4cf757d829d..a64c0674dc8 100644 --- a/gcc/rtlhooks.c +++ b/gcc/rtlhooks.c @@ -153,7 +153,8 @@ gen_lowpart_if_possible (enum machine_mode mode, rtx x) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); new_rtx = adjust_address_nv (x, mode, offset); - if (! memory_address_p (mode, XEXP (new_rtx, 0))) + if (! memory_address_addr_space_p (mode, XEXP (new_rtx, 0), + MEM_ADDR_SPACE (x))) return 0; return new_rtx; diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c index 1fd484d97aa..1f1a76c1090 100644 --- a/gcc/sched-deps.c +++ b/gcc/sched-deps.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "cselib.h" #include "ira.h" +#include "target.h" #ifdef INSN_SCHEDULING @@ -2281,8 +2282,11 @@ sched_analyze_1 (struct deps *deps, rtx x, rtx insn) if (sched_deps_info->use_cselib) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest)); + t = shallow_copy_rtx (dest); - cselib_lookup (XEXP (t, 0), Pmode, 1); + cselib_lookup (XEXP (t, 0), address_mode, 1); XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0)); } t = canon_rtx (t); @@ -2435,8 +2439,11 @@ sched_analyze_2 (struct deps *deps, rtx x, rtx insn) if (sched_deps_info->use_cselib) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (t)); + t = shallow_copy_rtx (t); - cselib_lookup (XEXP (t, 0), Pmode, 1); + cselib_lookup (XEXP (t, 0), address_mode, 1); XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0)); } diff --git a/gcc/sel-sched-dump.c b/gcc/sel-sched-dump.c index 5fce7cf6b9e..b307f52b841 100644 --- a/gcc/sel-sched-dump.c +++ b/gcc/sel-sched-dump.c @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "basic-block.h" #include "cselib.h" +#include "target.h" #ifdef INSN_SCHEDULING #include "sel-sched-ir.h" @@ -931,10 +932,13 @@ rtx debug_mem_addr_value (rtx x) { rtx t, addr; + enum machine_mode address_mode; gcc_assert (MEM_P (x)); + address_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + t = shallow_copy_rtx (x); - if (cselib_lookup (XEXP (t, 0), Pmode, 0)) + if (cselib_lookup (XEXP (t, 0), address_mode, 0)) XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0)); t = canon_rtx (t); diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 926615ec86f..39a791d9890 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1012,7 +1012,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) return rtl_hooks.gen_lowpart_no_emit (mode, op); #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) - if (! POINTERS_EXTEND_UNSIGNED + /* As we do not know which address space the pointer is refering to, + we can do this only if the target does not support different pointer + or address modes depending on the address space. */ + if (target_default_pointer_address_modes_p () + && ! POINTERS_EXTEND_UNSIGNED && mode == Pmode && GET_MODE (op) == ptr_mode && (CONSTANT_P (op) || (GET_CODE (op) == SUBREG @@ -1034,7 +1038,11 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op) return rtl_hooks.gen_lowpart_no_emit (mode, op); #if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend) - if (POINTERS_EXTEND_UNSIGNED > 0 + /* As we do not know which address space the pointer is refering to, + we can do this only if the target does not support different pointer + or address modes depending on the address space. */ + if (target_default_pointer_address_modes_p () + && POINTERS_EXTEND_UNSIGNED > 0 && mode == Pmode && GET_MODE (op) == ptr_mode && (CONSTANT_P (op) || (GET_CODE (op) == SUBREG diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index d070b10e3dc..e512db83979 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -52,9 +52,9 @@ unsigned int maximum_field_alignment = TARGET_DEFAULT_PACK_STRUCT * BITS_PER_UNI /* ... and its original value in bytes, specified via -fpack-struct=<value>. */ unsigned int initial_max_fld_align = TARGET_DEFAULT_PACK_STRUCT; -/* Nonzero if all REFERENCE_TYPEs are internal and hence should be - allocated in Pmode, not ptr_mode. Set only by internal_reference_types - called only by a front end. */ +/* Nonzero if all REFERENCE_TYPEs are internal and hence should be allocated + in the address spaces' address_mode, not pointer_mode. Set only by + internal_reference_types called only by a front end. */ static int reference_types_internal = 0; static tree self_referential_size (tree); @@ -71,8 +71,8 @@ extern void debug_rli (record_layout_info); static GTY(()) tree pending_sizes; -/* Show that REFERENCE_TYPES are internal and should be Pmode. Called only - by front end. */ +/* Show that REFERENCE_TYPES are internal and should use address_mode. + Called only by front end. */ void internal_reference_types (void) @@ -1917,6 +1917,7 @@ layout_type (tree type) /* A pointer might be MODE_PARTIAL_INT, but ptrdiff_t must be integral. */ SET_TYPE_MODE (type, mode_for_size (POINTER_SIZE, MODE_INT, 0)); + TYPE_PRECISION (type) = POINTER_SIZE; break; case FUNCTION_TYPE: @@ -1932,16 +1933,17 @@ layout_type (tree type) case POINTER_TYPE: case REFERENCE_TYPE: { - enum machine_mode mode = ((TREE_CODE (type) == REFERENCE_TYPE - && reference_types_internal) - ? Pmode : TYPE_MODE (type)); - - int nbits = GET_MODE_BITSIZE (mode); + enum machine_mode mode = TYPE_MODE (type); + if (TREE_CODE (type) == REFERENCE_TYPE && reference_types_internal) + { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); + mode = targetm.addr_space.address_mode (as); + } - TYPE_SIZE (type) = bitsize_int (nbits); + TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (mode)); TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (mode)); TYPE_UNSIGNED (type) = 1; - TYPE_PRECISION (type) = nbits; + TYPE_PRECISION (type) = GET_MODE_BITSIZE (mode); } break; diff --git a/gcc/target-def.h b/gcc/target-def.h index 96b43eb9a9d..547a5fb89f8 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -471,6 +471,48 @@ #define TARGET_VALID_POINTER_MODE default_valid_pointer_mode #endif +#ifndef TARGET_ADDR_SPACE_POINTER_MODE +#define TARGET_ADDR_SPACE_POINTER_MODE default_addr_space_pointer_mode +#endif + +#ifndef TARGET_ADDR_SPACE_ADDRESS_MODE +#define TARGET_ADDR_SPACE_ADDRESS_MODE default_addr_space_address_mode +#endif + +#ifndef TARGET_ADDR_SPACE_VALID_POINTER_MODE +#define TARGET_ADDR_SPACE_VALID_POINTER_MODE \ + default_addr_space_valid_pointer_mode +#endif + +#ifndef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ + default_addr_space_legitimate_address_p +#endif + +#ifndef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS +#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS \ + default_addr_space_legitimize_address +#endif + +#ifndef TARGET_ADDR_SPACE_SUBSET_P +#define TARGET_ADDR_SPACE_SUBSET_P default_addr_space_subset_p +#endif + +#ifndef TARGET_ADDR_SPACE_CONVERT +#define TARGET_ADDR_SPACE_CONVERT default_addr_space_convert +#endif + +#define TARGET_ADDR_SPACE_HOOKS \ + { \ + TARGET_ADDR_SPACE_POINTER_MODE, \ + TARGET_ADDR_SPACE_ADDRESS_MODE, \ + TARGET_ADDR_SPACE_VALID_POINTER_MODE, \ + TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P, \ + TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS, \ + TARGET_ADDR_SPACE_SUBSET_P, \ + TARGET_ADDR_SPACE_CONVERT, \ + } + #ifndef TARGET_SCALAR_MODE_SUPPORTED_P #define TARGET_SCALAR_MODE_SUPPORTED_P default_scalar_mode_supported_p #endif @@ -913,6 +955,7 @@ TARGET_MIN_DIVISIONS_FOR_RECIP_MUL, \ TARGET_MODE_REP_EXTENDED, \ TARGET_VALID_POINTER_MODE, \ + TARGET_ADDR_SPACE_HOOKS, \ TARGET_SCALAR_MODE_SUPPORTED_P, \ TARGET_VECTOR_MODE_SUPPORTED_P, \ TARGET_RTX_COSTS, \ diff --git a/gcc/target.h b/gcc/target.h index 2c7fa4a6aa9..a243bcd3bfb 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -68,6 +68,12 @@ typedef int (* print_switch_fn_type) (print_switch_type, const char *); /* An example implementation for ELF targets. Defined in varasm.c */ extern int elf_record_gcc_switches (print_switch_type type, const char *); +/* Some places still assume that all pointer or address modes are the + standard Pmode and ptr_mode. These optimizations become invalid if + the target actually supports multiple different modes. For now, + we disable such optimizations on such targets, using this function. */ +extern bool target_default_pointer_address_modes_p (void); + struct stdarg_info; struct spec_info_def; @@ -694,6 +700,36 @@ struct gcc_target /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))). */ bool (* valid_pointer_mode) (enum machine_mode mode); + /* Support for named address spaces. */ + struct addr_space { + /* MODE to use for a pointer into another address space. */ + enum machine_mode (* pointer_mode) (addr_space_t); + + /* MODE to use for an address in another address space. */ + enum machine_mode (* address_mode) (addr_space_t); + + /* True if MODE is valid for a pointer in __attribute__((mode("MODE"))) + in another address space. */ + bool (* valid_pointer_mode) (enum machine_mode, addr_space_t); + + /* True if an address is a valid memory address to a given named address + space for a given mode. */ + bool (* legitimate_address_p) (enum machine_mode, rtx, bool, addr_space_t); + + /* Return an updated address to convert an invalid pointer to a named + address space to a valid one. If NULL_RTX is returned use machine + independent methods to make the address valid. */ + rtx (* legitimize_address) (rtx, rtx, enum machine_mode, addr_space_t); + + /* True if one named address space is a subset of another named address. */ + bool (* subset_p) (addr_space_t, addr_space_t); + + /* Function to convert an rtl expression from one address space to + another. */ + rtx (* convert) (rtx, tree, tree); + + } addr_space; + /* True if MODE is valid for the target. By "valid", we mean able to be manipulated in non-trivial ways. In particular, this means all the arithmetic is supported. */ diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 8614a4ff669..35ed9eed4a6 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -831,6 +831,107 @@ default_builtin_support_vector_misalignment (enum machine_mode mode, return false; } +/* Determine whether or not a pointer mode is valid. Assume defaults + of ptr_mode or Pmode - can be overridden. */ +bool +default_valid_pointer_mode (enum machine_mode mode) +{ + return (mode == ptr_mode || mode == Pmode); +} + +/* Return the mode for a pointer to a given ADDRSPACE, defaulting to ptr_mode + for the generic address space only. */ + +enum machine_mode +default_addr_space_pointer_mode (addr_space_t addrspace ATTRIBUTE_UNUSED) +{ + gcc_assert (ADDR_SPACE_GENERIC_P (addrspace)); + return ptr_mode; +} + +/* Return the mode for an address in a given ADDRSPACE, defaulting to Pmode + for the generic address space only. */ + +enum machine_mode +default_addr_space_address_mode (addr_space_t addrspace ATTRIBUTE_UNUSED) +{ + gcc_assert (ADDR_SPACE_GENERIC_P (addrspace)); + return Pmode; +} + +/* Named address space version of valid_pointer_mode. */ + +bool +default_addr_space_valid_pointer_mode (enum machine_mode mode, addr_space_t as) +{ + if (!ADDR_SPACE_GENERIC_P (as)) + return (mode == targetm.addr_space.pointer_mode (as) + || mode == targetm.addr_space.address_mode (as)); + + return targetm.valid_pointer_mode (mode); +} + +/* Some places still assume that all pointer or address modes are the + standard Pmode and ptr_mode. These optimizations become invalid if + the target actually supports multiple different modes. For now, + we disable such optimizations on such targets, using this function. */ + +bool +target_default_pointer_address_modes_p (void) +{ + if (targetm.addr_space.address_mode != default_addr_space_address_mode) + return false; + if (targetm.addr_space.pointer_mode != default_addr_space_pointer_mode) + return false; + + return true; +} + +/* Named address space version of legitimate_address_p. */ + +bool +default_addr_space_legitimate_address_p (enum machine_mode mode, rtx mem, + bool strict, addr_space_t as) +{ + if (!ADDR_SPACE_GENERIC_P (as)) + gcc_unreachable (); + + return targetm.legitimate_address_p (mode, mem, strict); +} + +/* Named address space version of LEGITIMIZE_ADDRESS. */ + +rtx +default_addr_space_legitimize_address (rtx x, rtx oldx, + enum machine_mode mode, addr_space_t as) +{ + if (!ADDR_SPACE_GENERIC_P (as)) + return x; + + return targetm.legitimize_address (x, oldx, mode); +} + +/* The default hook for determining if one named address space is a subset of + another and to return which address space to use as the common address + space. */ + +bool +default_addr_space_subset_p (addr_space_t subset, addr_space_t superset) +{ + return (subset == superset); +} + +/* The default hook for TARGET_ADDR_SPACE_CONVERT. This hook should never be + called for targets with only a generic address space. */ + +rtx +default_addr_space_convert (rtx op ATTRIBUTE_UNUSED, + tree from_type ATTRIBUTE_UNUSED, + tree to_type ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + bool default_hard_regno_scratch_ok (unsigned int regno ATTRIBUTE_UNUSED) { diff --git a/gcc/targhooks.h b/gcc/targhooks.h index 3680b9bb63f..cbbbee89d2e 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -119,4 +119,15 @@ extern bool default_hard_regno_scratch_ok (unsigned int); extern bool default_target_option_valid_attribute_p (tree, tree, tree, int); extern bool default_target_option_pragma_parse (tree, tree); extern bool default_target_can_inline_p (tree, tree); +extern bool default_valid_pointer_mode (enum machine_mode); +extern enum machine_mode default_addr_space_pointer_mode (addr_space_t); +extern enum machine_mode default_addr_space_address_mode (addr_space_t); +extern bool default_addr_space_valid_pointer_mode (enum machine_mode, + addr_space_t); +extern bool default_addr_space_legitimate_address_p (enum machine_mode, rtx, + bool, addr_space_t); +extern rtx default_addr_space_legitimize_address (rtx, rtx, enum machine_mode, + addr_space_t); +extern bool default_addr_space_subset_p (addr_space_t, addr_space_t); +extern rtx default_addr_space_convert (rtx, tree, tree); extern unsigned int default_case_values_threshold (void); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 178af56dde0..9673d28c227 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,109 @@ +2009-10-26 Ben Elliston <bje@au.ibm.com> + Michael Meissner <meissner@linux.vnet.ibm.com> + Ulrich Weigand <uweigand@de.ibm.com> + + * gcc.target/spu/ea/ea.exp: New file. + * gcc.target/spu/ea/cache1.c: Likewise. + * gcc.target/spu/ea/cast1.c: Likewise. + * gcc.target/spu/ea/cast2.c: Likewise. + * gcc.target/spu/ea/compile1.c: Likewise. + * gcc.target/spu/ea/compile2.c: Likewise. + * gcc.target/spu/ea/cppdefine.c: Likewise. + * gcc.target/spu/ea/errors1.c: Likewise. + * gcc.target/spu/ea/errors2.c: Likewise. + * gcc.target/spu/ea/execute1.c: Likewise. + * gcc.target/spu/ea/execute2.c: Likewise. + * gcc.target/spu/ea/execute3.c: Likewise. + * gcc.target/spu/ea/ops1.c: Likewise. + * gcc.target/spu/ea/ops2.c: Likewise. + * gcc.target/spu/ea/options1.c: Likewise. + * gcc.target/spu/ea/test-sizes.c: Likewise. + +2009-10-26 Jakub Jelinek <jakub@redhat.com> + + PR bootstrap/41345 + * gcc.dg/pr41345.c: New test. + + PR debug/41828 + * g++.dg/debug/dwarf2/anonname1.C: New test. + +2009-10-26 Jason Merrill <jason@redhat.com> + + PR c++/38796 + * g++.dg/cpp0x/defaulted15.C: New. + * g++.dg/cpp0x/defaulted16.C: New. + +2009-10-26 Dodji Seketeli <dodji@redhat.com> + + PR c++/41785 + * gcc/testsuite/g++.dg/cpp0x/variadic96.C: New test. + +2009-10-26 Nick Clifton <nickc@redhat.com> + + * lib/target-supports.exp (check_profiling_available): + Profiling is not, currently, available for the RX port. + (check_effective_target_hard_float): Add support for RX + target. + * gcc.target/rx: New directory. + * gcc.target/rx/builtins.c: New test file. + * gcc.target/rx/interrupts.c: New test file. + * gcc.target/rx/rx-abi-function-tests.c: New test file. + * gcc.target/rx/zero-width-bitfield.c: New test file. + * gcc.target/rx/i272091.c: New test file. + * gcc.target/rx/packed-struct.c: New test file. + * gcc.target/rx/rx.exp: New file: Drives RX tests. + +2009-10-26 Andrew Pinski <pinskia@gcc.gnu.org> + + * gcc.dg/lto/20091014-1_0.c: Replace -shared with -r -nostlib. + * gcc.dg/lto/20091016-1_0.c: Likewise. + * gcc.dg/lto/20090206-1_0.c: Likewise. + * gcc.dg/lto/20081120-1_0.c: Likewise. + * gcc.dg/lto/20081120-2_0.c: Likewise. + * gcc.dg/lto/20090116_0.c: Likewise. + * gcc.dg/lto/20081126_0.c: Likewise. + * gcc.dg/lto/20091013-1_0.c: Likewise. + * gcc.dg/lto/20081212-1_0.c: Likewise. + * gcc.dg/lto/20091015-1_0.c: Likewise. + * gcc.dg/lto/20090126-1_0.c: Likewise. + * gcc.dg/lto/20090126-2_0.c: Likewise. + * gcc.dg/lto/20091020-1_0.c: Likewise. + * gcc.dg/lto/20091020-2_0.c: Likewise. + * gcc.dg/lto/20081204-1_0.c: Likewise. + * gcc.dg/lto/20081204-2_0.c: Likewise. + * gcc.dg/lto/20081224_0.c: Likewise. + * gcc.dg/lto/20090219_0.c: Likewise. + +2009-10-26 Dodji Seketeli <dodji@redhat.com> + + PR c++/41020 + * g++.dg/lookup/extern-c-redecl2.C: New test. + * g++.dg/lookup/extern-c-redecl3.C: Likewise. + * g++.dg/lookup/extern-c-redecl4.C: Likewise. + * g++.dg/lookup/extern-c-redecl5.C: Likewise. + +2009-10-26 Michael Matz <matz@suse.de> + + PR tree-optimization/41783 + * gcc.dg/pr41783.c: New test. + * gcc.dg/tree-ssa/ssa-pre-23.c: Adjust. + * gcc.dg/tree-ssa/ssa-pre-24.c: Don't xfail anymore. + * gcc.dg/tree-ssa/ssa-pre-27.c: New test. + +2009-10-26 Janus Weil <janus@gcc.gnu.org> + + PR fortran/41714 + * gfortran.dg/class_allocate_4.f03: New test. + +2009-10-24 Adam Nemet <anemet@caviumnetworks.com> + + * gcc.target/mips/mult-1.c: New test. + +2009-10-24 Janus Weil <janus@gcc.gnu.org> + + PR fortran/41784 + * gfortran.dg/extends_8.f03: New test. + 2009-10-24 Eric Botcazou <ebotcazou@adacore.com> * gnat.dg/specs/pack4.ads: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted15.C b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C new file mode 100644 index 00000000000..092b5605901 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted15.C @@ -0,0 +1,43 @@ +// PR c++/38796 +// { dg-options -std=c++0x } + +struct A +{ + A (int); + A (const A& = 1) = default; // { dg-error "default argument" } + void operator= (const A&) = default; // { dg-error "defaulted|match" } +}; + +struct B +{ +private: + B() = default; // { dg-error "access" } +}; + +struct C +{ +protected: + ~C() = default; // { dg-error "access" } +}; + +struct D +{ +private: + D& operator= (const D&) = default; // { dg-error "access" } +}; + +struct E +{ + explicit E (const E&) = default; // { dg-error "explicit" } +}; + +struct F +{ + F(F&) = default; // { dg-error "non-const" } +}; + +struct G: public F +{ + // Can't be const because F copy ctor isn't. + G(const G&) = default; // { dg-error "const" } +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted16.C b/gcc/testsuite/g++.dg/cpp0x/defaulted16.C new file mode 100644 index 00000000000..741b43de27d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/defaulted16.C @@ -0,0 +1,13 @@ +// Test that non-inline default causes the function to be defined even if +// it isn't used. + +// { dg-options -std=c++0x } +// { dg-final { scan-assembler "_ZN1AC1Ev" } } + +struct A +{ + A(); +}; + +A::A() = default; + diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic96.C b/gcc/testsuite/g++.dg/cpp0x/variadic96.C new file mode 100644 index 00000000000..d4709d074b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/variadic96.C @@ -0,0 +1,26 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/41785 +// { dg-options -std=c++0x } + +struct a {}; + +template < typename T, typename ENCLOSING > +struct base; + +template < typename... T > +struct derived + : public base< T, derived< T... > >... +{}; + +template < typename... T> +struct base< a, derived< T... > > +{ + typedef derived< T... > + Derived; +}; + +int main() +{ + derived< a > instance; +} + diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C b/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C new file mode 100644 index 00000000000..dcd2d8d5660 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C @@ -0,0 +1,18 @@ +// PR debug/41828 +// { dg-do compile } +// { dg-options "-gdwarf-2 -dA" } +// { dg-final { scan-assembler-not "<anonymous" } } +// { dg-final { scan-assembler-not "\._\[0-9\]" } } +// { dg-final { scan-assembler-not "\$_\[0-9\]" } } +// { dg-final { scan-assembler-not "__anon_" } } + +struct +{ + union + { + struct + { + enum { a, b, c } x; + } s; + }; +} x; diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl2.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl2.C new file mode 100644 index 00000000000..055148f3841 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl2.C @@ -0,0 +1,21 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin PR c++/41020 +// { dg-do compile } + +extern "C" +{ + int fork (void); +} + +class frok +{ + int this_errno; + friend int fork (void); +}; + +extern "C" int +fork (void) +{ + frok grouped; + return grouped.this_errno; +} diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl3.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl3.C new file mode 100644 index 00000000000..00ff4a966ce --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl3.C @@ -0,0 +1,22 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/41020 +// { dg-do compile } +// { dg-final { scan-assembler-not "call\[\t \]+_Z4forkv" } } +// { dg-final { scan-assembler "call\[\t \]+fork" } } + +extern "C" int fork (void); + +void +foo () +{ + extern int fork (void); + fork (); +} + +extern "C" +int +fork (void) +{ + return 0; +} + diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C new file mode 100644 index 00000000000..9dfa54dad4d --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C @@ -0,0 +1,19 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/41020 + +// Avoid the "-ansi -pedantic" option +// { dg-options "" } +// { dg-do compile } +// { dg-final { scan-assembler "call\[\t \]+_Z4forkv" } } + +class frok +{ + int this_errno; + friend int fork (void); +}; + +void +foo () +{ + fork (); +} diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl5.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl5.C new file mode 100644 index 00000000000..031059f7657 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl5.C @@ -0,0 +1,18 @@ +// Contributed by Dodji Seketeli <dodji@redhat.com> +// Origin: PR c++/41020 +// { dg-do compile } + + +class frok +{ + int this_errno; + friend int fork (void); // { dg-error "previous declaration .*?C++. linkage" } +}; + +extern "C" int +fork (void) // { dg-error "conflicts with new declaration .*?C. linkage" }} +{ + frok grouped; + return grouped.this_errno; +} + diff --git a/gcc/testsuite/gcc.dg/lto/20081120-1_0.c b/gcc/testsuite/gcc.dg/lto/20081120-1_0.c index c35119605d6..e842b37f663 100644 --- a/gcc/testsuite/gcc.dg/lto/20081120-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081120-1_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-flto -shared}} } */ +/* { dg-lto-options {{-flto -r -nostdlib}} } */ extern int stat(void) __asm__("" "stat64"); extern inline int stat(void) { } static void foo(void) { stat(); } diff --git a/gcc/testsuite/gcc.dg/lto/20081120-2_0.c b/gcc/testsuite/gcc.dg/lto/20081120-2_0.c index ff8a9a435f2..19c4ab34784 100644 --- a/gcc/testsuite/gcc.dg/lto/20081120-2_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081120-2_0.c @@ -1,3 +1,3 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fwhopr -shared}} } */ +/* { dg-lto-options {{-fwhopr -r -nostdlib}} } */ void bar(void) {} diff --git a/gcc/testsuite/gcc.dg/lto/20081126_0.c b/gcc/testsuite/gcc.dg/lto/20081126_0.c index 9d0bb14c4cb..9243da96a79 100644 --- a/gcc/testsuite/gcc.dg/lto/20081126_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081126_0.c @@ -1,6 +1,6 @@ /* { dg-lto-do link } */ /* { dg-skip-if "" { ! { i?86-*-* x86_64-*-* } } { "*" } { "" } } */ -/* { dg-lto-options {{-flto -shared}} } */ +/* { dg-lto-options {{-flto -r -nostdlib}} } */ int f(void) { register int ri asm("edi"); diff --git a/gcc/testsuite/gcc.dg/lto/20081204-1_0.c b/gcc/testsuite/gcc.dg/lto/20081204-1_0.c index 92598085c9a..5952b07b76f 100644 --- a/gcc/testsuite/gcc.dg/lto/20081204-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081204-1_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fwhopr -fPIC -shared}} } */ +/* { dg-lto-options {{-fwhopr -fPIC -r -nostdlib}} } */ /* Tests for the absence during linking of: lto1: error: type of 'i' does not match original declaration */ diff --git a/gcc/testsuite/gcc.dg/lto/20081204-2_0.c b/gcc/testsuite/gcc.dg/lto/20081204-2_0.c index 241ac5d607a..53446050f95 100644 --- a/gcc/testsuite/gcc.dg/lto/20081204-2_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081204-2_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ /* { dg-skip-if "" { ! { i?86-*-* x86_64-*-* } } { "*" } { "" } } */ -/* { dg-lto-options {{-w -flto -fPIC -shared}} } */ +/* { dg-lto-options {{-w -flto -fPIC -r -nostdlib}} } */ register int ri asm("edi"); diff --git a/gcc/testsuite/gcc.dg/lto/20081212-1_0.c b/gcc/testsuite/gcc.dg/lto/20081212-1_0.c index a19bff1bac5..acc00186840 100644 --- a/gcc/testsuite/gcc.dg/lto/20081212-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081212-1_0.c @@ -1,4 +1,4 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-shared}} } */ +/* { dg-lto-options {{-r -nostdlib}} } */ int exported_var = 42; /* { dg-final { scan-symbol "exported_var" } } */ diff --git a/gcc/testsuite/gcc.dg/lto/20081224_0.c b/gcc/testsuite/gcc.dg/lto/20081224_0.c index c146115b086..9c784fe29ff 100644 --- a/gcc/testsuite/gcc.dg/lto/20081224_0.c +++ b/gcc/testsuite/gcc.dg/lto/20081224_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fwhopr -shared -fPIC}} } */ +/* { dg-lto-options {{-fwhopr -r -nostdlib -fPIC}} } */ #include "20081224_0.h" extern struct foo x; diff --git a/gcc/testsuite/gcc.dg/lto/20090116_0.c b/gcc/testsuite/gcc.dg/lto/20090116_0.c index 4b88e4ab3b1..9fd83ca0766 100644 --- a/gcc/testsuite/gcc.dg/lto/20090116_0.c +++ b/gcc/testsuite/gcc.dg/lto/20090116_0.c @@ -1,6 +1,6 @@ /* { dg-lto-do link } */ /* { dg-lto-options {{-O1 -fwhopr -fPIC}} } */ -/* { dg-extra-ld-options {-shared -O0} } */ +/* { dg-extra-ld-options {-r -nostdlib -O0} } */ int foo(void) { int ret, i; diff --git a/gcc/testsuite/gcc.dg/lto/20090126-1_0.c b/gcc/testsuite/gcc.dg/lto/20090126-1_0.c index 0ed8ea32401..b2a25b2261c 100644 --- a/gcc/testsuite/gcc.dg/lto/20090126-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20090126-1_0.c @@ -1,6 +1,6 @@ /* { dg-lto-do link } */ /* { dg-lto-options {{-O0 -fwhopr}} } */ -/* { dg-extra-ld-options {-shared -O2 -fwhopr} } */ +/* { dg-extra-ld-options {-r -nostdlib -O2 -fwhopr} } */ int main(int argc, char **argv) { return 0; diff --git a/gcc/testsuite/gcc.dg/lto/20090126-2_0.c b/gcc/testsuite/gcc.dg/lto/20090126-2_0.c index 64e63853250..a366c183873 100644 --- a/gcc/testsuite/gcc.dg/lto/20090126-2_0.c +++ b/gcc/testsuite/gcc.dg/lto/20090126-2_0.c @@ -1,6 +1,6 @@ /* { dg-lto-do link } */ /* { dg-lto-options {{-fPIC -O2 -fwhopr}} } */ -/* { dg-extra-ld-options {-fno-PIC -shared -O2 -fwhopr} } */ +/* { dg-extra-ld-options {-fno-PIC -r -nostdlib -O2 -fwhopr} } */ int main(int argc, char **argv) { return 0; diff --git a/gcc/testsuite/gcc.dg/lto/20090206-1_0.c b/gcc/testsuite/gcc.dg/lto/20090206-1_0.c index 42eaca9d5e2..13cd8861183 100644 --- a/gcc/testsuite/gcc.dg/lto/20090206-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20090206-1_0.c @@ -1,6 +1,6 @@ /* { dg-lto-do link } */ /* { dg-skip-if "" { ! { i?86-*-linux* x86_64-*-linux* } } { "*" } { "" } } */ -/* { dg-lto-options {{-fPIC -shared -fwhopr -msse2}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -fwhopr -msse2}} } */ /* { dg-suppress-ld-options {-fPIC -msse2} } */ typedef short v8hi __attribute__((__vector_size__(16))); diff --git a/gcc/testsuite/gcc.dg/lto/20090219_0.c b/gcc/testsuite/gcc.dg/lto/20090219_0.c index 6229de7aef1..b93dd1fe946 100644 --- a/gcc/testsuite/gcc.dg/lto/20090219_0.c +++ b/gcc/testsuite/gcc.dg/lto/20090219_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-O3 -fwhopr -fPIC -shared}} } */ +/* { dg-lto-options {{-O3 -fwhopr -fPIC -r -nostdlib}} } */ struct Foo { int f1, f2, f3, f4, f5; }; diff --git a/gcc/testsuite/gcc.dg/lto/20091013-1_0.c b/gcc/testsuite/gcc.dg/lto/20091013-1_0.c index e1a7dc86b6b..0fecce04f09 100644 --- a/gcc/testsuite/gcc.dg/lto/20091013-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20091013-1_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fPIC -shared -flto} {-fPIC -shared -O2 -flto}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -flto} {-fPIC -r -nostdlib -O2 -flto}} } */ void * HeapAlloc(void*,unsigned int,unsigned long); diff --git a/gcc/testsuite/gcc.dg/lto/20091014-1_0.c b/gcc/testsuite/gcc.dg/lto/20091014-1_0.c index 241dddbf81f..975214e0430 100644 --- a/gcc/testsuite/gcc.dg/lto/20091014-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20091014-1_0.c @@ -1,4 +1,4 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fPIC -shared -flto}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -flto}} } */ /* Empty file. See PR41173. */ diff --git a/gcc/testsuite/gcc.dg/lto/20091015-1_0.c b/gcc/testsuite/gcc.dg/lto/20091015-1_0.c index f60e7d16a7e..d55ebcf4042 100644 --- a/gcc/testsuite/gcc.dg/lto/20091015-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20091015-1_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fPIC -shared -O2 -flto} {-fPIC -shared -O2 -fwhopr}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -O2 -flto} {-fPIC -r -nostdlib -O2 -fwhopr}} } */ #include "20091015-1_b.h" void diagnostic_initialize (FILE **stream) { *stream = stderr; } diff --git a/gcc/testsuite/gcc.dg/lto/20091016-1_0.c b/gcc/testsuite/gcc.dg/lto/20091016-1_0.c index 942c5c6c0a4..39a04b950bf 100644 --- a/gcc/testsuite/gcc.dg/lto/20091016-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20091016-1_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fPIC -shared -O2 -flto}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -O2 -flto}} } */ typedef struct VEC_constructor_elt_gc { } VEC_constructor_elt_gc; #include "20091016-1_a.h" diff --git a/gcc/testsuite/gcc.dg/lto/20091020-1_0.c b/gcc/testsuite/gcc.dg/lto/20091020-1_0.c index ef61e98b4cc..c9bcb565d96 100644 --- a/gcc/testsuite/gcc.dg/lto/20091020-1_0.c +++ b/gcc/testsuite/gcc.dg/lto/20091020-1_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fPIC -shared -flto}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -flto}} } */ typedef struct { int NumPackStreams; diff --git a/gcc/testsuite/gcc.dg/lto/20091020-2_0.c b/gcc/testsuite/gcc.dg/lto/20091020-2_0.c index 7dcbb2da2ca..fb1a82bb8c6 100644 --- a/gcc/testsuite/gcc.dg/lto/20091020-2_0.c +++ b/gcc/testsuite/gcc.dg/lto/20091020-2_0.c @@ -1,5 +1,5 @@ /* { dg-lto-do link } */ -/* { dg-lto-options {{-fPIC -shared -flto}} } */ +/* { dg-lto-options {{-fPIC -r -nostdlib -flto}} } */ typedef struct { int NumPackStreams; diff --git a/gcc/testsuite/gcc.dg/pr41345.c b/gcc/testsuite/gcc.dg/pr41345.c new file mode 100644 index 00000000000..4b146c0c202 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr41345.c @@ -0,0 +1,14 @@ +/* PR bootstrap/41345 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -g -fcompare-debug" } */ + +void +foo (int *x) +{ + int a; + for (a = 0; a < 2; a++) + if (x[a]) + goto lab; + __builtin_unreachable (); +lab:; +} diff --git a/gcc/testsuite/gcc.dg/pr41783.c b/gcc/testsuite/gcc.dg/pr41783.c new file mode 100644 index 00000000000..cae066be6f4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr41783.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-pre" } */ +int db[100]; +int a_global_var, fact; +int main() +{ + int i,j=0; + do + { + for (i=0; i<100; ++i) + db[i] = i; + fact = a_global_var * i; + } + while (j++ < 100); +} +/* We want to have exactly one load (not two) from a_global_var, + and we want that load to be into a PRE temporary. */ +/* { dg-final { scan-tree-dump-times "= a_global_var;" 1 "pre" } } */ +/* { dg-final { scan-tree-dump "pretmp\[^\\n\]* = a_global_var;" "pre" } } */ +/* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-23.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-23.c index 88c8bb71eb9..6aeb06af9ee 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-23.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-23.c @@ -9,5 +9,5 @@ void foo(int n) global.y += global.x*global.x; } -/* { dg-final { scan-tree-dump "Eliminated: 2" "pre" } } */ +/* { dg-final { scan-tree-dump "Eliminated: 3" "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-24.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-24.c index 6729e2a297e..f91f4af74df 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-24.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-24.c @@ -9,12 +9,7 @@ void foo(int *p, double *x, int n) } /* We should remove the unnecessary insertion of a phi-node and - _not_ end up using the phi result for replacement *p. - The issue here is that when PHI-translating the virtual operands - we assign different value-numbers to the load. Re-running VN - after insertion or trying to be clever and doing this on the - fly during PHI translation would solve this. The next copyprop - fixes this anyway. */ + _not_ end up using the phi result for replacement *p. */ -/* { dg-final { scan-tree-dump-not "= prephitmp" "pre" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-not "= prephitmp" "pre" } } */ /* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.target/mips/mult-1.c b/gcc/testsuite/gcc.target/mips/mult-1.c new file mode 100644 index 00000000000..d82a4778263 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/mult-1.c @@ -0,0 +1,14 @@ +/* For SI->DI widening multiplication we should use DINS to combine the two + halves. */ +/* { dg-options "-O -mgp64 isa_rev>=2" } */ +/* { dg-final { scan-assembler "\tdins\t" } } */ +/* { dg-final { scan-assembler-not "\tdsll\t" } } */ +/* { dg-final { scan-assembler-not "\tdsrl\t" } } */ +/* { dg-final { scan-assembler-not "\tor\t" } } */ + +NOMIPS16 unsigned long long +f (unsigned int i, unsigned int j) +{ + i++; + return (unsigned long long) i * j; +} diff --git a/gcc/testsuite/gcc.target/rx/builtins.c b/gcc/testsuite/gcc.target/rx/builtins.c new file mode 100644 index 00000000000..07448024b44 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/builtins.c @@ -0,0 +1,159 @@ +/* { dg-do run } */ +/* { dg-options "-fno-ipa-cp-clone" } */ + +/* Verify that the RX specific builtin functions work. */ + +/* IPA CP cloning is disabled because the constant propagation + has no understanding of the saturation behaviour of the + __builtin_rx_sat function and so it will optimize away the + saturation addition test. */ + +#include <stdlib.h> +#include <stdio.h> + +/* We need to prevent these functions from being inlined + as otherwise gcc will attempt to optimize away their + arguments and we need the operations on them in order + to correctly set the psw flags. */ + +int saturate_add (int, int) __attribute__((__noinline__)); +int subtract_with_borrow (int, int, int) __attribute__((__noinline__)); +int exchange (int, int) __attribute__((__noinline__)); + +int +half_word_swap (int arg) +{ + return __builtin_rx_revw (arg); +} + +int +saturate_add (int arg1, int arg2) +{ + arg1 += arg2; + return __builtin_rx_sat (arg1); +} + +long +multiply_and_accumulate (long arg1, long arg2, long arg3) +{ + __builtin_rx_mvtaclo (0); + __builtin_rx_mvtachi (0); + + __builtin_rx_mullo (arg1, arg2); + __builtin_rx_mulhi (arg1, arg2); + __builtin_rx_maclo (arg1, arg3); + __builtin_rx_machi (arg1, arg3); + + __builtin_rx_racw (1); + + arg1 = __builtin_rx_mvfachi (); + arg1 += __builtin_rx_mvfacmi (); + + return arg1; +} + +int +rxround (float arg) +{ + return __builtin_rx_round (arg); +} + +/* #define DEBUG 1 */ + +#ifdef DEBUG +#define CHECK_0ARG(func, result) \ + if (func () != result) \ + { \ + printf (#func " () fails: %x not %x\n", func (), result); \ + abort (); \ + } + +#define CHECK_1ARG(func, arg, result) \ + if (func (arg) != result) \ + { \ + printf (#func " (" #arg ") fails: %x not %x\n", func (arg), result); \ + abort (); \ + } + +#define CHECK_2ARG(func, arg1, arg2, result) \ + if (func (arg1, arg2) != result) \ + { \ + printf (#func " (" #arg1 "," #arg2 ") fails: %x not %x\n", \ + func (arg1, arg2), result); \ + abort (); \ + } + +#define CHECK_3ARG(func, arg1, arg2, arg3, result) \ + if (func (arg1, arg2, arg3) != result) \ + { \ + printf (#func " (" #arg1 "," #arg2 "," #arg3 ") fails: %x not %x\n", \ + func (arg1, arg2, arg3), result); \ + abort (); \ + } +#else +#define CHECK_0ARG(func, result) \ + if (func () != result) \ + abort (); + +#define CHECK_1ARG(func, arg, result) \ + if (func (arg) != result) \ + abort (); + +#define CHECK_2ARG(func, arg1, arg2, result) \ + if (func (arg1, arg2) != result) \ + abort (); + +#define CHECK_3ARG(func, arg1, arg2, arg3, result) \ + if (func (arg1, arg2, arg3) != result) \ + abort (); +#endif + +int +main (void) +{ + CHECK_1ARG (half_word_swap, 0x12345678, 0x34127856); + CHECK_2ARG (saturate_add, 0x80000000, 0x80000000, 0x80000000); + CHECK_3ARG (multiply_and_accumulate, 0x111, 0x222, 0x333, 0x70007); + CHECK_1ARG (rxround, 0.5, 1); + return 0; +} + +/* The following builtins are compiled but + not executed because they need OS support. */ + +void +rxbreak (void) +{ + __builtin_rx_brk (); +} + +void +interrupt (void) +{ + __builtin_rx_int (0x12); +} + +int +get_stack_pointer (void) +{ + return __builtin_rx_mvfc (2); +} + +void +set_stack_pointer (int value) +{ + __builtin_rx_mvtc (2, value); + __builtin_rx_mvtc (2, 0x1234); +} + +void +wait (void) +{ + __builtin_rx_wait (); +} + +void +rmpa (int * multiplicand, int * multiplier, int num) +{ + __builtin_rx_rmpa (); +} diff --git a/gcc/testsuite/gcc.target/rx/i272091.c b/gcc/testsuite/gcc.target/rx/i272091.c new file mode 100644 index 00000000000..39da576326f --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/i272091.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */
+/* { dg-options "-msmall-data-limit=100" } */
+
+double a=6.76,b=7.34,c=0.54;
+double x_1= 45.46;
+static double SD_1;
+static double SD_init = 45.54;
+double DD_1;
+double DD_init=769.0;
+
+
+int main()
+{
+ volatile double x,y,z;
+
+ x = 56.76;
+ y = 4.5645;
+
+ z = x + y;
+ z = x - 4.65;
+ z = 4.566 - x;
+ z = x * y;
+ b = 8;
+ c = 34;
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.target/rx/interrupts.c b/gcc/testsuite/gcc.target/rx/interrupts.c new file mode 100644 index 00000000000..910e870f11b --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/interrupts.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-mint-register=3" } */ + +/* Verify that the RX specific function attributes work. */ + +void interrupt (void) __attribute__((__interrupt__)); +void exception (void) __attribute__((__exception__)); +int naked (int) __attribute__((__naked__)); + +int flag = 0; + +/* Fast interrupt handler. Only uses registers marked as fixed + by the -fixed-xxx gcc command line option. Returns via RTFI. */ + +void +interrupt (void) +{ + flag = 1; +} + +/* Exception handler. Must preserve any register it uses, even + call clobbered ones. Returns via RTE. */ + +void +exception (void) +{ + switch (flag) + { + case 0: + flag = -1; + break; + case 1: + case 2: + case 4: + flag = flag - 2; + break; + case 5: + case 7: + case 6: + flag ^= 3; + break; + default: + naked (flag * 2); + break; + } +} + +/* Naked function. The programmer must supply the function's + prologue and epilogue instructions. */ + +int +naked (int arg) +{ + flag = arg; +} + +/* { dg-final { scan-assembler "rtfi" } } */ +/* { dg-final { scan-assembler "rte" } } */ diff --git a/gcc/testsuite/gcc.target/rx/packed-struct.c b/gcc/testsuite/gcc.target/rx/packed-struct.c new file mode 100644 index 00000000000..8c2a4345b82 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/packed-struct.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ + +struct unpacked +{ + int i; + char c; +}; + +#pragma pack(1) + +struct packed +{ + int i; + char c; +}; + +struct packed_contains_unpacked +{ + char c; + struct unpacked uuuu; /* This should generate an error message. */ +}; /* { dg-error "unpacked structure/union inside a packed struct" "XFAILed until patch for generic GCC structure layout code is accepted" { xfail rx-*-* } } */ + +union contains_unpacked +{ + char c; + struct unpacked uuuu; /* This should not. */ +}; + +struct packed_contains_packed +{ + char c; + struct packed ppppp; /* This should not. */ +}; + +#pragma pack() + +struct unpacked_contains_packed +{ + char c; + struct packed p; +}; + +struct unpacked_contains_unpacked +{ + char c; + struct unpacked u; +}; + + +int s1 = sizeof (struct unpacked); +int s2 = sizeof (struct packed); +int s3 = sizeof (struct packed_contains_unpacked); +int s4 = sizeof (struct packed_contains_packed); +int s5 = sizeof (struct unpacked_contains_packed); +int s6 = sizeof (struct unpacked_contains_unpacked); diff --git a/gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c b/gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c new file mode 100644 index 00000000000..0c4ec3f6b05 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c @@ -0,0 +1,159 @@ +/* { dg-do run } */ +/* { dg-options "-msim" } */ +/* Note: The -msim abiove is actually there to override the default + options which include -ansi -pendantic and -Wlong-long... */ + +extern int printf (const char *, ...); +extern void exit (int); +extern void abort (void); + +extern signed long _COM_CONVf32s (float); +extern unsigned long _COM_CONVf32u (float); +extern float _COM_CONV32sf (signed long); +extern float _COM_CONV32uf (unsigned long); +extern float _COM_ADDf (float, float); +extern float _COM_SUBf (float, float); +extern float _COM_MULf (float, float); +extern float _COM_DIVf (float, float); +extern int _COM_CMPLTf (float, float); + +extern long long _COM_MUL64 (long long, long long); +extern signed long long _COM_DIV64s (long long, long long); +extern unsigned long long _COM_DIV64u (unsigned long long, unsigned long long); +extern long long _COM_SHLL64 (long long, int); +extern long long _COM_SHLR64 (long long, int); +extern long long _COM_SHAR64 (long long, int); +extern signed long long _COM_CONVf64s (float); +extern unsigned long long _COM_CONVf64u (float); +extern signed long long _COM_CONVd64s (double); +extern unsigned long long _COM_CONVd64u (double); +extern float _COM_CONV64sf (signed long long); +extern float _COM_CONV64uf (unsigned long long); +extern double _COM_CONV64sd (signed long long); +extern double _COM_CONV64ud (unsigned long long); +extern signed long long _COM_MOD64s (long long, long long); +extern unsigned long long _COM_MOD64u (unsigned long long, unsigned long long); +extern int _COM_CMPLT64s (long long, long long); +extern int _COM_CMPLT64u (unsigned long long, unsigned long long); +extern int _COM_CMPGT64s (long long, long long); +extern int _COM_CMPGT64u (unsigned long long, unsigned long long); +extern int _COM_CMPLE64s (long long, long long); +extern int _COM_CMPLE64u (unsigned long long, unsigned long long); +extern int _COM_CMPGE64s (long long, long long); +extern int _COM_CMPGE64u (unsigned long long, unsigned long long); +extern int _COM_CMPEQ64 (long long, long long); +extern int _COM_CMPNE64 (long long, long long); + +extern double _COM_ADDd (double, double); +extern double _COM_SUBd (double, double); +extern double _COM_MULd (double, double); +extern double _COM_DIVd (double, double); +extern signed long _COM_CONVd32s (double); +extern unsigned long _COM_CONVd32u (double); +extern double _COM_CONV32sd (signed long); +extern double _COM_CONV32ud (unsigned long); +extern double _COM_CONVfd (float); +extern float _COM_CONVdf (double); +extern double _COM_NEGd (double); + + +/* #define DEBUG 1 */ + +#ifdef DEBUG +# define TEST1(func,arg1,result) if (func (arg1) != result) printf ("fail: " #func " (" #arg1 ") returns %x rather than " #result "\n", func (arg1)) +# define TEST2(func,arg1,arg2,result) if (func (arg1, arg2) != result) printf ("fail: " #func " (" #arg1 ", " #arg2 ") returns %x rather than " #result "\n", func (arg1, arg2)) +# define TEST_CMP(func, low_arg, high_arg, lt_result, eq_result, gt_result) \ + do \ + { \ + int res; \ + \ + if ((res = func (low_arg, high_arg)) != lt_result) printf ("fail: " #func " (" #low_arg ", " #high_arg ") returns %d rather than %d\n", res, lt_result); \ + if ((res = func (high_arg, low_arg)) != gt_result) printf ("fail: " #func " (" #high_arg ", " #low_arg ") returns %d rather than %d\n", res, gt_result); \ + if ((res = func (low_arg, low_arg)) != eq_result) printf ("fail: " #func " (" #low_arg ", " #low_arg ") returns %d rather than %d\n", res, eq_result); \ + } \ + while (0) +#else +# define TEST1(func,arg1,result) if (func (arg1) != result) abort () +# define TEST2(func,arg1,arg2,result) if (func (arg1, arg2) != result) abort () +# define TEST_CMP(func,low,high,lt_res,eq_res,gt_res) \ + if ( (func (low, high) != lt_res) \ + || (func (high, low) != gt_res) \ + || (func (low, low) != eq_res)) \ + abort (); +#endif + + +int +main (void) +{ +#ifdef DEBUG + printf ("Tests starting\n"); +#endif + + TEST1 (_COM_CONVf32s, -2.0f, -2); + TEST1 (_COM_CONVf32u, -2.0f, (unsigned) -2); + TEST1 (_COM_CONV32sf, -2, -2.0f); + TEST1 (_COM_CONV32uf, 2, 2.0f); + TEST2 (_COM_ADDf, 1.0f, 2.0f, 3.0f); + TEST2 (_COM_SUBf, 3.0f, 2.0f, 1.0f); + TEST2 (_COM_MULf, 2.0f, 3.0f, 6.0f); + TEST2 (_COM_DIVf, 6.0f, 2.0f, 3.0f); + TEST_CMP (_COM_CMPLTf, 1.0f, 2.0f, 1, 0, 0); + TEST_CMP (_COM_CMPGTf, 1.0f, 2.0f, 0, 0, 1); + TEST_CMP (_COM_CMPLEf, 1.0f, 2.0f, 1, 1, 0); + TEST_CMP (_COM_CMPGEf, 1.0f, 2.0f, 0, 1, 1); + TEST_CMP (_COM_CMPEQf, 1.0f, 2.0f, 0, 1, 0); + TEST_CMP (_COM_CMPNEf, 1.0f, 2.0f, 1, 0, 1); + + + TEST2 (_COM_MUL64, 2LL, 4LL, 8LL); + TEST2 (_COM_DIV64s, 6LL, 3LL, 2LL); + TEST2 (_COM_DIV64u, 6ULL, 3ULL, 2ULL); + TEST2 (_COM_SHLL64, 6LL, 3, 48LL); + TEST2 (_COM_SHLR64, 8LL, 2, 2LL); + TEST2 (_COM_SHAR64, -1LL, 2, -1LL); + TEST1 (_COM_CONVf64s, -2.0f, -2LL); + TEST1 (_COM_CONVf64u, 2.0f, 2ULL); + TEST1 (_COM_CONVd64s, -2.0, -2LL); + TEST1 (_COM_CONVd64u, 2.0, 2ULL); + TEST1 (_COM_CONV64sf, -2LL, -2.0f); + TEST1 (_COM_CONV64uf, 2ULL, 2.0f); + TEST1 (_COM_CONV64sd, -2LL, -2.0); + TEST1 (_COM_CONV64ud, 2ULL, 2.0); + TEST2 (_COM_MOD64s, 4LL, 3LL, 1LL); + TEST2 (_COM_MOD64u, 4ULL, 3ULL, 1ULL); + TEST_CMP (_COM_CMPLT64s, 1LL, 2LL, 1, 0, 0); + TEST_CMP (_COM_CMPLT64u, 1ULL, 2ULL, 1, 0, 0); + TEST_CMP (_COM_CMPGT64s, 1LL, 2LL, 0, 0, 1); + TEST_CMP (_COM_CMPGT64u, 1ULL, 2ULL, 0, 0, 1); + TEST_CMP (_COM_CMPLE64s, 1LL, 2LL, 1, 1, 0); + TEST_CMP (_COM_CMPLE64u, 1ULL, 2ULL, 1, 1, 0); + TEST_CMP (_COM_CMPGE64s, 1LL, 2LL, 0, 1, 1); + TEST_CMP (_COM_CMPGE64u, 1ULL, 2ULL, 0, 1, 1); + TEST_CMP (_COM_CMPEQ64, 1LL, 2LL, 0, 1, 0); + TEST_CMP (_COM_CMPNE64, 1LL, 2LL, 1, 0, 1); + + + TEST2 (_COM_ADDd, 1.0, 2.0, 3.0); + TEST2 (_COM_SUBd, 3.0, 2.0, 1.0); + TEST2 (_COM_MULd, 2.0, 3.0, 6.0); + TEST2 (_COM_DIVd, 6.0, 2.0, 3.0); + TEST1 (_COM_CONVd32s, -2.0, -2); + TEST1 (_COM_CONVd32u, -2.0, (unsigned) -2); + TEST1 (_COM_CONV32sd, -2, -2.0); + TEST1 (_COM_CONV32ud, 2, 2.0); + TEST1 (_COM_CONVfd, 2.0f, 2.0); + TEST1 (_COM_CONVdf, 2.0, 2.0f); + TEST1 (_COM_NEGd, -2.0, 2.0); + TEST_CMP (_COM_CMPLTd, 1.0, 2.0, 1, 0, 0); + TEST_CMP (_COM_CMPGTd, 1.0, 2.0, 0, 0, 1); + TEST_CMP (_COM_CMPLEd, 1.0, 2.0, 1, 1, 0); + TEST_CMP (_COM_CMPGEd, 1.0, 2.0, 0, 1, 1); + TEST_CMP (_COM_CMPEQd, 1.0, 2.0, 0, 1, 0); + TEST_CMP (_COM_CMPNEd, 1.0, 2.0, 1, 0, 1); + +#ifdef DEBUG + printf ("Tests finished\n"); +#endif + exit (0); +} diff --git a/gcc/testsuite/gcc.target/rx/rx.exp b/gcc/testsuite/gcc.target/rx/rx.exp new file mode 100644 index 00000000000..aa516e4555d --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/rx.exp @@ -0,0 +1,43 @@ +# Copyright (C) 2008 Free Software Foundation, Inc. + +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't the right target. +if { ![istarget rx-*-*] } then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "" +} + +# Initialize `dg'. +dg-init + +# Find all tests +set tests [lsort [find $srcdir/$subdir *.\[cS\]]] + +# Main loop. +gcc-dg-runtest $tests $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/rx/zero-width-bitfield.c b/gcc/testsuite/gcc.target/rx/zero-width-bitfield.c new file mode 100644 index 00000000000..26cf5a2b542 --- /dev/null +++ b/gcc/testsuite/gcc.target/rx/zero-width-bitfield.c @@ -0,0 +1,32 @@ +/* { dg-do run { xfail rx-*-* } } */ +/* { dg-skip-if "skipped until patch for generic zero=width bit-field handling is accepted" { rx-*-* } { "*" } { "" } } */ +/* { dg-options "-msim" } */ +/* Note: The -msim abiove is actually there to override the default + options which do not allow the GCC extension of zero-width bitfields. */ + +extern void abort (void); +extern void exit (int); + +struct S_zero +{ + int f1: 4; + int f2: 0; + short f3: 4; +} S_zero; + +struct S_norm +{ + int f1: 4; + short f3: 4; +} S_norm; + + +int +main (void) +{ + if (sizeof (S_zero) != 4 || sizeof (S_norm) != 8) + abort (); + + exit (0); + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/cache1.c b/gcc/testsuite/gcc.target/spu/ea/cache1.c new file mode 100644 index 00000000000..3487ce9806b --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/cache1.c @@ -0,0 +1,195 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do run } */ +/* { dg-require-effective-target "ealib" } */ + +#include <stdlib.h> +#include <string.h> +#include <ea.h> +#include <spu_cache.h> + +#ifdef __EA64__ +#define addr unsigned long long +#else +#define addr unsigned long +#endif + +static __ea void *bigblock; +static __ea void *block; +static int *ls_block; + +extern char __cache_tag_array_size[]; +#define CACHE_SIZE (4 * (int) &__cache_tag_array_size[0]) +#define LINE_SIZE ((addr)128) + +void +init_mem (void) +{ + bigblock = malloc_ea (CACHE_SIZE + 2 * LINE_SIZE); + block = malloc_ea (2 * LINE_SIZE); + ls_block = malloc (LINE_SIZE); + + memset_ea (bigblock, 0, CACHE_SIZE + 2 * LINE_SIZE); + memset_ea (block, -1, 2 * LINE_SIZE); + memset (ls_block, -1, LINE_SIZE); + cache_flush (); +} + +/* Test 1: Simple cache fetching. */ +void +test1 (void) +{ + addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE); + int *p1 = NULL; + int *p2 = NULL; + int i = 0; + + /* First, check if the same addr give the same cache ptr. */ + p1 = cache_fetch ((__ea void *) aligned); + p2 = cache_fetch ((__ea void *) aligned); + + if (p1 != p2) + abort (); + + /* Check that the data actually is in the cache. */ + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + { + if (p1[i] != -1) + abort (); + } + + /* Check returning within the cache line. */ + p2 = cache_fetch ((__ea void *) (aligned + sizeof (int))); + + if (p2 - p1 != 1) + abort (); + + /* Finally, check that fetching an LS pointer returns that pointer. */ + p1 = cache_fetch ((__ea char *) ls_block); + if (p1 != ls_block) + abort (); +} + +/* Test 2: Eviction testing. */ +void +test2 (void) +{ + addr aligned = ((((addr) block) + LINE_SIZE - 1) & -LINE_SIZE); + int *p = NULL; + int i = 0; + + /* First check that clean evictions don't write back. */ + p = cache_fetch ((__ea void *) aligned); + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + p[i] = 0; + + cache_evict ((__ea void *) aligned); + memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE); + + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + { + if (ls_block[i] == 0) + abort (); + } + + /* Now check that dirty evictions do write back. */ + p = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE); + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + p[i] = 0; + + cache_evict ((__ea void *) aligned); + memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE); + + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + { + if (ls_block[i] != 0) + abort (); + } + + /* Finally, check that non-atomic writeback only writes dirty bytes. */ + + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + { + p = cache_fetch_dirty ((__ea void *) (aligned + i * sizeof (int)), + (i % 2) * sizeof (int)); + p[0] = -1; + } + + cache_evict ((__ea void *) aligned); + memcpy_ea ((__ea char *) ls_block, (__ea void *) aligned, LINE_SIZE); + + for (i = 0; i < LINE_SIZE / sizeof (int); i++) + { + if ((ls_block[i] == -1) && (i % 2 == 0)) + abort (); + if ((ls_block[i] == 0) && (i % 2 == 1)) + abort (); + } +} + +/* Test LS forced-eviction. */ +void +test3 (void) +{ + addr aligned = ((((addr) bigblock) + LINE_SIZE - 1) & -LINE_SIZE); + char *test = NULL; + char *ls = NULL; + int i = 0; + + /* Init memory, fill the cache to capacity. */ + ls = cache_fetch_dirty ((__ea void *) aligned, LINE_SIZE); + for (i = 1; i < (CACHE_SIZE / LINE_SIZE); i++) + cache_fetch_dirty ((__ea void *) (aligned + i * LINE_SIZE), LINE_SIZE); + + memset (ls, -1, LINE_SIZE); + test = cache_fetch ((__ea void *) (aligned + CACHE_SIZE)); + + /* test == ls indicates cache collision. */ + if (test != ls) + abort (); + + /* Make sure it actually wrote the cache line. */ + for (i = 0; i < LINE_SIZE; i++) + { + if (ls[i] != 0) + abort (); + } + + ls = cache_fetch ((__ea void *) aligned); + + /* test != ls indicates another entry was evicted. */ + if (test == ls) + abort (); + + /* Make sure that the previous eviction actually wrote back. */ + for (i = 0; i < LINE_SIZE; i++) + { + if (ls[i] != 0xFF) + abort (); + } +} + +int +main (int argc, char **argv) +{ + init_mem (); + test1 (); + test2 (); + test3 (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/cast1.c b/gcc/testsuite/gcc.target/spu/ea/cast1.c new file mode 100644 index 00000000000..9ec4e154630 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/cast1.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do run } */ + +extern void abort (void); +extern unsigned long long __ea_local_store; + +__ea int *ppu; +int x, *spu = &x, *spu2; + +int +main (int argc, char **argv) +{ + ppu = (__ea int *) spu; + spu2 = (int *) ppu; + +#ifdef __EA32__ + if ((int) ppu != (int) __ea_local_store + (int) spu) +#else + if ((unsigned long long) ppu != __ea_local_store + (unsigned long long)(int) spu) +#endif + + abort (); + + if (spu != spu2) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/cast2.c b/gcc/testsuite/gcc.target/spu/ea/cast2.c new file mode 100644 index 00000000000..6ce57dc4da7 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/cast2.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do run } */ + +extern void abort (void); + +int array[128]; + +__ea int *ea; +int *lm; + +void verify_ea (void) __attribute__ ((noinline)); +void +verify_ea (void) +{ + if (ea != (__ea int *)lm) + abort (); +} + +void verify_lm (void) __attribute__ ((noinline)); +void +verify_lm (void) +{ + if ((int *)ea != lm) + abort (); +} + +void verify_diff (int x) __attribute__ ((noinline)); +void +verify_diff (int x) +{ + if (ea - lm != x) + abort (); +} + +int +main (int argc, char **argv) +{ + ea = 0; + lm = 0; + verify_ea (); + verify_lm (); + verify_diff (0); + + ea = &array[64]; + lm = &array[64]; + verify_ea (); + verify_lm (); + verify_diff (0); + + ea = &array[0]; + lm = &array[64]; + verify_diff (-64); + + ea = &array[64]; + lm = &array[0]; + verify_diff (64); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/compile1.c b/gcc/testsuite/gcc.target/spu/ea/compile1.c new file mode 100644 index 00000000000..ee7a32ad29b --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/compile1.c @@ -0,0 +1,109 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Valid __ea declarations. */ + +/* { dg-do compile } */ + +/* Typedefs. */ +typedef __ea int ea_int_t; +typedef __ea int *ea_int_star_t; +typedef int outer_t; + +/* Externs. */ + +__ea extern int i1; +extern __ea int i2; +extern int __ea i3; +extern __ea ea_int_t i4; /* __ea qualifier permitted via typedef. */ +extern int __ea __ea __ea dupe; /* __ea duplicate permitted directly. */ +extern int __ea *ppu; + +/* Pointers. */ +__ea int *i4p; + +/* Structs. */ +struct st { + __ea int *p; +}; + +/* Variable definitions. */ +__ea int ii0; +int *__ea ii1; +static int __ea ii2; + +void +f1 () +{ + int *spu; + ppu = (ea_int_t *) spu; + ppu = (ea_int_star_t) spu; +} + +void +f2 () +{ + int *spu; + spu = (int *) ppu; + ppu = (__ea int *) spu; +} + +void +f3 () +{ + int i = sizeof (__ea int); +} + +__ea int *f4 (void) +{ + return 0; +} + +int f5 (__ea int *parm) +{ + static __ea int local4; + int tmp = local4; + local4 = *parm; + return tmp; +} + +static inline __ea void *f6 (__ea void *start) +{ + return 0; +} + +void f7 (void) +{ + __ea void *s1; + auto __ea void *s2; +} + +__ea int *f8 (__ea int *x) +{ + register __ea int *y = x; + __ea int *z = y; + return z; +} + +long long f9 (__ea long long x[2]) +{ + return x[0] + x[1]; +} + +void f10 () +{ + static __ea outer_t o; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/compile2.c b/gcc/testsuite/gcc.target/spu/ea/compile2.c new file mode 100644 index 00000000000..58e64890e67 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/compile2.c @@ -0,0 +1,43 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Make sure __ea structure references work. */ + +/* { dg-do compile } */ + +typedef unsigned long int uintptr_t; + +struct tostruct +{ + uintptr_t selfpc; + long count; + unsigned short link; +}; + +/* froms are indexing tos */ +static __ea unsigned short *froms; +static __ea struct tostruct *tos = 0; + +void +foo (uintptr_t frompc, uintptr_t selfpc) +{ + __ea unsigned short *frompcindex; + + frompcindex = &froms[(frompc) / (4 * sizeof (*froms))]; + *frompcindex = tos[0].link; + + return; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/cppdefine.c b/gcc/testsuite/gcc.target/spu/ea/cppdefine.c new file mode 100644 index 00000000000..583635734b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/cppdefine.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Test default __EA32__/__EA64__ define. */ + +/* { dg-do compile } */ + +#if !defined (__EA32__) && !defined (__EA64__) +#error both __EA32__ and __EA64__ undefined +#endif + +#if defined (__EA32__) && defined (__EA64__) +#error both __EA32__ and __EA64__ defined +#endif + +#ifdef __EA32__ +int x [ sizeof (__ea char *) == 4 ? 1 : -1 ]; +#endif + +#ifdef __EA64__ +int x [ sizeof (__ea char *) == 8 ? 1 : -1 ]; +#endif + diff --git a/gcc/testsuite/gcc.target/spu/ea/ea.exp b/gcc/testsuite/gcc.target/spu/ea/ea.exp new file mode 100644 index 00000000000..8485d0fc720 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/ea.exp @@ -0,0 +1,54 @@ +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. + +# This program 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 3 of the License, or +# (at your option) any later version. +# +# This program 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a SPU target. +if { ![istarget spu-*-*] } then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# Return 1 if target __ea library functions are available +proc check_effective_target_ealib { } { + return [check_no_compiler_messages ealib executable { + #include <ea.h> + int main (void) + { + __ea void *ptr = malloc_ea (1024); + return 0; + } + }] +} + +# If a testcase doesn't have special options, use these. +# We do not use the global DEFAULT_CFLAGS as all test cases +# in this directory use the __ea address space qualifier +# extension and thus will not compile with -ansi. +set DEFAULT_EA_CFLAGS "-std=gnu99 -pedantic-errors -O2" + +# Initialize `dg'. +dg-init + +# Run all tests in both -mea32 and -mea64 mode. +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] +dg-runtest $tests "-mea32" $DEFAULT_EA_CFLAGS +dg-runtest $tests "-mea64" $DEFAULT_EA_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/spu/ea/errors1.c b/gcc/testsuite/gcc.target/spu/ea/errors1.c new file mode 100644 index 00000000000..7d0b5a11ca9 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/errors1.c @@ -0,0 +1,67 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Invalid __ea declarations. */ + +/* { dg-do compile } */ + +typedef __ea int eaint; + +void func () +{ + register __ea int local1; /* { dg-error "'__ea' combined with 'register' qualifier for 'local1'" } */ + auto __ea int local2; /* { dg-error "'__ea' combined with 'auto' qualifier for 'local2'" } */ + __ea int local3; /* { dg-error "'__ea' specified for auto variable 'local3'" } */ + register int *__ea p1; /* { dg-error "'__ea' combined with 'register' qualifier for 'p1'" } */ + auto char *__ea p2; /* { dg-error "'__ea' combined with 'auto' qualifier for 'p2'" } */ + void *__ea p3; /* { dg-error "'__ea' specified for auto variable 'p3'" } */ + register __ea int a1[2]; /* { dg-error "'__ea' combined with 'register' qualifier for 'a1'" } */ + auto __ea char a2[1]; /* { dg-error "'__ea' combined with 'auto' qualifier for 'a2'" } */ + __ea char a3[5]; /* { dg-error "'__ea' specified for auto variable 'a3'" } */ + register eaint td1; /* { dg-error "'__ea' combined with 'register' qualifier for 'td1'" } */ + auto eaint td2; /* { dg-error "'__ea' combined with 'auto' qualifier for 'td2'" } */ + eaint td3; /* { dg-error "'__ea' specified for auto variable 'td3'" } */ +} + +void func2 (__ea int x) /* { dg-error "'__ea' specified for parameter 'x'" } */ +{ } + +void func2td (eaint x) /* { dg-error "'__ea' specified for parameter 'x'" } */ +{ } + +struct st { + __ea int x; /* { dg-error "'__ea' specified for structure field 'x'" } */ + eaint td; /* { dg-error "'__ea' specified for structure field 'td'" } */ + int *__ea q; /* { dg-error "'__ea' specified for structure field 'q'" } */ + int __ea b : 7; /* { dg-error "'__ea' specified for structure field 'b'" } */ + int __ea : 1; /* { dg-error "'__ea' specified for structure field" } */ +} s; + +struct A { int a; }; + +int func3 (int *__ea); /* { dg-error "'__ea' specified for unnamed parameter" } */ +int func3 (int *__ea x) /* { dg-error "'__ea' specified for parameter 'x'" } */ +{ + struct A i = (__ea struct A) { 1 }; /* { dg-error "compound literal qualified by address-space qualifier" } */ + return i.a; +} + +extern __ea int ea_var; /* { dg-message "note: previous declaration of 'ea_var' was here" } */ +int ea_var; /* { dg-error "conflicting named address spaces \\(generic vs __ea\\) for 'ea_var'" } */ + +extern eaint ea_var_td; /* { dg-message "note: previous declaration of 'ea_var_td' was here" } */ +int ea_var_td; /* { dg-error "conflicting named address spaces \\(generic vs __ea\\) for 'ea_var_td'" } */ + diff --git a/gcc/testsuite/gcc.target/spu/ea/errors2.c b/gcc/testsuite/gcc.target/spu/ea/errors2.c new file mode 100644 index 00000000000..74a32ff5e7e --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/errors2.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Invalid __ea declarations. */ + +/* { dg-do compile } */ + +__ea char ea_str[] = "abc"; +char lm_str[] = "abc"; + +__ea char *lm_ea_ptr1 = "abc"; /* { dg-error "initializer element is not computable at load time" } */ +__ea char *lm_ea_ptr2 = (__ea char *)"abc"; /* { dg-error "initializer element is not constant" } */ +__ea char *lm_ea_ptr3 = ea_str; +__ea char *lm_ea_ptr4 = (__ea char *)ea_str; +__ea char *lm_ea_ptr5 = lm_str; /* { dg-error "initializer element is not computable at load time" } */ +__ea char *lm_ea_ptr6 = (__ea char *)lm_str; /* { dg-error "initializer element is not constant" } */ + +__ea char * __ea ea_ea_ptr1 = ea_str; +__ea char * __ea ea_ea_ptr2 = (__ea char *)ea_str; + +char * __ea ea_lm_ptr1 = lm_str; +char * __ea ea_lm_ptr2 = (char *)lm_str; + +struct foo { + int first; + __ea char *ptr; + int last; +}; + +__ea struct foo ea_struct1 = { + 10, + (__ea char *)0, + 11, +}; + +__ea struct foo ea_struct2 = { + 20, + 0, + 21, +}; + +struct foo ea_struct3 = { + 30, + ea_str, + 31, +}; + +struct foo ea_struct4 = { + 40, + (__ea char *)lm_str, /* { dg-error "(initializer element is not constant)|(near initialization)" "" } */ + 41, +}; + +struct bar { + int first; + char *ptr; + int last; +}; + +__ea struct bar ea_struct5 = { + 50, + 0, + 51, +}; + +__ea struct bar ea_struct6 = { + 60, + (char *)0, + 61, +}; + +__ea struct bar ea_struct7 = { + 70, + lm_str, + 71, +}; + +struct bar lm_struct8 = { + 80, + 0, + 81, +}; + +struct bar lm_struct9 = { + 90, + (char *)0, + 91, +}; + +struct bar lm_struct10 = { + 100, + lm_str, + 101, +}; diff --git a/gcc/testsuite/gcc.target/spu/ea/execute1.c b/gcc/testsuite/gcc.target/spu/ea/execute1.c new file mode 100644 index 00000000000..99d6d691810 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/execute1.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do compile } */ + +#include <stdlib.h> + +__ea char str[] = "abc"; + +int +main (void) +{ + __ea char *p = str; + + if (*p++ != 'a') + abort (); + + if (*p++ != 'b') + abort (); + + if (*p++ != 'c') + abort (); + + if (*p++ != '\0') + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/execute2.c b/gcc/testsuite/gcc.target/spu/ea/execute2.c new file mode 100644 index 00000000000..5fce4e673ff --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/execute2.c @@ -0,0 +1,41 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do run } */ + +#include <stdlib.h> + +char str[] = "abc"; + +int +main (void) +{ + __ea char *p = (__ea char *)str; + + if (*p++ != 'a') + abort (); + + if (*p++ != 'b') + abort (); + + if (*p++ != 'c') + abort (); + + if (*p++ != '\0') + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/execute3.c b/gcc/testsuite/gcc.target/spu/ea/execute3.c new file mode 100644 index 00000000000..1b8c139d7af --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/execute3.c @@ -0,0 +1,39 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do run } */ + +#include <stdlib.h> + +int +main (void) +{ + __ea char *p = (__ea char *)"abc"; + + if (*p++ != 'a') + abort (); + + if (*p++ != 'b') + abort (); + + if (*p++ != 'c') + abort (); + + if (*p++ != '\0') + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/spu/ea/ops1.c b/gcc/testsuite/gcc.target/spu/ea/ops1.c new file mode 100644 index 00000000000..0d162f21820 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/ops1.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* This is the same as ops2.c except for the compile option. + If you modify this code, please modify ops2.c as well. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -std=gnu99 -pedantic-errors -maddress-space-conversion" } */ + +#define __lm + +__ea int ea_var = 1; +__lm int lm_var = 2; + +typedef __ea int *ea_ptr_t; +typedef __lm int *lm_ptr_t; + +typedef __ea void *ea_vptr_t; +typedef __lm void *lm_vptr_t; + +ea_ptr_t ea, ea2; +lm_ptr_t lm, lm2; + +ea_vptr_t eav; +lm_vptr_t lmv; + +extern void call_ea (ea_ptr_t); +extern void call_lm (lm_ptr_t); + +/* Assignment, initialization, argument passing, and return. */ +void to_ea (void) { ea = lm; } +void to_lm (void) { lm = ea; } /* { dg-error "assignment from pointer to non-enclosed address space" } */ +void init_ea (void) { ea_ptr_t l_ea = lm; } +void init_lm (void) { lm_ptr_t l_lm = ea; } /* { dg-error "initialization from pointer to non-enclosed address space" } */ +ea_ptr_t ret_ea (void) { return lm; } +lm_ptr_t ret_lm (void) { return ea; } /* { dg-error "return from pointer to non-enclosed address space" } */ +void call_ea2 (void) { call_ea (lm); } +void call_lm2 (void) { call_lm (ea); } /* { dg-error "passing argument 1 of 'call_lm' from pointer to non-enclosed address space" } */ + +/* Explicit casts. */ +void to_ea_with_cast (void) { ea = (ea_ptr_t)lm; } +void to_lm_with_cast (void) { lm = (lm_ptr_t)ea; } +void init_ea_with_cast (void) { ea_ptr_t l_ea = (ea_ptr_t)lm; } +void init_lm_with_cast (void) { lm_ptr_t l_lm = (lm_ptr_t)ea; } +ea_ptr_t ret_ea_with_cast (void) { return (ea_ptr_t)lm; } +lm_ptr_t ret_lm_with_cast (void) { return (lm_ptr_t)ea; } +void call_ea2_with_cast (void) { call_ea ((ea_ptr_t)lm); } +void call_lm2_with_cast (void) { call_lm ((lm_ptr_t)ea); } + +/* Arithmetic operators. */ +int sub_eaea (void) { return ea - ea2; } +int sub_ealm (void) { return ea - lm2; } +int sub_lmea (void) { return lm - ea2; } +int sub_lmlm (void) { return lm - lm2; } +ea_ptr_t if_eaea1 (int test) { return test? ea : ea2; } +lm_ptr_t if_eaea2 (int test) { return test? ea : ea2; } /* { dg-error "return from pointer to non-enclosed address space" } */ +ea_ptr_t if_ealm1 (int test) { return test? ea : lm2; } +lm_ptr_t if_ealm2 (int test) { return test? ea : lm2; } /* { dg-error "return from pointer to non-enclosed address space" } */ +ea_ptr_t if_lmea1 (int test) { return test? lm : ea2; } +lm_ptr_t if_lmea2 (int test) { return test? lm : ea2; } /* { dg-error "return from pointer to non-enclosed address space" } */ +ea_ptr_t if_lmlm1 (int test) { return test? lm : lm2; } +lm_ptr_t if_lmlm2 (int test) { return test? lm : lm2; } + +/* Relational operators. */ +int eq_eaea (void) { return ea == ea2; } +int eq_ealm (void) { return ea == lm2; } +int eq_lmea (void) { return lm == ea2; } +int eq_lmlm (void) { return lm == lm2; } +int lt_eaea (void) { return ea < ea2; } +int lt_ealm (void) { return ea < lm2; } +int lt_lmea (void) { return lm < ea2; } +int lt_lmlm (void) { return lm < lm2; } + +/* Null pointer. */ +void null_ea1 (void) { ea = 0; } +void null_ea2 (void) { ea = (void *)0; } +void null_ea3 (void) { ea = (__ea void *)0; } +void null_lm1 (void) { lm = 0; } +void null_lm2 (void) { lm = (void *)0; } +void null_lm3 (void) { lm = (__ea void *)0; } /* { dg-error "assignment from pointer to non-enclosed address space" } */ + diff --git a/gcc/testsuite/gcc.target/spu/ea/ops2.c b/gcc/testsuite/gcc.target/spu/ea/ops2.c new file mode 100644 index 00000000000..2514e6b2095 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/ops2.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* This is the same as ops1.c except for the compile option. + If you modify this code, please modify ops1.c as well. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -std=gnu99 -pedantic-errors -mno-address-space-conversion" } */ + +#define __lm + +__ea int ea_var = 1; +__lm int lm_var = 2; + +typedef __ea int *ea_ptr_t; +typedef __lm int *lm_ptr_t; + +typedef __ea void *ea_vptr_t; +typedef __lm void *lm_vptr_t; + +ea_ptr_t ea, ea2; +lm_ptr_t lm, lm2; + +ea_vptr_t eav; +lm_vptr_t lmv; + +extern void call_ea (ea_ptr_t); +extern void call_lm (lm_ptr_t); + +/* Assignment, initialization, argument passing, and return. */ +void to_ea (void) { ea = lm; } /* { dg-error "assignment from pointer to non-enclosed address space" } */ +void to_lm (void) { lm = ea; } /* { dg-error "assignment from pointer to non-enclosed address space" } */ +void init_ea (void) { ea_ptr_t l_ea = lm; } /* { dg-error "initialization from pointer to non-enclosed address space" } */ +void init_lm (void) { lm_ptr_t l_lm = ea; } /* { dg-error "initialization from pointer to non-enclosed address space" } */ +ea_ptr_t ret_ea (void) { return lm; } /* { dg-error "return from pointer to non-enclosed address space" } */ +lm_ptr_t ret_lm (void) { return ea; } /* { dg-error "return from pointer to non-enclosed address space" } */ +void call_ea2 (void) { call_ea (lm); } /* { dg-error "passing argument 1 of 'call_ea' from pointer to non-enclosed address space" } */ +void call_lm2 (void) { call_lm (ea); } /* { dg-error "passing argument 1 of 'call_lm' from pointer to non-enclosed address space" } */ + +/* Explicit casts. */ +void to_ea_with_cast (void) { ea = (ea_ptr_t)lm; } /* { dg-warning "cast to __ea address space pointer" } */ +void to_lm_with_cast (void) { lm = (lm_ptr_t)ea; } /* { dg-warning "cast to generic address space pointer" } */ +void init_ea_with_cast (void) { ea_ptr_t l_ea = (ea_ptr_t)lm; } /* { dg-warning "cast to __ea address space pointer" } */ +void init_lm_with_cast (void) { lm_ptr_t l_lm = (lm_ptr_t)ea; } /* { dg-warning "cast to generic address space pointer" } */ +ea_ptr_t ret_ea_with_cast (void) { return (ea_ptr_t)lm; } /* { dg-warning "cast to __ea address space pointer" } */ +lm_ptr_t ret_lm_with_cast (void) { return (lm_ptr_t)ea; } /* { dg-warning "cast to generic address space pointer" } */ +void call_ea2_with_cast (void) { call_ea ((ea_ptr_t)lm); } /* { dg-warning "cast to __ea address space pointer" } */ +void call_lm2_with_cast (void) { call_lm ((lm_ptr_t)ea); } /* { dg-warning "cast to generic address space pointer" } */ + +/* Arithmetic operators. */ +int sub_eaea (void) { return ea - ea2; } +int sub_ealm (void) { return ea - lm2; } /* { dg-error "invalid operands to binary -" } */ +int sub_lmea (void) { return lm - ea2; } /* { dg-error "invalid operands to binary -" } */ +int sub_lmlm (void) { return lm - lm2; } +ea_ptr_t if_eaea1 (int test) { return test? ea : ea2; } +lm_ptr_t if_eaea2 (int test) { return test? ea : ea2; } /* { dg-error "return from pointer to non-enclosed address space" } */ +ea_ptr_t if_ealm1 (int test) { return test? ea : lm2; } /* { dg-error "pointers to disjoint address spaces used in conditional expression" } */ +lm_ptr_t if_ealm2 (int test) { return test? ea : lm2; } /* { dg-error "pointers to disjoint address spaces used in conditional expression" } */ +ea_ptr_t if_lmea1 (int test) { return test? lm : ea2; } /* { dg-error "pointers to disjoint address spaces used in conditional expression" } */ +lm_ptr_t if_lmea2 (int test) { return test? lm : ea2; } /* { dg-error "pointers to disjoint address spaces used in conditional expression" } */ +ea_ptr_t if_lmlm1 (int test) { return test? lm : lm2; } /* { dg-error "return from pointer to non-enclosed address space" } */ +lm_ptr_t if_lmlm2 (int test) { return test? lm : lm2; } + +/* Relational operators. */ +int eq_eaea (void) { return ea == ea2; } +int eq_ealm (void) { return ea == lm2; } /* { dg-error "comparison of pointers to disjoint address spaces" } */ +int eq_lmea (void) { return lm == ea2; } /* { dg-error "comparison of pointers to disjoint address spaces" } */ +int eq_lmlm (void) { return lm == lm2; } +int lt_eaea (void) { return ea < ea2; } +int lt_ealm (void) { return ea < lm2; } /* { dg-error "comparison of pointers to disjoint address spaces" } */ +int lt_lmea (void) { return lm < ea2; } /* { dg-error "comparison of pointers to disjoint address spaces" } */ +int lt_lmlm (void) { return lm < lm2; } + +/* Null pointer. */ +void null_ea1 (void) { ea = 0; } +void null_ea2 (void) { ea = (void *)0; } +void null_ea3 (void) { ea = (__ea void *)0; } +void null_lm1 (void) { lm = 0; } +void null_lm2 (void) { lm = (void *)0; } +void null_lm3 (void) { lm = (__ea void *)0; } /* { dg-error "assignment from pointer to non-enclosed address space" } */ + diff --git a/gcc/testsuite/gcc.target/spu/ea/options1.c b/gcc/testsuite/gcc.target/spu/ea/options1.c new file mode 100644 index 00000000000..19040090206 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/options1.c @@ -0,0 +1,22 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Test -mcache-size. */ + +/* { dg-do compile } */ +/* { dg-options "-mcache-size=128" } */ + +int x; diff --git a/gcc/testsuite/gcc.target/spu/ea/test-sizes.c b/gcc/testsuite/gcc.target/spu/ea/test-sizes.c new file mode 100644 index 00000000000..e467616b628 --- /dev/null +++ b/gcc/testsuite/gcc.target/spu/ea/test-sizes.c @@ -0,0 +1,608 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + + This file 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 3 of the License, or (at your option) + any later version. + + This file 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 this file; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* { dg-do run } */ + +#ifdef __EA32__ +#define EA_PTRSIZE 4 +#endif +#ifdef __EA64__ +#define EA_PTRSIZE 8 +#endif + +#if !defined(LEVEL1) && !defined(LEVEL2) && !defined(LEVEL3) +#define LEVEL1 1 /* single pointer indirection */ +#define LEVEL2 1 /* 2 levels of pointer indirection */ +#define LEVEL3 1 /* 3 levels of pointer indirection */ + +#else +#ifndef LEVEL1 +#define LEVEL1 0 +#endif + +#ifndef LEVEL2 +#define LEVEL2 0 +#endif + +#ifndef LEVEL3 +#define LEVEL3 0 +#endif +#endif + +#if !defined(USE_SIMPLE) && !defined(USE_COMPLEX) +#define USE_SIMPLE 1 /* build up pointers via multiple typedefs */ +#define USE_COMPLEX 1 /* single typedef for pointer indirections */ + +#else +#ifndef USE_SIMPLE +#define USE_SIMPLE 0 +#endif + +#ifndef USE_COMPLEX +#define USE_COMPLEX 0 +#endif +#endif + +#if !defined(USE_LOCAL_VAR) && !defined(USE_EA_VAR) +#define USE_LOCAL_VAR 1 /* use variables declared locally */ +#define USE_EA_VAR 1 /* use variables on the host */ + +#else +#ifndef USE_LOCAL_VAR +#define USE_LOCAL_VAR 0 +#endif + +#ifndef USE_EA_VAR +#define USE_EA_VAR 0 +#endif +#endif + +static int errors; + +#ifdef USE_PRINTF /* print results via printf */ +#include <stdio.h> +#include <stdlib.h> + +static int num_tests; + +#define TEST_SIZE(EXPR, EXPECTED) \ +do { \ + char *msg; \ + \ + if (sizeof (EXPR) != EXPECTED) \ + { \ + msg = ", FAIL"; \ + errors++; \ + } \ + else \ + msg = ""; \ + \ + num_tests++; \ + printf ("sizeof %-20s = %2u, expected = %2u%s\n", \ + #EXPR, \ + (unsigned) sizeof (EXPR), \ + (unsigned) EXPECTED, \ + msg); \ +} while (0) + +#define PRINT1(FMT) printf (FMT) +#define PRINT2(FMT,A1) printf (FMT,A1) +#define PRINT3(FMT,A1,A2) printf (FMT,A1,A2) + +#else /* standalone */ +extern void abort (void); + +#define TEST_SIZE(EXPR, EXPECTED) \ +do { \ + if (sizeof (EXPR) != EXPECTED) \ + abort (); \ +} while (0) + +#define PRINT1(FMT) +#define PRINT2(FMT,ARG) +#define PRINT3(FMT,A1,A2) +#endif + +/* 'local memory' hack to keep the same spacing. */ +#define __lm + +#if USE_SIMPLE +#if (LEVEL1 || LEVEL2 || LEVEL3) +typedef __lm char *lm_ptr_t; +typedef __ea char *ea_ptr_t; +#endif + +#if LEVEL1 +#if USE_LOCAL_VAR +__lm lm_ptr_t lm_ptr; +__lm ea_ptr_t ea_ptr; +#endif + +#if USE_EA_VAR +__ea lm_ptr_t lm_ptr_ea; +__ea ea_ptr_t ea_ptr_ea; +#endif +#endif + +#if (LEVEL2 || LEVEL3) +typedef __lm lm_ptr_t *lm_lm_ptr_t; +typedef __ea lm_ptr_t *ea_lm_ptr_t; +typedef __lm ea_ptr_t *lm_ea_ptr_t; +typedef __ea ea_ptr_t *ea_ea_ptr_t; +#endif + +#if LEVEL2 +#if USE_LOCAL_VAR +__lm lm_lm_ptr_t lm_lm_ptr; +__lm ea_lm_ptr_t ea_lm_ptr; +__lm lm_ea_ptr_t lm_ea_ptr; +__lm ea_ea_ptr_t ea_ea_ptr; +#endif + +#if USE_EA_VAR +__ea lm_lm_ptr_t lm_lm_ptr_ea; +__ea ea_lm_ptr_t ea_lm_ptr_ea; +__ea lm_ea_ptr_t lm_ea_ptr_ea; +__ea ea_ea_ptr_t ea_ea_ptr_ea; +#endif +#endif + +#if LEVEL3 +typedef __lm lm_lm_ptr_t *lm_lm_lm_ptr_t; +typedef __ea lm_lm_ptr_t *ea_lm_lm_ptr_t; +typedef __lm ea_lm_ptr_t *lm_ea_lm_ptr_t; +typedef __ea ea_lm_ptr_t *ea_ea_lm_ptr_t; +typedef __lm lm_ea_ptr_t *lm_lm_ea_ptr_t; +typedef __ea lm_ea_ptr_t *ea_lm_ea_ptr_t; +typedef __lm ea_ea_ptr_t *lm_ea_ea_ptr_t; +typedef __ea ea_ea_ptr_t *ea_ea_ea_ptr_t; + +#if USE_LOCAL_VAR +__lm lm_lm_lm_ptr_t lm_lm_lm_ptr; +__lm ea_lm_lm_ptr_t ea_lm_lm_ptr; +__lm lm_ea_lm_ptr_t lm_ea_lm_ptr; +__lm ea_ea_lm_ptr_t ea_ea_lm_ptr; +__lm lm_lm_ea_ptr_t lm_lm_ea_ptr; +__lm ea_lm_ea_ptr_t ea_lm_ea_ptr; +__lm lm_ea_ea_ptr_t lm_ea_ea_ptr; +__lm ea_ea_ea_ptr_t ea_ea_ea_ptr; +#endif + +#if USE_EA_VAR +__ea lm_lm_lm_ptr_t lm_lm_lm_ptr_ea; +__ea ea_lm_lm_ptr_t ea_lm_lm_ptr_ea; +__ea lm_ea_lm_ptr_t lm_ea_lm_ptr_ea; +__ea ea_ea_lm_ptr_t ea_ea_lm_ptr_ea; +__ea lm_lm_ea_ptr_t lm_lm_ea_ptr_ea; +__ea ea_lm_ea_ptr_t ea_lm_ea_ptr_ea; +__ea lm_ea_ea_ptr_t lm_ea_ea_ptr_ea; +__ea ea_ea_ea_ptr_t ea_ea_ea_ptr_ea; +#endif +#endif +#endif + +#if USE_COMPLEX +#if LEVEL1 +#if USE_LOCAL_VAR +__lm char *__lm lm_cptr; +__ea char *__lm ea_cptr; +#endif + +#if USE_EA_VAR +__lm char *__ea lm_cptr_ea; +__ea char *__ea ea_cptr_ea; +#endif +#endif + +#if LEVEL2 +#if USE_LOCAL_VAR +__lm char *__lm *__lm lm_lm_cptr; +__lm char *__ea *__lm ea_lm_cptr; +__ea char *__lm *__lm lm_ea_cptr; +__ea char *__ea *__lm ea_ea_cptr; +#endif + +#if USE_EA_VAR +__lm char *__lm *__ea lm_lm_cptr_ea; +__lm char *__ea *__ea ea_lm_cptr_ea; +__ea char *__lm *__ea lm_ea_cptr_ea; +__ea char *__ea *__ea ea_ea_cptr_ea; +#endif +#endif + +#if LEVEL3 +#if USE_LOCAL_VAR +__lm char *__lm *__lm *__lm lm_lm_lm_cptr; +__lm char *__ea *__lm *__lm lm_ea_lm_cptr; +__ea char *__lm *__lm *__lm lm_lm_ea_cptr; +__ea char *__ea *__lm *__lm lm_ea_ea_cptr; +__lm char *__lm *__ea *__lm ea_lm_lm_cptr; +__lm char *__ea *__ea *__lm ea_ea_lm_cptr; +__ea char *__lm *__ea *__lm ea_lm_ea_cptr; +__ea char *__ea *__ea *__lm ea_ea_ea_cptr; +#endif + +#if USE_EA_VAR +__lm char *__lm *__lm *__ea lm_lm_lm_cptr_ea; +__lm char *__ea *__lm *__ea lm_ea_lm_cptr_ea; +__ea char *__lm *__lm *__ea lm_lm_ea_cptr_ea; +__ea char *__ea *__lm *__ea lm_ea_ea_cptr_ea; +__lm char *__lm *__ea *__ea ea_lm_lm_cptr_ea; +__lm char *__ea *__ea *__ea ea_ea_lm_cptr_ea; +__ea char *__lm *__ea *__ea ea_lm_ea_cptr_ea; +__ea char *__ea *__ea *__ea ea_ea_ea_cptr_ea; +#endif +#endif +#endif + +int +main () +{ + PRINT2 ("LEVEL1 = %d\n", LEVEL1); + PRINT2 ("LEVEL2 = %d\n", LEVEL2); + PRINT2 ("LEVEL3 = %d\n", LEVEL3); + PRINT2 ("USE_SIMPLE = %d\n", USE_SIMPLE); + PRINT2 ("USE_COMPLEX = %d\n", USE_COMPLEX); + PRINT2 ("USE_LOCAL_VAR = %d\n", USE_LOCAL_VAR); + PRINT2 ("USE_EA_VAR = %d\n", USE_EA_VAR); + PRINT1 ("\n"); + +#if USE_SIMPLE +#if LEVEL1 +#if USE_LOCAL_VAR + TEST_SIZE ( lm_ptr, 4); + TEST_SIZE (*lm_ptr, 1); + TEST_SIZE ( ea_ptr, EA_PTRSIZE); + TEST_SIZE (*ea_ptr, 1); + PRINT1 ("\n"); +#endif + +#if USE_EA_VAR + TEST_SIZE ( lm_ptr_ea, 4); + TEST_SIZE (*lm_ptr_ea, 1); + TEST_SIZE ( ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (*ea_ptr_ea, 1); + PRINT1 ("\n"); +#endif +#endif + +#if LEVEL2 +#if USE_LOCAL_VAR + TEST_SIZE ( lm_lm_ptr, 4); + TEST_SIZE ( *lm_lm_ptr, 4); + TEST_SIZE (**lm_lm_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_ptr, 4); + TEST_SIZE ( *lm_ea_ptr, EA_PTRSIZE); + TEST_SIZE (**lm_ea_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_ptr, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_ptr, 4); + TEST_SIZE (**ea_lm_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE (**ea_ea_ptr, 1); + PRINT1 ("\n"); +#endif + +#if USE_EA_VAR + TEST_SIZE ( lm_lm_ptr_ea, 4); + TEST_SIZE ( *lm_lm_ptr_ea, 4); + TEST_SIZE (**lm_lm_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_ptr_ea, 4); + TEST_SIZE ( *lm_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (**lm_ea_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_ptr_ea, 4); + TEST_SIZE (**ea_lm_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (**ea_ea_ptr_ea, 1); + PRINT1 ("\n"); +#endif +#endif + +#if LEVEL3 +#if USE_LOCAL_VAR + TEST_SIZE ( lm_lm_lm_ptr, 4); + TEST_SIZE ( *lm_lm_lm_ptr, 4); + TEST_SIZE ( **lm_lm_lm_ptr, 4); + TEST_SIZE (***lm_lm_lm_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_lm_ea_ptr, 4); + TEST_SIZE ( *lm_lm_ea_ptr, 4); + TEST_SIZE ( **lm_lm_ea_ptr, EA_PTRSIZE); + TEST_SIZE (***lm_lm_ea_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_lm_ptr, 4); + TEST_SIZE ( *lm_ea_lm_ptr, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_lm_ptr, 4); + TEST_SIZE (***lm_ea_lm_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_ea_ptr, 4); + TEST_SIZE ( *lm_ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE (***lm_ea_ea_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_lm_ptr, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_lm_ptr, 4); + TEST_SIZE ( **ea_lm_lm_ptr, 4); + TEST_SIZE (***ea_lm_lm_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_ea_ptr, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_ea_ptr, 4); + TEST_SIZE ( **ea_lm_ea_ptr, EA_PTRSIZE); + TEST_SIZE (***ea_lm_ea_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_lm_ptr, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_lm_ptr, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_lm_ptr, 4); + TEST_SIZE (***ea_ea_lm_ptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_ea_ptr, EA_PTRSIZE); + TEST_SIZE (***ea_ea_ea_ptr, 1); + PRINT1 ("\n"); +#endif + +#if USE_EA_VAR + TEST_SIZE ( lm_lm_lm_ptr_ea, 4); + TEST_SIZE ( *lm_lm_lm_ptr_ea, 4); + TEST_SIZE ( **lm_lm_lm_ptr_ea, 4); + TEST_SIZE (***lm_lm_lm_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_lm_ea_ptr_ea, 4); + TEST_SIZE ( *lm_lm_ea_ptr_ea, 4); + TEST_SIZE ( **lm_lm_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (***lm_lm_ea_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_lm_ptr_ea, 4); + TEST_SIZE ( *lm_ea_lm_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_lm_ptr_ea, 4); + TEST_SIZE (***lm_ea_lm_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_ea_ptr_ea, 4); + TEST_SIZE ( *lm_ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (***lm_ea_ea_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_lm_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_lm_ptr_ea, 4); + TEST_SIZE ( **ea_lm_lm_ptr_ea, 4); + TEST_SIZE (***ea_lm_lm_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_ea_ptr_ea, 4); + TEST_SIZE ( **ea_lm_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (***ea_lm_ea_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_lm_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_lm_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_lm_ptr_ea, 4); + TEST_SIZE (***ea_ea_lm_ptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_ea_ptr_ea, EA_PTRSIZE); + TEST_SIZE (***ea_ea_ea_ptr_ea, 1); + PRINT1 ("\n"); +#endif +#endif +#endif + +#if USE_COMPLEX +#if LEVEL1 +#if USE_LOCAL_VAR + TEST_SIZE ( lm_cptr, 4); + TEST_SIZE (*lm_cptr, 1); + TEST_SIZE ( ea_cptr, EA_PTRSIZE); + TEST_SIZE (*ea_cptr, 1); + PRINT1 ("\n"); +#endif + +#if USE_EA_VAR + TEST_SIZE ( lm_cptr_ea, 4); + TEST_SIZE (*lm_cptr_ea, 1); + TEST_SIZE ( ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (*ea_cptr_ea, 1); + PRINT1 ("\n"); +#endif +#endif + +#if LEVEL2 +#if USE_LOCAL_VAR + TEST_SIZE ( lm_lm_cptr, 4); + TEST_SIZE ( *lm_lm_cptr, 4); + TEST_SIZE (**lm_lm_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_cptr, 4); + TEST_SIZE ( *lm_ea_cptr, EA_PTRSIZE); + TEST_SIZE (**lm_ea_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_cptr, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_cptr, 4); + TEST_SIZE (**ea_lm_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE (**ea_ea_cptr, 1); + PRINT1 ("\n"); +#endif + +#if USE_EA_VAR + TEST_SIZE ( lm_lm_cptr_ea, 4); + TEST_SIZE ( *lm_lm_cptr_ea, 4); + TEST_SIZE (**lm_lm_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_cptr_ea, 4); + TEST_SIZE ( *lm_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (**lm_ea_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_cptr_ea, 4); + TEST_SIZE (**ea_lm_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (**ea_ea_cptr_ea, 1); + PRINT1 ("\n"); +#endif +#endif + +#if LEVEL3 +#if USE_LOCAL_VAR + TEST_SIZE ( lm_lm_lm_cptr, 4); + TEST_SIZE ( *lm_lm_lm_cptr, 4); + TEST_SIZE ( **lm_lm_lm_cptr, 4); + TEST_SIZE (***lm_lm_lm_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_lm_ea_cptr, 4); + TEST_SIZE ( *lm_lm_ea_cptr, 4); + TEST_SIZE ( **lm_lm_ea_cptr, EA_PTRSIZE); + TEST_SIZE (***lm_lm_ea_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_lm_cptr, 4); + TEST_SIZE ( *lm_ea_lm_cptr, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_lm_cptr, 4); + TEST_SIZE (***lm_ea_lm_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_ea_cptr, 4); + TEST_SIZE ( *lm_ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE (***lm_ea_ea_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_lm_cptr, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_lm_cptr, 4); + TEST_SIZE ( **ea_lm_lm_cptr, 4); + TEST_SIZE (***ea_lm_lm_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_ea_cptr, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_ea_cptr, 4); + TEST_SIZE ( **ea_lm_ea_cptr, EA_PTRSIZE); + TEST_SIZE (***ea_lm_ea_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_lm_cptr, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_lm_cptr, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_lm_cptr, 4); + TEST_SIZE (***ea_ea_lm_cptr, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_ea_cptr, EA_PTRSIZE); + TEST_SIZE (***ea_ea_ea_cptr, 1); + PRINT1 ("\n"); +#endif + +#if USE_EA_VAR + TEST_SIZE ( lm_lm_lm_cptr_ea, 4); + TEST_SIZE ( *lm_lm_lm_cptr_ea, 4); + TEST_SIZE ( **lm_lm_lm_cptr_ea, 4); + TEST_SIZE (***lm_lm_lm_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_lm_ea_cptr_ea, 4); + TEST_SIZE ( *lm_lm_ea_cptr_ea, 4); + TEST_SIZE ( **lm_lm_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (***lm_lm_ea_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_lm_cptr_ea, 4); + TEST_SIZE ( *lm_ea_lm_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_lm_cptr_ea, 4); + TEST_SIZE (***lm_ea_lm_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( lm_ea_ea_cptr_ea, 4); + TEST_SIZE ( *lm_ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( **lm_ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (***lm_ea_ea_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_lm_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_lm_cptr_ea, 4); + TEST_SIZE ( **ea_lm_lm_cptr_ea, 4); + TEST_SIZE (***ea_lm_lm_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_lm_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_lm_ea_cptr_ea, 4); + TEST_SIZE ( **ea_lm_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (***ea_lm_ea_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_lm_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_lm_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_lm_cptr_ea, 4); + TEST_SIZE (***ea_ea_lm_cptr_ea, 1); + PRINT1 ("\n"); + + TEST_SIZE ( ea_ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( *ea_ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE ( **ea_ea_ea_cptr_ea, EA_PTRSIZE); + TEST_SIZE (***ea_ea_ea_cptr_ea, 1); + PRINT1 ("\n"); +#endif +#endif +#endif + + if (errors) + { + PRINT3 ("%d error(s), %d test(s)\n", errors, num_tests); + abort (); + } + else + PRINT2 ("No errors, %d test(s)\n", num_tests); + + return 0; +} diff --git a/gcc/testsuite/gfortran.dg/class_allocate_4.f03 b/gcc/testsuite/gfortran.dg/class_allocate_4.f03 new file mode 100644 index 00000000000..d1ebf8cc915 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_allocate_4.f03 @@ -0,0 +1,23 @@ +! { dg-do run } +! +! PR 41714: [OOP] ALLOCATE SOURCE= does not properly copy the value from SOURCE +! +! Contributed by Tobias Burnus <burnus@gcc.gnu.org> + +type t + integer :: i +end type t +type, extends(t) :: t2 + integer :: j +end type t2 + +class(t), allocatable :: a +allocate(a, source=t2(1,2)) +print *,a%i +if(a%i /= 1) call abort() +select type (a) + type is (t2) + print *,a%j + if(a%j /= 2) call abort() +end select +end diff --git a/gcc/testsuite/gfortran.dg/extends_8.f03 b/gcc/testsuite/gfortran.dg/extends_8.f03 new file mode 100644 index 00000000000..4af5ab9327c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/extends_8.f03 @@ -0,0 +1,17 @@ +! { dg-do compile } +! +! PR 41784: [OOP] ICE in load_derived_extensions +! +! Contributed by Salvatore Filippone <sfilippone@uniroma2.it> + +module m + type :: A + end type + type, extends(A) :: B + end type +end module + +use m, only: A +end + +! { dg-final { cleanup-modules "m" } } diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index f8e83ec0988..51a6a397386 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -501,6 +501,7 @@ proc check_profiling_available { test_what } { || [istarget mep-*-elf] || [istarget mips*-*-elf*] || [istarget moxie-*-elf*] + || [istarget rx-*-*] || [istarget xstormy16-*] || [istarget xtensa*-*-elf] || [istarget *-*-rtems*] @@ -686,6 +687,18 @@ proc check_effective_target_hard_float { } { }] } + # This proc is actually checking the availabilty of FPU + # support for doubles, so on the RX we must fail if the + # 64-bit double multilib has been selected. + if { [istarget rx-*-*] } { + return 0 + # return [check_no_compiler_messages hard_float assembly { + #if defined __RX_64_BIT_DOUBLES__ + #error FOO + #endif + # }] + } + # The generic test equates hard_float with "no call for adding doubles". return [check_no_messages_and_pattern hard_float "!\\(call" rtl-expand { double a (double b, double c) { return b + c; } @@ -2505,8 +2518,8 @@ proc check_effective_target_vect_short_mult { } { if { [istarget ia64-*-*] || [istarget spu-*-*] || [istarget i?86-*-*] - || [istarget x86_64-*-*] - || [istarget powerpc*-*-*] + || [istarget x86_64-*-*] + || [istarget powerpc*-*-*] || [check_effective_target_arm32] } { set et_vect_short_mult_saved 1 } @@ -2646,7 +2659,7 @@ proc check_effective_target_section_anchors { } { verbose "check_effective_target_section_anchors: using cached result" 2 } else { set et_section_anchors_saved 0 - if { [istarget powerpc*-*-*] + if { [istarget powerpc*-*-*] || [istarget arm*-*-*] } { set et_section_anchors_saved 1 } diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 4a34cefd2a4..97b08924ff7 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -3107,6 +3107,21 @@ verify_gimple_assign_unary (gimple stmt) return false; } + case ADDR_SPACE_CONVERT_EXPR: + { + if (!POINTER_TYPE_P (rhs1_type) || !POINTER_TYPE_P (lhs_type) + || (TYPE_ADDR_SPACE (TREE_TYPE (rhs1_type)) + == TYPE_ADDR_SPACE (TREE_TYPE (lhs_type)))) + { + error ("invalid types in address space conversion"); + debug_generic_expr (lhs_type); + debug_generic_expr (rhs1_type); + return true; + } + + return false; + } + case FIXED_CONVERT_EXPR: { if (!valid_fixed_convert_types_p (lhs_type, rhs1_type) diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 85f1f5ef60a..a7015691811 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -890,7 +890,8 @@ extern void tree_check_data_deps (void); /* In tree-ssa-loop-ivopts.c */ bool expr_invariant_in_loop_p (struct loop *, tree); bool stmt_invariant_in_loop_p (struct loop *, gimple); -bool multiplier_allowed_in_address_p (HOST_WIDE_INT, enum machine_mode); +bool multiplier_allowed_in_address_p (HOST_WIDE_INT, enum machine_mode, + addr_space_t); unsigned multiply_by_cost (HOST_WIDE_INT, enum machine_mode, bool); /* In tree-ssa-threadupdate.c. */ @@ -921,7 +922,7 @@ struct mem_address struct affine_tree_combination; tree create_mem_ref (gimple_stmt_iterator *, tree, struct affine_tree_combination *, bool); -rtx addr_for_mem_ref (struct mem_address *, bool); +rtx addr_for_mem_ref (struct mem_address *, addr_space_t, bool); void get_address_description (tree, struct mem_address *); tree maybe_fold_tmr (tree); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 91ed023312a..f0ed4ba73a7 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -3083,6 +3083,7 @@ estimate_operator_cost (enum tree_code code, eni_weights *weights, case MINUS_EXPR: case MULT_EXPR: + case ADDR_SPACE_CONVERT_EXPR: case FIXED_CONVERT_EXPR: case FIX_TRUNC_EXPR: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index cfc20a178ea..7173ad2331b 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -657,6 +657,13 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, else if (quals & TYPE_QUAL_RESTRICT) pp_string (buffer, "restrict "); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) + { + pp_string (buffer, "<address-space-"); + pp_decimal_int (buffer, TYPE_ADDR_SPACE (node)); + pp_string (buffer, "> "); + } + tclass = TREE_CODE_CLASS (TREE_CODE (node)); if (tclass == tcc_declaration) @@ -755,6 +762,13 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, if (quals & TYPE_QUAL_RESTRICT) pp_string (buffer, " restrict"); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) + { + pp_string (buffer, " <address-space-"); + pp_decimal_int (buffer, TYPE_ADDR_SPACE (node)); + pp_string (buffer, ">"); + } + if (TYPE_REF_CAN_ALIAS_ALL (node)) pp_string (buffer, " {ref-all}"); } @@ -1550,6 +1564,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, NIY; break; + case ADDR_SPACE_CONVERT_EXPR: case FIXED_CONVERT_EXPR: case FIX_TRUNC_EXPR: case FLOAT_EXPR: diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c index 7a2ba399172..1428803272f 100644 --- a/gcc/tree-ssa-address.c +++ b/gcc/tree-ssa-address.c @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "expr.h" #include "ggc.h" #include "tree-affine.h" +#include "target.h" /* TODO -- handling of symbols (according to Richard Hendersons comments, http://gcc.gnu.org/ml/gcc-patches/2005-04/msg00949.html): @@ -70,32 +71,38 @@ along with GCC; see the file COPYING3. If not see /* A "template" for memory address, used to determine whether the address is valid for mode. */ -struct GTY (()) mem_addr_template { +typedef struct GTY (()) mem_addr_template { rtx ref; /* The template. */ rtx * GTY ((skip)) step_p; /* The point in template where the step should be filled in. */ rtx * GTY ((skip)) off_p; /* The point in template where the offset should be filled in. */ -}; +} mem_addr_template; -/* The templates. Each of the five bits of the index corresponds to one - component of TARGET_MEM_REF being present, see TEMPL_IDX. */ +DEF_VEC_O (mem_addr_template); +DEF_VEC_ALLOC_O (mem_addr_template, gc); -static GTY (()) struct mem_addr_template templates[32]; +/* The templates. Each of the low five bits of the index corresponds to one + component of TARGET_MEM_REF being present, while the high bits identify + the address space. See TEMPL_IDX. */ -#define TEMPL_IDX(SYMBOL, BASE, INDEX, STEP, OFFSET) \ - (((SYMBOL != 0) << 4) \ +static GTY(()) VEC (mem_addr_template, gc) *mem_addr_template_list; + +#define TEMPL_IDX(AS, SYMBOL, BASE, INDEX, STEP, OFFSET) \ + (((int) (AS) << 5) \ + | ((SYMBOL != 0) << 4) \ | ((BASE != 0) << 3) \ | ((INDEX != 0) << 2) \ | ((STEP != 0) << 1) \ | (OFFSET != 0)) /* Stores address for memory reference with parameters SYMBOL, BASE, INDEX, - STEP and OFFSET to *ADDR. Stores pointers to where step is placed to - *STEP_P and offset to *OFFSET_P. */ + STEP and OFFSET to *ADDR using address mode ADDRESS_MODE. Stores pointers + to where step is placed to *STEP_P and offset to *OFFSET_P. */ static void -gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, +gen_addr_rtx (enum machine_mode address_mode, + rtx symbol, rtx base, rtx index, rtx step, rtx offset, rtx *addr, rtx **step_p, rtx **offset_p) { rtx act_elem; @@ -111,7 +118,7 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, act_elem = index; if (step) { - act_elem = gen_rtx_MULT (Pmode, act_elem, step); + act_elem = gen_rtx_MULT (address_mode, act_elem, step); if (step_p) *step_p = &XEXP (act_elem, 1); @@ -123,7 +130,7 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, if (base) { if (*addr) - *addr = simplify_gen_binary (PLUS, Pmode, base, *addr); + *addr = simplify_gen_binary (PLUS, address_mode, base, *addr); else *addr = base; } @@ -133,7 +140,7 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, act_elem = symbol; if (offset) { - act_elem = gen_rtx_PLUS (Pmode, act_elem, offset); + act_elem = gen_rtx_PLUS (address_mode, act_elem, offset); if (offset_p) *offset_p = &XEXP (act_elem, 1); @@ -141,11 +148,11 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, if (GET_CODE (symbol) == SYMBOL_REF || GET_CODE (symbol) == LABEL_REF || GET_CODE (symbol) == CONST) - act_elem = gen_rtx_CONST (Pmode, act_elem); + act_elem = gen_rtx_CONST (address_mode, act_elem); } if (*addr) - *addr = gen_rtx_PLUS (Pmode, *addr, act_elem); + *addr = gen_rtx_PLUS (address_mode, *addr, act_elem); else *addr = act_elem; } @@ -153,7 +160,7 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, { if (*addr) { - *addr = gen_rtx_PLUS (Pmode, *addr, offset); + *addr = gen_rtx_PLUS (address_mode, *addr, offset); if (offset_p) *offset_p = &XEXP (*addr, 1); } @@ -169,55 +176,64 @@ gen_addr_rtx (rtx symbol, rtx base, rtx index, rtx step, rtx offset, *addr = const0_rtx; } -/* Returns address for TARGET_MEM_REF with parameters given by ADDR. +/* Returns address for TARGET_MEM_REF with parameters given by ADDR + in address space AS. If REALLY_EXPAND is false, just make fake registers instead of really expanding the operands, and perform the expansion in-place by using one of the "templates". */ rtx -addr_for_mem_ref (struct mem_address *addr, bool really_expand) +addr_for_mem_ref (struct mem_address *addr, addr_space_t as, + bool really_expand) { + enum machine_mode address_mode = targetm.addr_space.address_mode (as); rtx address, sym, bse, idx, st, off; - static bool templates_initialized = false; struct mem_addr_template *templ; if (addr->step && !integer_onep (addr->step)) st = immed_double_const (TREE_INT_CST_LOW (addr->step), - TREE_INT_CST_HIGH (addr->step), Pmode); + TREE_INT_CST_HIGH (addr->step), address_mode); else st = NULL_RTX; if (addr->offset && !integer_zerop (addr->offset)) off = immed_double_const (TREE_INT_CST_LOW (addr->offset), - TREE_INT_CST_HIGH (addr->offset), Pmode); + TREE_INT_CST_HIGH (addr->offset), address_mode); else off = NULL_RTX; if (!really_expand) { + unsigned int templ_index + = TEMPL_IDX (as, addr->symbol, addr->base, addr->index, st, off); + + if (templ_index + >= VEC_length (mem_addr_template, mem_addr_template_list)) + VEC_safe_grow_cleared (mem_addr_template, gc, mem_addr_template_list, + templ_index + 1); + /* Reuse the templates for addresses, so that we do not waste memory. */ - if (!templates_initialized) + templ = VEC_index (mem_addr_template, mem_addr_template_list, templ_index); + if (!templ->ref) { - unsigned i; - - templates_initialized = true; - sym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("test_symbol")); - bse = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1); - idx = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2); - - for (i = 0; i < 32; i++) - gen_addr_rtx ((i & 16 ? sym : NULL_RTX), - (i & 8 ? bse : NULL_RTX), - (i & 4 ? idx : NULL_RTX), - (i & 2 ? const0_rtx : NULL_RTX), - (i & 1 ? const0_rtx : NULL_RTX), - &templates[i].ref, - &templates[i].step_p, - &templates[i].off_p); + sym = (addr->symbol ? + gen_rtx_SYMBOL_REF (address_mode, ggc_strdup ("test_symbol")) + : NULL_RTX); + bse = (addr->base ? + gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1) + : NULL_RTX); + idx = (addr->index ? + gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2) + : NULL_RTX); + + gen_addr_rtx (address_mode, sym, bse, idx, + st? const0_rtx : NULL_RTX, + off? const0_rtx : NULL_RTX, + &templ->ref, + &templ->step_p, + &templ->off_p); } - templ = templates + TEMPL_IDX (addr->symbol, addr->base, addr->index, - st, off); if (st) *templ->step_p = st; if (off) @@ -229,16 +245,16 @@ addr_for_mem_ref (struct mem_address *addr, bool really_expand) /* Otherwise really expand the expressions. */ sym = (addr->symbol ? expand_expr (build_addr (addr->symbol, current_function_decl), - NULL_RTX, Pmode, EXPAND_NORMAL) + NULL_RTX, address_mode, EXPAND_NORMAL) : NULL_RTX); bse = (addr->base - ? expand_expr (addr->base, NULL_RTX, Pmode, EXPAND_NORMAL) + ? expand_expr (addr->base, NULL_RTX, address_mode, EXPAND_NORMAL) : NULL_RTX); idx = (addr->index - ? expand_expr (addr->index, NULL_RTX, Pmode, EXPAND_NORMAL) + ? expand_expr (addr->index, NULL_RTX, address_mode, EXPAND_NORMAL) : NULL_RTX); - gen_addr_rtx (sym, bse, idx, st, off, &address, NULL, NULL); + gen_addr_rtx (address_mode, sym, bse, idx, st, off, &address, NULL, NULL); return address; } @@ -305,15 +321,16 @@ tree_mem_ref_addr (tree type, tree mem_ref) ADDR is valid on the current target. */ static bool -valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr) +valid_mem_ref_p (enum machine_mode mode, addr_space_t as, + struct mem_address *addr) { rtx address; - address = addr_for_mem_ref (addr, false); + address = addr_for_mem_ref (addr, as, false); if (!address) return false; - return memory_address_p (mode, address); + return memory_address_addr_space_p (mode, address, as); } /* Checks whether a TARGET_MEM_REF with type TYPE and parameters given by ADDR @@ -323,7 +340,7 @@ valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr) static tree create_mem_ref_raw (tree type, struct mem_address *addr) { - if (!valid_mem_ref_p (TYPE_MODE (type), addr)) + if (!valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), addr)) return NULL_TREE; if (addr->step && integer_onep (addr->step)) @@ -456,7 +473,8 @@ most_expensive_mult_to_index (struct mem_address *parts, aff_tree *addr, coef = double_int_to_shwi (addr->elts[i].coef); if (coef == 1 - || !multiplier_allowed_in_address_p (coef, Pmode)) + || !multiplier_allowed_in_address_p (coef, Pmode, + ADDR_SPACE_GENERIC)) continue; acost = multiply_by_cost (coef, Pmode, speed); diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index ba5cbbc9488..fbd047085da 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -1313,8 +1313,6 @@ stmt_may_clobber_ref_p (gimple stmt, tree ref) } -static tree get_continuation_for_phi (gimple, ao_ref *, bitmap *); - /* Walk the virtual use-def chain of VUSE until hitting the virtual operand TARGET or a statement clobbering the memory reference REF in which case false is returned. The walk starts with VUSE, one argument of PHI. */ @@ -1358,7 +1356,7 @@ maybe_skip_until (gimple phi, tree target, ao_ref *ref, clobber REF. Returns NULL_TREE if no suitable virtual operand can be found. */ -static tree +tree get_continuation_for_phi (gimple phi, ao_ref *ref, bitmap *visited) { unsigned nargs = gimple_phi_num_args (phi); @@ -1375,6 +1373,7 @@ get_continuation_for_phi (gimple phi, ao_ref *ref, bitmap *visited) tree arg1 = PHI_ARG_DEF (phi, 1); gimple def0 = SSA_NAME_DEF_STMT (arg0); gimple def1 = SSA_NAME_DEF_STMT (arg1); + tree common_vuse; if (arg0 == arg1) return arg0; @@ -1393,6 +1392,26 @@ get_continuation_for_phi (gimple phi, ao_ref *ref, bitmap *visited) if (maybe_skip_until (phi, arg1, ref, arg0, visited)) return arg1; } + /* Special case of a diamond: + MEM_1 = ... + goto (cond) ? L1 : L2 + L1: store1 = ... #MEM_2 = vuse(MEM_1) + goto L3 + L2: store2 = ... #MEM_3 = vuse(MEM_1) + L3: MEM_4 = PHI<MEM_2, MEM_3> + We were called with the PHI at L3, MEM_2 and MEM_3 don't + dominate each other, but still we can easily skip this PHI node + if we recognize that the vuse MEM operand is the same for both, + and that we can skip both statements (they don't clobber us). + This is still linear. Don't use maybe_skip_until, that might + potentially be slow. */ + else if ((common_vuse = gimple_vuse (def0)) + && common_vuse == gimple_vuse (def1)) + { + if (!stmt_may_clobber_ref_p_1 (def0, ref) + && !stmt_may_clobber_ref_p_1 (def1, ref)) + return common_vuse; + } } return NULL_TREE; diff --git a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h index 49706925836..289fb86d04c 100644 --- a/gcc/tree-ssa-alias.h +++ b/gcc/tree-ssa-alias.h @@ -99,6 +99,7 @@ extern bool refs_output_dependent_p (tree, tree); extern bool ref_maybe_used_by_stmt_p (gimple, tree); extern bool stmt_may_clobber_ref_p (gimple, tree); extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *); +extern tree get_continuation_for_phi (gimple, ao_ref *, bitmap *); extern void *walk_non_aliased_vuses (ao_ref *, tree, void *(*)(ao_ref *, tree, void *), void *(*)(ao_ref *, tree, void *), void *); diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 42b2ef36252..82e45d2db4d 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -2642,21 +2642,25 @@ seq_cost (rtx seq, bool speed) static rtx produce_memory_decl_rtl (tree obj, int *regno) { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (obj)); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); rtx x; gcc_assert (obj); if (TREE_STATIC (obj) || DECL_EXTERNAL (obj)) { const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (obj)); - x = gen_rtx_SYMBOL_REF (Pmode, name); + x = gen_rtx_SYMBOL_REF (address_mode, name); SET_SYMBOL_REF_DECL (x, obj); x = gen_rtx_MEM (DECL_MODE (obj), x); + set_mem_addr_space (x, as); targetm.encode_section_info (obj, x, true); } else { - x = gen_raw_REG (Pmode, (*regno)++); + x = gen_raw_REG (address_mode, (*regno)++); x = gen_rtx_MEM (DECL_MODE (obj), x); + set_mem_addr_space (x, as); } return x; @@ -2744,7 +2748,8 @@ computation_cost (tree expr, bool speed) cost = seq_cost (seq, speed); if (MEM_P (rslt)) - cost += address_cost (XEXP (rslt, 0), TYPE_MODE (type), speed); + cost += address_cost (XEXP (rslt, 0), TYPE_MODE (type), + TYPE_ADDR_SPACE (type), speed); return cost; } @@ -3020,51 +3025,65 @@ multiply_by_cost (HOST_WIDE_INT cst, enum machine_mode mode, bool speed) } /* Returns true if multiplying by RATIO is allowed in an address. Test the - validity for a memory reference accessing memory of mode MODE. */ + validity for a memory reference accessing memory of mode MODE in + address space AS. */ + +DEF_VEC_P (sbitmap); +DEF_VEC_ALLOC_P (sbitmap, heap); bool -multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, enum machine_mode mode) +multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, enum machine_mode mode, + addr_space_t as) { #define MAX_RATIO 128 - static sbitmap valid_mult[MAX_MACHINE_MODE]; - - if (!valid_mult[mode]) + unsigned int data_index = (int) as * MAX_MACHINE_MODE + (int) mode; + static VEC (sbitmap, heap) *valid_mult_list; + sbitmap valid_mult; + + if (data_index >= VEC_length (sbitmap, valid_mult_list)) + VEC_safe_grow_cleared (sbitmap, heap, valid_mult_list, data_index + 1); + + valid_mult = VEC_index (sbitmap, valid_mult_list, data_index); + if (!valid_mult) { - rtx reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); + rtx reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1); rtx addr; HOST_WIDE_INT i; - valid_mult[mode] = sbitmap_alloc (2 * MAX_RATIO + 1); - sbitmap_zero (valid_mult[mode]); - addr = gen_rtx_fmt_ee (MULT, Pmode, reg1, NULL_RTX); + valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1); + sbitmap_zero (valid_mult); + addr = gen_rtx_fmt_ee (MULT, address_mode, reg1, NULL_RTX); for (i = -MAX_RATIO; i <= MAX_RATIO; i++) { - XEXP (addr, 1) = gen_int_mode (i, Pmode); - if (memory_address_p (mode, addr)) - SET_BIT (valid_mult[mode], i + MAX_RATIO); + XEXP (addr, 1) = gen_int_mode (i, address_mode); + if (memory_address_addr_space_p (mode, addr, as)) + SET_BIT (valid_mult, i + MAX_RATIO); } if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, " allowed multipliers:"); for (i = -MAX_RATIO; i <= MAX_RATIO; i++) - if (TEST_BIT (valid_mult[mode], i + MAX_RATIO)) + if (TEST_BIT (valid_mult, i + MAX_RATIO)) fprintf (dump_file, " %d", (int) i); fprintf (dump_file, "\n"); fprintf (dump_file, "\n"); } + + VEC_replace (sbitmap, valid_mult_list, data_index, valid_mult); } if (ratio > MAX_RATIO || ratio < -MAX_RATIO) return false; - return TEST_BIT (valid_mult[mode], ratio + MAX_RATIO); + return TEST_BIT (valid_mult, ratio + MAX_RATIO); } /* Returns cost of address in shape symbol + var + OFFSET + RATIO * index. If SYMBOL_PRESENT is false, symbol is omitted. If VAR_PRESENT is false, variable is omitted. Compute the cost for a memory reference that accesses - a memory location of mode MEM_MODE. + a memory location of mode MEM_MODE in address space AS. MAY_AUTOINC is set to true if the autoincrement (increasing index by size of MEM_MODE / RATIO) is available. To make this determination, we @@ -3075,16 +3094,26 @@ multiplier_allowed_in_address_p (HOST_WIDE_INT ratio, enum machine_mode mode) TODO -- there must be some better way. This all is quite crude. */ +typedef struct +{ + HOST_WIDE_INT min_offset, max_offset; + unsigned costs[2][2][2][2]; +} *address_cost_data; + +DEF_VEC_P (address_cost_data); +DEF_VEC_ALLOC_P (address_cost_data, heap); + static comp_cost get_address_cost (bool symbol_present, bool var_present, unsigned HOST_WIDE_INT offset, HOST_WIDE_INT ratio, - HOST_WIDE_INT cstep, enum machine_mode mem_mode, bool speed, + HOST_WIDE_INT cstep, enum machine_mode mem_mode, + addr_space_t as, bool speed, bool stmt_after_inc, bool *may_autoinc) { - static bool initialized[MAX_MACHINE_MODE]; - static HOST_WIDE_INT rat[MAX_MACHINE_MODE], off[MAX_MACHINE_MODE]; - static HOST_WIDE_INT min_offset[MAX_MACHINE_MODE], max_offset[MAX_MACHINE_MODE]; - static unsigned costs[MAX_MACHINE_MODE][2][2][2][2]; + enum machine_mode address_mode = targetm.addr_space.address_mode (as); + static VEC(address_cost_data, heap) *address_cost_data_list; + unsigned int data_index = (int) as * MAX_MACHINE_MODE + (int) mem_mode; + address_cost_data data; static bool has_preinc[MAX_MACHINE_MODE], has_postinc[MAX_MACHINE_MODE]; static bool has_predec[MAX_MACHINE_MODE], has_postdec[MAX_MACHINE_MODE]; unsigned cost, acost, complexity; @@ -3093,80 +3122,90 @@ get_address_cost (bool symbol_present, bool var_present, unsigned HOST_WIDE_INT mask; unsigned bits; - if (!initialized[mem_mode]) + if (data_index >= VEC_length (address_cost_data, address_cost_data_list)) + VEC_safe_grow_cleared (address_cost_data, heap, address_cost_data_list, + data_index + 1); + + data = VEC_index (address_cost_data, address_cost_data_list, data_index); + if (!data) { HOST_WIDE_INT i; HOST_WIDE_INT start = BIGGEST_ALIGNMENT / BITS_PER_UNIT; + HOST_WIDE_INT rat, off; int old_cse_not_expected; unsigned sym_p, var_p, off_p, rat_p, add_c; rtx seq, addr, base; rtx reg0, reg1; - initialized[mem_mode] = true; + data = (address_cost_data) xcalloc (1, sizeof (*data)); - reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1); + reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1); - addr = gen_rtx_fmt_ee (PLUS, Pmode, reg1, NULL_RTX); + addr = gen_rtx_fmt_ee (PLUS, address_mode, reg1, NULL_RTX); for (i = start; i <= 1 << 20; i <<= 1) { - XEXP (addr, 1) = gen_int_mode (i, Pmode); - if (!memory_address_p (mem_mode, addr)) + XEXP (addr, 1) = gen_int_mode (i, address_mode); + if (!memory_address_addr_space_p (mem_mode, addr, as)) break; } - max_offset[mem_mode] = i == start ? 0 : i >> 1; - off[mem_mode] = max_offset[mem_mode]; + data->max_offset = i == start ? 0 : i >> 1; + off = data->max_offset; for (i = start; i <= 1 << 20; i <<= 1) { - XEXP (addr, 1) = gen_int_mode (-i, Pmode); - if (!memory_address_p (mem_mode, addr)) + XEXP (addr, 1) = gen_int_mode (-i, address_mode); + if (!memory_address_addr_space_p (mem_mode, addr, as)) break; } - min_offset[mem_mode] = i == start ? 0 : -(i >> 1); + data->min_offset = i == start ? 0 : -(i >> 1); if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "get_address_cost:\n"); fprintf (dump_file, " min offset %s %d\n", GET_MODE_NAME (mem_mode), - (int) min_offset[mem_mode]); + (int) data->min_offset); fprintf (dump_file, " max offset %s %d\n", GET_MODE_NAME (mem_mode), - (int) max_offset[mem_mode]); + (int) data->max_offset); } - rat[mem_mode] = 1; + rat = 1; for (i = 2; i <= MAX_RATIO; i++) - if (multiplier_allowed_in_address_p (i, mem_mode)) + if (multiplier_allowed_in_address_p (i, mem_mode, as)) { - rat[mem_mode] = i; + rat = i; break; } /* Compute the cost of various addressing modes. */ acost = 0; - reg0 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1); - reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 2); + reg0 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 1); + reg1 = gen_raw_REG (address_mode, LAST_VIRTUAL_REGISTER + 2); if (HAVE_PRE_DECREMENT) { - addr = gen_rtx_PRE_DEC (Pmode, reg0); - has_predec[mem_mode] = memory_address_p (mem_mode, addr); + addr = gen_rtx_PRE_DEC (address_mode, reg0); + has_predec[mem_mode] + = memory_address_addr_space_p (mem_mode, addr, as); } if (HAVE_POST_DECREMENT) { - addr = gen_rtx_POST_DEC (Pmode, reg0); - has_postdec[mem_mode] = memory_address_p (mem_mode, addr); + addr = gen_rtx_POST_DEC (address_mode, reg0); + has_postdec[mem_mode] + = memory_address_addr_space_p (mem_mode, addr, as); } if (HAVE_PRE_INCREMENT) { - addr = gen_rtx_PRE_INC (Pmode, reg0); - has_preinc[mem_mode] = memory_address_p (mem_mode, addr); + addr = gen_rtx_PRE_INC (address_mode, reg0); + has_preinc[mem_mode] + = memory_address_addr_space_p (mem_mode, addr, as); } if (HAVE_POST_INCREMENT) { - addr = gen_rtx_POST_INC (Pmode, reg0); - has_postinc[mem_mode] = memory_address_p (mem_mode, addr); + addr = gen_rtx_POST_INC (address_mode, reg0); + has_postinc[mem_mode] + = memory_address_addr_space_p (mem_mode, addr, as); } for (i = 0; i < 16; i++) { @@ -3177,15 +3216,15 @@ get_address_cost (bool symbol_present, bool var_present, addr = reg0; if (rat_p) - addr = gen_rtx_fmt_ee (MULT, Pmode, addr, - gen_int_mode (rat[mem_mode], Pmode)); + addr = gen_rtx_fmt_ee (MULT, address_mode, addr, + gen_int_mode (rat, address_mode)); if (var_p) - addr = gen_rtx_fmt_ee (PLUS, Pmode, addr, reg1); + addr = gen_rtx_fmt_ee (PLUS, address_mode, addr, reg1); if (sym_p) { - base = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup ("")); + base = gen_rtx_SYMBOL_REF (address_mode, ggc_strdup ("")); /* ??? We can run into trouble with some backends by presenting it with symbols which haven't been properly passed through targetm.encode_section_info. By setting the local bit, we @@ -3193,36 +3232,35 @@ get_address_cost (bool symbol_present, bool var_present, SYMBOL_REF_FLAGS (base) = SYMBOL_FLAG_LOCAL; if (off_p) - base = gen_rtx_fmt_e (CONST, Pmode, - gen_rtx_fmt_ee (PLUS, Pmode, - base, - gen_int_mode (off[mem_mode], - Pmode))); + base = gen_rtx_fmt_e (CONST, address_mode, + gen_rtx_fmt_ee + (PLUS, address_mode, base, + gen_int_mode (off, address_mode))); } else if (off_p) - base = gen_int_mode (off[mem_mode], Pmode); + base = gen_int_mode (off, address_mode); else base = NULL_RTX; if (base) - addr = gen_rtx_fmt_ee (PLUS, Pmode, addr, base); + addr = gen_rtx_fmt_ee (PLUS, address_mode, addr, base); start_sequence (); /* To avoid splitting addressing modes, pretend that no cse will follow. */ old_cse_not_expected = cse_not_expected; cse_not_expected = true; - addr = memory_address (mem_mode, addr); + addr = memory_address_addr_space (mem_mode, addr, as); cse_not_expected = old_cse_not_expected; seq = get_insns (); end_sequence (); acost = seq_cost (seq, speed); - acost += address_cost (addr, mem_mode, speed); + acost += address_cost (addr, mem_mode, as, speed); if (!acost) acost = 1; - costs[mem_mode][sym_p][var_p][off_p][rat_p] = acost; + data->costs[sym_p][var_p][off_p][rat_p] = acost; } /* On some targets, it is quite expensive to load symbol to a register, @@ -3237,19 +3275,19 @@ get_address_cost (bool symbol_present, bool var_present, If VAR_PRESENT is true, try whether the mode with SYMBOL_PRESENT = false is cheaper even with cost of addition, and if this is the case, use it. */ - add_c = add_cost (Pmode, speed); + add_c = add_cost (address_mode, speed); for (i = 0; i < 8; i++) { var_p = i & 1; off_p = (i >> 1) & 1; rat_p = (i >> 2) & 1; - acost = costs[mem_mode][0][1][off_p][rat_p] + 1; + acost = data->costs[0][1][off_p][rat_p] + 1; if (var_p) acost += add_c; - if (acost < costs[mem_mode][1][var_p][off_p][rat_p]) - costs[mem_mode][1][var_p][off_p][rat_p] = acost; + if (acost < data->costs[1][var_p][off_p][rat_p]) + data->costs[1][var_p][off_p][rat_p] = acost; } if (dump_file && (dump_flags & TDF_DETAILS)) @@ -3273,7 +3311,7 @@ get_address_cost (bool symbol_present, bool var_present, if (rat_p) fprintf (dump_file, "rat * "); - acost = costs[mem_mode][sym_p][var_p][off_p][rat_p]; + acost = data->costs[sym_p][var_p][off_p][rat_p]; fprintf (dump_file, "index costs %d\n", acost); } if (has_predec[mem_mode] || has_postdec[mem_mode] @@ -3281,9 +3319,12 @@ get_address_cost (bool symbol_present, bool var_present, fprintf (dump_file, " May include autoinc/dec\n"); fprintf (dump_file, "\n"); } + + VEC_replace (address_cost_data, address_cost_data_list, + data_index, data); } - bits = GET_MODE_BITSIZE (Pmode); + bits = GET_MODE_BITSIZE (address_mode); mask = ~(~(unsigned HOST_WIDE_INT) 0 << (bits - 1) << 1); offset &= mask; if ((offset >> (bits - 1) & 1)) @@ -3309,20 +3350,20 @@ get_address_cost (bool symbol_present, bool var_present, cost = 0; offset_p = (s_offset != 0 - && min_offset[mem_mode] <= s_offset - && s_offset <= max_offset[mem_mode]); + && data->min_offset <= s_offset + && s_offset <= data->max_offset); ratio_p = (ratio != 1 - && multiplier_allowed_in_address_p (ratio, mem_mode)); + && multiplier_allowed_in_address_p (ratio, mem_mode, as)); if (ratio != 1 && !ratio_p) - cost += multiply_by_cost (ratio, Pmode, speed); + cost += multiply_by_cost (ratio, address_mode, speed); if (s_offset && !offset_p && !symbol_present) - cost += add_cost (Pmode, speed); + cost += add_cost (address_mode, speed); if (may_autoinc) *may_autoinc = autoinc; - acost = costs[mem_mode][symbol_present][var_present][offset_p][ratio_p]; + acost = data->costs[symbol_present][var_present][offset_p][ratio_p]; complexity = (symbol_present != 0) + (var_present != 0) + offset_p + ratio_p; return new_cost (cost + acost, complexity); } @@ -3742,8 +3783,9 @@ get_computation_cost_at (struct ivopts_data *data, } else if (address_p && !POINTER_TYPE_P (ctype) - && multiplier_allowed_in_address_p (ratio, - TYPE_MODE (TREE_TYPE (utype)))) + && multiplier_allowed_in_address_p + (ratio, TYPE_MODE (TREE_TYPE (utype)), + TYPE_ADDR_SPACE (TREE_TYPE (utype)))) { cbase = fold_build2 (MULT_EXPR, ctype, cbase, build_int_cst (ctype, ratio)); @@ -3777,6 +3819,7 @@ get_computation_cost_at (struct ivopts_data *data, get_address_cost (symbol_present, var_present, offset, ratio, cstepi, TYPE_MODE (TREE_TYPE (utype)), + TYPE_ADDR_SPACE (TREE_TYPE (utype)), speed, stmt_is_after_inc, can_autoinc)); diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 6ae05b5a866..2ef6d76a40a 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -1243,43 +1243,74 @@ do_unary: } /* Translate the VUSE backwards through phi nodes in PHIBLOCK, so that - it has the value it would have in BLOCK. */ + it has the value it would have in BLOCK. Set *SAME_VALID to true + in case the new vuse doesn't change the value id of the OPERANDS. */ static tree translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands, alias_set_type set, tree type, tree vuse, basic_block phiblock, - basic_block block) + basic_block block, bool *same_valid) { gimple phi = SSA_NAME_DEF_STMT (vuse); ao_ref ref; + edge e = NULL; + bool use_oracle; + + *same_valid = true; if (gimple_bb (phi) != phiblock) return vuse; - if (gimple_code (phi) == GIMPLE_PHI) - { - edge e = find_edge (block, phiblock); - return PHI_ARG_DEF (phi, e->dest_idx); - } - - if (!ao_ref_init_from_vn_reference (&ref, set, type, operands)) - return NULL_TREE; + use_oracle = ao_ref_init_from_vn_reference (&ref, set, type, operands); /* Use the alias-oracle to find either the PHI node in this block, the first VUSE used in this block that is equivalent to vuse or the first VUSE which definition in this block kills the value. */ - while (!stmt_may_clobber_ref_p_1 (phi, &ref)) + if (gimple_code (phi) == GIMPLE_PHI) + e = find_edge (block, phiblock); + else if (use_oracle) + while (!stmt_may_clobber_ref_p_1 (phi, &ref)) + { + vuse = gimple_vuse (phi); + phi = SSA_NAME_DEF_STMT (vuse); + if (gimple_bb (phi) != phiblock) + return vuse; + if (gimple_code (phi) == GIMPLE_PHI) + { + e = find_edge (block, phiblock); + break; + } + } + else + return NULL_TREE; + + if (e) { - vuse = gimple_vuse (phi); - phi = SSA_NAME_DEF_STMT (vuse); - if (gimple_bb (phi) != phiblock) - return vuse; - if (gimple_code (phi) == GIMPLE_PHI) + if (use_oracle) { - edge e = find_edge (block, phiblock); - return PHI_ARG_DEF (phi, e->dest_idx); + bitmap visited = NULL; + /* Try to find a vuse that dominates this phi node by skipping + non-clobbering statements. */ + vuse = get_continuation_for_phi (phi, &ref, &visited); + if (visited) + BITMAP_FREE (visited); } + else + vuse = NULL_TREE; + if (!vuse) + { + /* If we didn't find any, the value ID can't stay the same, + but return the translated vuse. */ + *same_valid = false; + vuse = PHI_ARG_DEF (phi, e->dest_idx); + } + /* ??? We would like to return vuse here as this is the canonical + upmost vdef that this reference is associated with. But during + insertion of the references into the hash tables we only ever + directly insert with their direct gimple_vuse, hence returning + something else would make us not find the other expression. */ + return PHI_ARG_DEF (phi, e->dest_idx); } return NULL_TREE; @@ -1541,7 +1572,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, tree vuse = ref->vuse; tree newvuse = vuse; VEC (vn_reference_op_s, heap) *newoperands = NULL; - bool changed = false; + bool changed = false, same_valid = true; unsigned int i, j; vn_reference_op_t operand; vn_reference_t newref; @@ -1647,16 +1678,16 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, { newvuse = translate_vuse_through_block (newoperands, ref->set, ref->type, - vuse, phiblock, pred); + vuse, phiblock, pred, + &same_valid); if (newvuse == NULL_TREE) { VEC_free (vn_reference_op_s, heap, newoperands); return NULL; } } - changed |= newvuse != vuse; - if (changed) + if (changed || newvuse != vuse) { unsigned int new_val_id; pre_expr constant; @@ -1690,9 +1721,15 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, } else { - new_val_id = get_next_value_id (); - VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions, - get_max_value_id() + 1); + if (changed || !same_valid) + { + new_val_id = get_next_value_id (); + VEC_safe_grow_cleared (bitmap_set_t, heap, + value_expressions, + get_max_value_id() + 1); + } + else + new_val_id = ref->value_id; newref = vn_reference_insert_pieces (newvuse, ref->set, ref->type, newoperands, @@ -3914,7 +3951,7 @@ compute_avail (void) vn_reference_lookup (gimple_assign_rhs1 (stmt), gimple_vuse (stmt), - false, &ref); + true, &ref); if (!ref) continue; diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index e5f4a292855..cc655df7cc6 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -2825,7 +2825,7 @@ static void get_constraint_for_ptr_offset (tree ptr, tree offset, VEC (ce_s, heap) **results) { - struct constraint_expr *c; + struct constraint_expr c; unsigned int j, n; HOST_WIDE_INT rhsunitoffset, rhsoffset; @@ -2863,14 +2863,14 @@ get_constraint_for_ptr_offset (tree ptr, tree offset, for (j = 0; j < n; j++) { varinfo_t curr; - c = VEC_index (ce_s, *results, j); - curr = get_varinfo (c->var); + c = *VEC_index (ce_s, *results, j); + curr = get_varinfo (c.var); - if (c->type == ADDRESSOF + if (c.type == ADDRESSOF /* If this varinfo represents a full variable just use it. */ && curr->is_full_var) - c->offset = 0; - else if (c->type == ADDRESSOF + c.offset = 0; + else if (c.type == ADDRESSOF /* If we do not know the offset add all subfields. */ && rhsoffset == UNKNOWN_OFFSET) { @@ -2881,13 +2881,13 @@ get_constraint_for_ptr_offset (tree ptr, tree offset, c2.var = temp->id; c2.type = ADDRESSOF; c2.offset = 0; - if (c2.var != c->var) + if (c2.var != c.var) VEC_safe_push (ce_s, heap, *results, &c2); temp = temp->next; } while (temp); } - else if (c->type == ADDRESSOF) + else if (c.type == ADDRESSOF) { varinfo_t temp; unsigned HOST_WIDE_INT offset = curr->offset + rhsoffset; @@ -2919,11 +2919,13 @@ get_constraint_for_ptr_offset (tree ptr, tree offset, c2.offset = 0; VEC_safe_push (ce_s, heap, *results, &c2); } - c->var = temp->id; - c->offset = 0; + c.var = temp->id; + c.offset = 0; } else - c->offset = rhsoffset; + c.offset = rhsoffset; + + VEC_replace (ce_s, *results, j, &c); } } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 9858b109d03..b646ded59e7 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -1192,6 +1192,11 @@ useless_type_conversion_p (tree outer_type, tree inner_type) if (POINTER_TYPE_P (inner_type) && POINTER_TYPE_P (outer_type)) { + /* Do not lose casts between pointers to different address spaces. */ + if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type)) + != TYPE_ADDR_SPACE (TREE_TYPE (inner_type))) + return false; + /* If the outer type is (void *) or a pointer to an incomplete record type or a pointer to an unprototyped function, then the conversion is not necessary. */ diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index c3570d31948..ea3a508966f 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -2376,7 +2376,9 @@ vect_create_data_ref_ptr (gimple stmt, struct loop *at_loop, if (!alias_sets_conflict_p (get_deref_alias_set (vect_ptr), get_alias_set (DR_REF (dr)))) { - vect_ptr_type = build_pointer_type_for_mode (vectype, ptr_mode, true); + vect_ptr_type + = build_pointer_type_for_mode (vectype, + TYPE_MODE (vect_ptr_type), true); vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var, get_name (base_name)); } @@ -2392,7 +2394,8 @@ vect_create_data_ref_ptr (gimple stmt, struct loop *at_loop, get_alias_set (lhs))) { vect_ptr_type - = build_pointer_type_for_mode (vectype, ptr_mode, true); + = build_pointer_type_for_mode (vectype, + TYPE_MODE (vect_ptr_type), true); vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var, get_name (base_name)); diff --git a/gcc/tree.c b/gcc/tree.c index 5da346c52f8..43434150231 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1684,8 +1684,7 @@ integer_pow2p (const_tree expr) if (TREE_CODE (expr) != INTEGER_CST) return 0; - prec = (POINTER_TYPE_P (TREE_TYPE (expr)) - ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr))); + prec = int_or_pointer_precision (TREE_TYPE (expr)); high = TREE_INT_CST_HIGH (expr); low = TREE_INT_CST_LOW (expr); @@ -1749,9 +1748,7 @@ tree_log2 (const_tree expr) if (TREE_CODE (expr) == COMPLEX_CST) return tree_log2 (TREE_REALPART (expr)); - prec = (POINTER_TYPE_P (TREE_TYPE (expr)) - ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr))); - + prec = int_or_pointer_precision (TREE_TYPE (expr)); high = TREE_INT_CST_HIGH (expr); low = TREE_INT_CST_LOW (expr); @@ -1787,9 +1784,7 @@ tree_floor_log2 (const_tree expr) if (TREE_CODE (expr) == COMPLEX_CST) return tree_log2 (TREE_REALPART (expr)); - prec = (POINTER_TYPE_P (TREE_TYPE (expr)) - ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr))); - + prec = int_or_pointer_precision (TREE_TYPE (expr)); high = TREE_INT_CST_HIGH (expr); low = TREE_INT_CST_LOW (expr); @@ -4648,11 +4643,15 @@ find_decls_types_r (tree *tp, int *ws, void *data) i, tem); ++i) fld_worklist_push (TREE_TYPE (tem), fld); tem = BINFO_VIRTUALS (TYPE_BINFO (t)); - while (tem) - { - fld_worklist_push (TREE_VALUE (tem), fld); - tem = TREE_CHAIN (tem); - } + if (tem + /* The Java FE overloads BINFO_VIRTUALS for its own purpose. */ + && TREE_CODE (tem) == TREE_LIST) + do + { + fld_worklist_push (TREE_VALUE (tem), fld); + tem = TREE_CHAIN (tem); + } + while (tem); } if (RECORD_OR_UNION_TYPE_P (t)) { @@ -5420,6 +5419,7 @@ set_type_quals (tree type, int type_quals) TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0; TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0; TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0; + TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals); } /* Returns true iff CAND is equivalent to BASE with TYPE_QUALS. */ @@ -6741,7 +6741,10 @@ build_pointer_type_for_mode (tree to_type, enum machine_mode mode, tree build_pointer_type (tree to_type) { - return build_pointer_type_for_mode (to_type, ptr_mode, false); + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as); + return build_pointer_type_for_mode (to_type, pointer_mode, false); } /* Same as build_pointer_type_for_mode, but for REFERENCE_TYPE. */ @@ -6805,7 +6808,10 @@ build_reference_type_for_mode (tree to_type, enum machine_mode mode, tree build_reference_type (tree to_type) { - return build_reference_type_for_mode (to_type, ptr_mode, false); + addr_space_t as = to_type == error_mark_node? ADDR_SPACE_GENERIC + : TYPE_ADDR_SPACE (to_type); + enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as); + return build_reference_type_for_mode (to_type, pointer_mode, false); } /* Build a type that is compatible with t but has no cv quals anywhere @@ -6999,6 +7005,7 @@ build_array_type (tree elt_type, tree index_type) t = make_node (ARRAY_TYPE); TREE_TYPE (t) = elt_type; TYPE_DOMAIN (t) = index_type; + TYPE_ADDR_SPACE (t) = TYPE_ADDR_SPACE (elt_type); layout_type (t); /* If the element type is incomplete at this point we get marked for @@ -9669,7 +9676,19 @@ signed_or_unsigned_type_for (int unsignedp, tree type) { tree t = type; if (POINTER_TYPE_P (type)) - t = size_type_node; + { + /* If the pointer points to the normal address space, use the + size_type_node. Otherwise use an appropriate size for the pointer + based on the named address space it points to. */ + if (!TYPE_ADDR_SPACE (TREE_TYPE (t))) + t = size_type_node; + + else + { + int prec = int_or_pointer_precision (t); + return lang_hooks.types.type_for_size (prec, unsignedp); + } + } if (!INTEGRAL_TYPE_P (t) || TYPE_UNSIGNED (t) == unsignedp) return t; @@ -10543,6 +10562,41 @@ build_target_option_node (void) return t; } +/* Return the size in bits of an integer or pointer type. TYPE_PRECISION + contains the bits, but in the past it was not set in some cases and there + was special purpose code that checked for POINTER_TYPE_P or OFFSET_TYPE, so + check that it is consitant when assertion checking is used. */ + +unsigned int +int_or_pointer_precision (const_tree type) +{ +#if ENABLE_ASSERT_CHECKING + unsigned int prec; + + if (POINTER_TYPE_P (type)) + { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); + prec = GET_MODE_BITSIZE (targetm.addr_space.pointer_mode (as)); + gcc_assert (prec == TYPE_PRECISION (type)); + } + else if (TREE_CODE (type) == OFFSET_TYPE) + { + prec = POINTER_SIZE; + gcc_assert (prec == TYPE_PRECISION (type)); + } + else + { + prec = TYPE_PRECISION (type); + gcc_assert (prec != 0); + } + + return prec; + +#else + return TYPE_PRECISION (type); +#endif +} + /* Determine the "ultimate origin" of a block. The block may be an inlined instance of an inlined instance of a block which is local to an inline function, so we have to trace all of the way back through the origin chain diff --git a/gcc/tree.def b/gcc/tree.def index 01d91b76a6f..74470b5783a 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -752,6 +752,10 @@ DEFTREECODE (PAREN_EXPR, "paren_expr", tcc_unary, 1) represented by CONVERT_EXPR or NOP_EXPR nodes. */ DEFTREECODE (CONVERT_EXPR, "convert_expr", tcc_unary, 1) +/* Conversion of a pointer value to a pointer to a different + address space. */ +DEFTREECODE (ADDR_SPACE_CONVERT_EXPR, "addr_space_convert_expr", tcc_unary, 1) + /* Conversion of a fixed-point value to an integer, a real, or a fixed-point value. Or conversion of a fixed-point value from an integer, a real, or a fixed-point value. */ diff --git a/gcc/tree.h b/gcc/tree.h index 2487a1ce9fe..36deb0d51e5 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -392,7 +392,12 @@ struct GTY(()) tree_base { unsigned packed_flag : 1; unsigned user_align : 1; - unsigned spare : 21; + unsigned spare : 13; + + /* This field is only used with type nodes; the only reason it is present + in tree_base instead of tree_type is to save space. The size of the + field must be large enough to hold addr_space_t values. */ + unsigned address_space : 8; union tree_ann_d *ann; }; @@ -2169,6 +2174,9 @@ extern enum machine_mode vector_type_mode (const_tree); the term. */ #define TYPE_RESTRICT(NODE) (TYPE_CHECK (NODE)->type.restrict_flag) +/* The address space the type is in. */ +#define TYPE_ADDR_SPACE(NODE) (TYPE_CHECK (NODE)->base.address_space) + /* There is a TYPE_QUAL value for each type qualifier. They can be combined by bitwise-or to form the complete set of qualifiers for a type. */ @@ -2178,10 +2186,29 @@ extern enum machine_mode vector_type_mode (const_tree); #define TYPE_QUAL_VOLATILE 0x2 #define TYPE_QUAL_RESTRICT 0x4 +/* Encode/decode the named memory support as part of the qualifier. If more + than 8 qualifiers are added, these macros need to be adjusted. */ +#define ENCODE_QUAL_ADDR_SPACE(NUM) ((NUM & 0xFF) << 8) +#define DECODE_QUAL_ADDR_SPACE(X) (((X) >> 8) & 0xFF) + +/* Return all qualifiers except for the address space qualifiers. */ +#define CLEAR_QUAL_ADDR_SPACE(X) ((X) & ~0xFF00) + +/* Only keep the address space out of the qualifiers and discard the other + qualifiers. */ +#define KEEP_QUAL_ADDR_SPACE(X) ((X) & 0xFF00) + /* The set of type qualifiers for this type. */ #define TYPE_QUALS(NODE) \ ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \ | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ + | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT) \ + | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE)))) + +/* The same as TYPE_QUALS without the address space qualifications. */ +#define TYPE_QUALS_NO_ADDR_SPACE(NODE) \ + ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST) \ + | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE) \ | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)) /* These flags are available for each language front end to use internally. */ @@ -4676,6 +4703,7 @@ extern const char *get_name (tree); extern bool stdarg_p (tree); extern bool prototype_p (tree); extern bool auto_var_in_fn_p (const_tree, const_tree); +extern unsigned int int_or_pointer_precision (const_tree); extern tree build_low_bits_mask (tree, unsigned); extern tree tree_strip_nop_conversions (tree); extern tree tree_strip_sign_nop_conversions (tree); diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index cfcc839b96c..9fa19219186 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -4359,7 +4359,9 @@ replace_expr_with_values (rtx loc) return NULL; else if (MEM_P (loc)) { - cselib_val *addr = cselib_lookup (XEXP (loc, 0), Pmode, 0); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (loc)); + cselib_val *addr = cselib_lookup (XEXP (loc, 0), address_mode, 0); if (addr) return replace_equiv_address_nv (loc, addr->val_rtx); else @@ -4493,7 +4495,9 @@ count_uses (rtx *loc, void *cuip) if (MEM_P (*loc) && !REG_P (XEXP (*loc, 0)) && !MEM_P (XEXP (*loc, 0))) { - val = cselib_lookup (XEXP (*loc, 0), Pmode, false); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (*loc)); + val = cselib_lookup (XEXP (*loc, 0), address_mode, false); if (val && !cselib_preserved_value_p (val)) { @@ -4613,7 +4617,10 @@ add_uses (rtx *loc, void *data) && !REG_P (XEXP (vloc, 0)) && !MEM_P (XEXP (vloc, 0))) { rtx mloc = vloc; - cselib_val *val = cselib_lookup (XEXP (mloc, 0), Pmode, 0); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc)); + cselib_val *val + = cselib_lookup (XEXP (mloc, 0), address_mode, 0); if (val && !cselib_preserved_value_p (val)) { @@ -4624,7 +4631,8 @@ add_uses (rtx *loc, void *data) cselib_preserve_value (val); mo->type = MO_VAL_USE; mloc = cselib_subst_to_values (XEXP (mloc, 0)); - mo->u.loc = gen_rtx_CONCAT (Pmode, val->val_rtx, mloc); + mo->u.loc = gen_rtx_CONCAT (address_mode, + val->val_rtx, mloc); if (dump_file && (dump_flags & TDF_DETAILS)) log_op_type (mo->u.loc, cui->bb, cui->insn, mo->type, dump_file); @@ -4680,7 +4688,10 @@ add_uses (rtx *loc, void *data) && !REG_P (XEXP (oloc, 0)) && !MEM_P (XEXP (oloc, 0))) { rtx mloc = oloc; - cselib_val *val = cselib_lookup (XEXP (mloc, 0), Pmode, 0); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc)); + cselib_val *val + = cselib_lookup (XEXP (mloc, 0), address_mode, 0); if (val && !cselib_preserved_value_p (val)) { @@ -4691,7 +4702,8 @@ add_uses (rtx *loc, void *data) cselib_preserve_value (val); mo->type = MO_VAL_USE; mloc = cselib_subst_to_values (XEXP (mloc, 0)); - mo->u.loc = gen_rtx_CONCAT (Pmode, val->val_rtx, mloc); + mo->u.loc = gen_rtx_CONCAT (address_mode, + val->val_rtx, mloc); mo->insn = cui->insn; if (dump_file && (dump_flags & TDF_DETAILS)) log_op_type (mo->u.loc, cui->bb, cui->insn, @@ -4824,14 +4836,16 @@ add_stores (rtx loc, const_rtx expr, void *cuip) && !REG_P (XEXP (loc, 0)) && !MEM_P (XEXP (loc, 0))) { rtx mloc = loc; - cselib_val *val = cselib_lookup (XEXP (mloc, 0), Pmode, 0); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc)); + cselib_val *val = cselib_lookup (XEXP (mloc, 0), address_mode, 0); if (val && !cselib_preserved_value_p (val)) { cselib_preserve_value (val); mo->type = MO_VAL_USE; mloc = cselib_subst_to_values (XEXP (mloc, 0)); - mo->u.loc = gen_rtx_CONCAT (Pmode, val->val_rtx, mloc); + mo->u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc); mo->insn = cui->insn; if (dump_file && (dump_flags & TDF_DETAILS)) log_op_type (mo->u.loc, cui->bb, cui->insn, diff --git a/gcc/varasm.c b/gcc/varasm.c index 4c0b9a663a5..b6ff4ae149d 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1168,11 +1168,17 @@ align_variable (tree decl, bool dont_output_data) static section * get_variable_section (tree decl, bool prefer_noswitch_p) { + addr_space_t as = ADDR_SPACE_GENERIC; int reloc; - /* If the decl has been given an explicit section name, then it - isn't common, and shouldn't be handled as such. */ - if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL) + if (TREE_TYPE (decl) != error_mark_node) + as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); + + /* If the decl has been given an explicit section name, or it resides + in a non-generic address space, then it isn't common, and shouldn't + be handled as such. */ + if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL + && ADDR_SPACE_GENERIC_P (as)) { if (DECL_THREAD_LOCAL_P (decl)) return tls_comm_section; @@ -1196,7 +1202,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p) if (IN_NAMED_SECTION (decl)) return get_named_section (decl, NULL, reloc); - if (!DECL_THREAD_LOCAL_P (decl) + if (ADDR_SPACE_GENERIC_P (as) + && !DECL_THREAD_LOCAL_P (decl) && !(prefer_noswitch_p && targetm.have_switchable_bss_sections) && bss_initializer_p (decl)) { @@ -1440,7 +1447,15 @@ make_decl_rtl (tree decl) if (use_object_blocks_p () && use_blocks_for_decl_p (decl)) x = create_block_symbol (name, get_block_for_decl (decl), -1); else - x = gen_rtx_SYMBOL_REF (Pmode, name); + { + enum machine_mode address_mode = Pmode; + if (TREE_TYPE (decl) != error_mark_node) + { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (decl)); + address_mode = targetm.addr_space.address_mode (as); + } + x = gen_rtx_SYMBOL_REF (address_mode, name); + } SYMBOL_REF_WEAK (x) = DECL_WEAK (decl); SET_SYMBOL_REF_DECL (x, decl); @@ -4308,7 +4323,8 @@ initializer_constant_valid_p (tree value, tree endtype) case POINTER_PLUS_EXPR: case PLUS_EXPR: if (! INTEGRAL_TYPE_P (endtype) - || TYPE_PRECISION (endtype) >= POINTER_SIZE) + || TYPE_PRECISION (endtype) + >= int_or_pointer_precision (TREE_TYPE (value))) { tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); @@ -4330,7 +4346,8 @@ initializer_constant_valid_p (tree value, tree endtype) case MINUS_EXPR: if (! INTEGRAL_TYPE_P (endtype) - || TYPE_PRECISION (endtype) >= POINTER_SIZE) + || TYPE_PRECISION (endtype) + >= int_or_pointer_precision (TREE_TYPE (value))) { tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); @@ -4451,7 +4468,9 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) resolving it. */ if (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) - && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp)))) + && targetm.addr_space.valid_pointer_mode + (TYPE_MODE (TREE_TYPE (exp)), + TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) { tree saved_type = TREE_TYPE (exp); @@ -4459,7 +4478,9 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) pointer modes. */ while (TREE_CODE (exp) == NOP_EXPR && POINTER_TYPE_P (TREE_TYPE (exp)) - && targetm.valid_pointer_mode (TYPE_MODE (TREE_TYPE (exp)))) + && targetm.addr_space.valid_pointer_mode + (TYPE_MODE (TREE_TYPE (exp)), + TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))))) exp = TREE_OPERAND (exp, 0); /* If what we're left with is the address of something, we can @@ -6555,14 +6576,6 @@ default_binds_local_p_1 (const_tree exp, int shlib) return local_p; } -/* Determine whether or not a pointer mode is valid. Assume defaults - of ptr_mode or Pmode - can be overridden. */ -bool -default_valid_pointer_mode (enum machine_mode mode) -{ - return (mode == ptr_mode || mode == Pmode); -} - /* Default function to output code that will globalize a label. A target must define GLOBAL_ASM_OP or provide its own function to globalize a label. */ diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index e951502ca76..2db5d2901c8 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,14 @@ +2009-10-26 Nick Clifton <nickc@redhat.com> + + * config.host: Add support for RX target. + * config/rx: New directory. + * config/rx/rx-abi-functions.c: New file. Supplementary + functions for libgcc to support the RX ABI. + * config/rx/rx-abi.h: New file. Supplementary header file for + libgcc RX ABI functions. + * config/rx/t-rx: New file: Makefile fragment for building + libgcc for the RX. + 2009-10-09 Uros Bizjak <ubizjak@gmail.com> * config/i386/32/sfp-machine.h (__FP_FRAC_SUB_4): Change operand diff --git a/libgcc/config.host b/libgcc/config.host index 91b70548101..f0861159adc 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -482,6 +482,10 @@ rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1.*) ;; rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*) ;; +rx-*-elf) + extra_parts="crtbegin.o crtend.o" + tmake_file="rx/t-rx" + ;; s390-*-linux*) tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux s390/32/t-floattodi" ;; diff --git a/libgcc/config/rx/rx-abi-functions.c b/libgcc/config/rx/rx-abi-functions.c new file mode 100644 index 00000000000..10dd9530d6b --- /dev/null +++ b/libgcc/config/rx/rx-abi-functions.c @@ -0,0 +1,90 @@ +/* RX C ABI functions + Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + + +/* The RX C ABI includes the specification of a set of compiler support + functions. Libgcc2 includes some of them, although the names have to + be changed (see rx-abi.h), and the rest are defined here. + + FIXME: Given that FINE_GRAINED_LIBRARIES is defined we ought to consider + compiling this file multiple times with one function per iteration being + compiled. */ + +#ifdef __RX_64BIT_DOUBLES__ + +int _COM_CMPLTd (double a, double b) { return __ltdf2 (a, b) == -1; } +int _COM_CMPGTd (double a, double b) { return __gtdf2 (a, b) == 1; } +int _COM_CMPLEd (double a, double b) { return __ledf2 (a, b) != 1; } +int _COM_CMPGEd (double a, double b) { return __gedf2 (a, b) != -1; } +int _COM_CMPEQd (double a, double b) { return __eqdf2 (a, b) == 0; } +int _COM_CMPNEd (double a, double b) { return __nedf2 (a, b) != 0; } + +int _COM_CMPLTf (double, double) __attribute__ ((weak, alias ("_COM_CMPLTd"))); +int _COM_CMPGTf (double, double) __attribute__ ((weak, alias ("_COM_CMPGTd"))); +int _COM_CMPLEf (double, double) __attribute__ ((weak, alias ("_COM_CMPLEd"))); +int _COM_CMPGEf (double, double) __attribute__ ((weak, alias ("_COM_CMPGEd"))); +int _COM_CMPEQf (double, double) __attribute__ ((weak, alias ("_COM_CMPEQd"))); +int _COM_CMPNEf (double, double) __attribute__ ((weak, alias ("_COM_CMPNEd"))); + +#else /* 32-bit doubles. */ + +double _COM_CONVfd (float a) { return a; } +float _COM_CONVdf (double a) { return a; } + +int _COM_CMPLTd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPLTf"))); +int _COM_CMPGTd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPGTf"))); +int _COM_CMPLEd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPLEf"))); +int _COM_CMPGEd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPGEf"))); +int _COM_CMPEQd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPEQf"))); +int _COM_CMPNEd (double a, double b) __attribute__ ((weak, alias ("_COM_CMPNEf"))); + +signed long long _COM_CONVd64s (double a) { return (signed long long) a; } +unsigned long long _COM_CONVd64u (double a) { return (unsigned long long) a; } + +int _COM_CMPLTf (float a, float b) { return __ltsf2 (a, b) == -1; } +int _COM_CMPGTf (float a, float b) { return __gtsf2 (a, b) == 1; } +int _COM_CMPLEf (float a, float b) { return __lesf2 (a, b) != 1; } +int _COM_CMPGEf (float a, float b) { return __gesf2 (a, b) != -1; } +int _COM_CMPEQf (float a, float b) { return __eqsf2 (a, b) == 0; } +int _COM_CMPNEf (float a, float b) { return __nesf2 (a, b) != 0; } + +#endif /* 64-bit vs 32-bit doubles. */ + +double _COM_CONV64sd (signed long long a) { return (double) a; } +double _COM_CONV64ud (unsigned long long a) { return (double) a; } + +extern int __cmpdi2 (long long, long long); +extern int __ucmpdi2 (long long, long long); + +int _COM_CMPLT64s (long long a, long long b) { return __cmpdi2 (a, b) == 0; } +int _COM_CMPLT64u (long long a, long long b) { return __ucmpdi2 (a, b) == 0; } +int _COM_CMPGT64s (long long a, long long b) { return __cmpdi2 (a, b) == 2; } +int _COM_CMPGT64u (long long a, long long b) { return __ucmpdi2 (a, b) == 2; } +int _COM_CMPLE64s (long long a, long long b) { return __cmpdi2 (a, b) != 2; } +int _COM_CMPLE64u (long long a, long long b) { return __ucmpdi2 (a, b) != 2; } +int _COM_CMPGE64s (long long a, long long b) { return __cmpdi2 (a, b) != 0; } +int _COM_CMPGE64u (long long a, long long b) { return __ucmpdi2 (a, b) != 0; } +int _COM_CMPEQ64 (long long a, long long b) { return __cmpdi2 (a, b) == 1; } +int _COM_CMPNE64 (long long a, long long b) { return __cmpdi2 (a, b) != 1; } + diff --git a/libgcc/config/rx/rx-abi.h b/libgcc/config/rx/rx-abi.h new file mode 100644 index 00000000000..8a0bbdcd82c --- /dev/null +++ b/libgcc/config/rx/rx-abi.h @@ -0,0 +1,235 @@ +/* Header file for RX ABI versions of libgcc functions. + Copyright (C) 2009 + Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Make __COM_<RX_NAME> an alias for __<GCC_NAME>. */ +#define RENAME_LIBRARY(GCC_NAME, RX_NAME) \ + __asm__ (".globl\t__COM_" #RX_NAME "\n" \ + ".set\t__COM_" #RX_NAME ", ___" #GCC_NAME "\n"); + + +/* The long-long aliases... */ + +#ifdef L_muldi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, MUL64) +#endif + +#ifdef L_divdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divdi3, DIV64s) +#endif + +#ifdef L_udivdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (udivdi3, DIV64u) +#endif + +#ifdef L_ashldi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashldi3, SHLL64) +#endif + +#ifdef L_lshrdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (lshrdi3, SHLR64) +#endif + +#ifdef L_ashrdi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (ashrdi3, SHAR64) +#endif + +#ifdef L_fixsfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfdi, CONVf64s) +#endif + +#ifdef L_fixunssfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfdi, CONVf64u) +#endif + +#ifdef L_floatdisf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, CONV64sf) +#endif + +#ifdef L_floatundisf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatundisf, CONV64uf) +#endif + +#ifdef L_moddi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (moddi3, MOD64s) +#endif + +#ifdef L_umoddi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (umoddi3, MOD64u) +#endif + + +#ifdef L_si_to_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatsisf, CONV32sf) +#endif + +#ifdef L_usi_to_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatunsisf, CONV32uf) +#endif + + + +#ifdef __RX_64BIT_DOUBLES__ + +/* Float (32-bit) aliases... */ + +#ifdef L_sf_to_si +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfsi, CONVf32s) +#endif + +#ifdef L_fixunssfsi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfsi, CONVf32u) +#endif + +#ifdef L_addsub_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (addsf3, ADDf) \ + RENAME_LIBRARY (subsf3, SUBf) +#endif + +#ifdef L_mul_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (mulsf3, MULf) +#endif + +#ifdef L_div_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divsf3, DIVf) +#endif + +/* Double (64-bit) aliases... */ + +#ifdef L_addsub_df +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (adddf3, ADDd) \ + RENAME_LIBRARY (subdf3, SUBd) +#endif + +#ifdef L_mul_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldf3, MULd) +#endif + +#ifdef L_div_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (divdf3, DIVd) +#endif + +#ifdef L_fixdfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfdi, CONVd64s) +#endif + +#ifdef L_fixunsdfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfdi, CONVd64u) +#endif + +#ifdef L_floatdidf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, CONV64sd) +#endif + +#ifdef L_floatundidf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, CONV64ud) +#endif + +#ifdef L_df_to_si +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfsi, CONVd32s) +#endif + +#ifdef L_fixunsdfsi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfsi, CONVd32u) +#endif + +#ifdef L_si_to_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatsidf, CONV32sd) +#endif + +#ifdef L_usi_to_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatunsidf, CONV32ud) +#endif + +#ifdef L_sf_to_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (extendsfdf2, CONVfd) +#endif + +#ifdef L_df_to_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (truncdfsf2, CONVdf) +#endif + +#ifdef L_negate_df +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (negdf2, NEGd) +#endif + +/* The 64-bit comparison functions do not have aliases because libgcc2 + does not provide them. Instead they have to be supplied in + rx-abi-functions.c. */ + + +#else /* 32-bit doubles. */ + + +#ifdef L_addsub_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (addsf3, ADDd) \ + RENAME_LIBRARY (subsf3, SUBd) \ + RENAME_LIBRARY (addsf3, ADDf) \ + RENAME_LIBRARY (subsf3, SUBf) +#endif + +#ifdef L_mul_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (mulsf3, MULd) \ + RENAME_LIBRARY (mulsf3, MULf) +#endif + +#ifdef L_div_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (divsf3, DIVd) \ + RENAME_LIBRARY (divsf3, DIVf) +#endif + +#ifdef L_sf_to_si +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (fixsfsi, CONVd32s) \ + RENAME_LIBRARY (fixsfsi, CONVf32s) +#endif + +#ifdef L_fixunssfsi +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (fixunssfsi, CONVd32u) \ + RENAME_LIBRARY (fixunssfsi, CONVf32u) +#endif + +#ifdef L_si_to_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (floatsisf, CONV32sd) \ + RENAME_LIBRARY (floatsisf, CONV32sf) +#endif + +#ifdef L_usi_to_sf +#define DECLARE_LIBRARY_RENAMES \ + RENAME_LIBRARY (floatunsisf, CONV32ud) \ + RENAME_LIBRARY (floatunsisf, CONV32uf) +#endif + +#ifdef L_negate_sf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (negsf2, NEGd) +#endif + +#endif /* 64-bit vs 32-bit doubles. */ diff --git a/libgcc/config/rx/t-rx b/libgcc/config/rx/t-rx new file mode 100644 index 00000000000..1e66af0c8d3 --- /dev/null +++ b/libgcc/config/rx/t-rx @@ -0,0 +1,44 @@ +# Makefile fragment for building LIBGCC for the Renesas RX target. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 3, 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 COPYING3. If not see +# <http://www.gnu.org/licenses/>. + + +# Add functions required by the RX ABI which are not part of +# the normal libgcc sources: + +LIB2ADD = $(srcdir)/config/rx/rx-abi-functions.c + + +# We need special handling of the floating point conversion +# routines, to allow for the varying size of a double: + +FPBIT = fp-bit.c +$(gcc_objdir)/fp-bit.c: $(gcc_srcdir)/config/fp-bit.c + echo '#define FLOAT' > $@ + echo '#ifndef __RX_64BIT_DOUBLES__' >> $@ + echo '#define DF SF' >> $@ + echo '#define FLOAT_ONLY' >> $@ + echo '#endif' >> $@ + cat $(gcc_srcdir)/config/fp-bit.c >> $@ + +DPBIT = dp-bit.c +$(gcc_objdir)/dp-bit.c: $(gcc_srcdir)/config/fp-bit.c + echo '#ifdef __RX_64BIT_DOUBLES__' > $@ + cat $(gcc_srcdir)/config/fp-bit.c >> $@ + echo '#endif' >> $@ diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index ac9bb19b55a..f9d20206d23 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,9 @@ +2009-10-26 Jakub Jelinek <jakub@redhat.com> + + * acinclude.m4 (LIBGOMP_CHECK_LINKER_FEATURES): Avoid using too many + *s. Accept ld version without text in ()s. + * configure: Regenerated. + 2009-10-17 Ralf Wildenhues <Ralf.Wildenhues@gmx.de> PR libgomp/41418 diff --git a/libgomp/acinclude.m4 b/libgomp/acinclude.m4 index 5e0f96c70f5..9e6b77b247a 100644 --- a/libgomp/acinclude.m4 +++ b/libgomp/acinclude.m4 @@ -153,7 +153,7 @@ AC_DEFUN([LIBGOMP_CHECK_LINKER_FEATURES], [ fi changequote(,) ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` changequote([,]) libgomp_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'` diff --git a/libgomp/configure b/libgomp/configure index a0a93d6d328..dac0399f7b6 100755 --- a/libgomp/configure +++ b/libgomp/configure @@ -15698,7 +15698,7 @@ with_gnu_ld=$lt_cv_prog_gnu_ld fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` libgomp_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index c13bb4005cc..daeb4393081 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,25 @@ +2009-10-26 Paolo Carlini <paolo.carlini@oracle.com> + + * include/std/chrono (duration<>::duration(const duration<>&)): Fix + per the straightforward resolution of DR 974. + * testsuite/20_util/duration/cons/dr974.cc: Add. + +2009-10-26 Jakub Jelinek <jakub@redhat.com> + + PR libstdc++/38923 + * acinclude.m4 (GLIBCXX_CHECK_LINKER_FEATURES): Avoid using too many + *s. Accept ld version without text in ()s. + * configure: Regenerated. + +2009-10-26 Jason Merrill <jason@redhat.com> + + Core issue 906 + * include/std/future (~Future_result_base): Default outside class + body. + * include/std/system_error (error_category()): Likewise. + * libsupc++/nested_exception.h (nested_exception): Remove + exception specifications from defaulted methods. + 009-10-20 Paolo Carlini <paolo.carlini@oracle.com> PR libstdc++/41773 diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 51e35ea42a6..aba9a1b2f52 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -210,7 +210,7 @@ AC_DEFUN([GLIBCXX_CHECK_LINKER_FEATURES], [ glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld /;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` changequote([,]) glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'` diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index bdd7a0592c7..e34b0c4bee8 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -19542,7 +19542,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -26444,7 +26444,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -32259,7 +32259,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -43904,7 +43904,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -44118,7 +44118,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -44593,7 +44593,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -50762,7 +50762,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -56562,7 +56562,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -56729,7 +56729,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -56878,7 +56878,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -57045,7 +57045,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` @@ -57217,7 +57217,7 @@ $as_echo_n "checking for ld version... " >&6; } glibcxx_ld_is_gold=yes fi ldver=`$LD --version 2>/dev/null | - sed -e 's/GNU g*o*ld v*e*r*s*i*o*n* *\(([^)]*)* *\) \([0-9.][0-9.]*\).*/\2/; q'` + sed -e 's/GNU gold /GNU ld/;s/GNU ld version /GNU ld /;s/GNU ld ([^)]*) /GNU ld /;s/GNU ld \([0-9.][0-9.]*\).*/\1/; q'` glibcxx_gnu_ld_version=`echo $ldver | \ $AWK -F. '{ if (NF<3) $3=0; print ($1*100+$2)*100+$3 }'` diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index aa4888d9a9d..300c13ce97e 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -225,7 +225,8 @@ namespace std : __r(duration_cast<duration>(__d).count()) { static_assert(treat_as_floating_point<rep>::value == true - || ratio_divide<_Period2, period>::type::den == 1, + || (ratio_divide<_Period2, period>::type::den == 1 + && !treat_as_floating_point<_Rep2>::value), "the resulting duration is not exactly representable"); } diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index f922dcd74d5..00f5c48bcfd 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -130,9 +130,11 @@ namespace std }; protected: - ~_Future_result_base() = default; + ~_Future_result_base(); }; + inline _Future_result_base::~_Future_result_base() = default; + // TODO: use template alias when available /* template<typename _Res> diff --git a/libstdc++-v3/include/std/system_error b/libstdc++-v3/include/std/system_error index 7f462a20dff..864741129a9 100644 --- a/libstdc++-v3/include/std/system_error +++ b/libstdc++-v3/include/std/system_error @@ -64,7 +64,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) class error_category { protected: - error_category() = default; + error_category(); public: virtual ~error_category() { } @@ -100,6 +100,8 @@ _GLIBCXX_BEGIN_NAMESPACE(std) { return this != &__other; } }; + inline error_category::error_category() = default; + // DR 890. _GLIBCXX_CONST const error_category& system_category() throw (); _GLIBCXX_CONST const error_category& generic_category() throw (); diff --git a/libstdc++-v3/libsupc++/nested_exception.h b/libstdc++-v3/libsupc++/nested_exception.h index 752c595b49b..d4e1347114b 100644 --- a/libstdc++-v3/libsupc++/nested_exception.h +++ b/libstdc++-v3/libsupc++/nested_exception.h @@ -57,9 +57,9 @@ namespace std public: nested_exception() throw() : _M_ptr(current_exception()) { } - nested_exception(const nested_exception&) throw() = default; + nested_exception(const nested_exception&) = default; - nested_exception& operator=(const nested_exception&) throw() = default; + nested_exception& operator=(const nested_exception&) = default; virtual ~nested_exception() = default; diff --git a/libstdc++-v3/testsuite/20_util/duration/cons/dr974.cc b/libstdc++-v3/testsuite/20_util/duration/cons/dr974.cc new file mode 100644 index 00000000000..43132c9867c --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/duration/cons/dr974.cc @@ -0,0 +1,37 @@ +// { dg-do compile } +// { dg-options "-std=gnu++0x" } +// { dg-require-cstdint "" } + +// Copyright (C) 2009 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library 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 3, or (at your option) +// any later version. + +// This library 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 this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 20.8.3.1 duration constructors [time.duration.cons] + +#include <chrono> + +// DR 974. +void test01() +{ + using namespace std::chrono; + + duration<double> d(3.5); + duration<int> i = d; // implicit truncation, should not compile +} + +// { dg-error "instantiated from here" "" { target *-*-* } 32 } +// { dg-error "not exactly representable" "" { target *-*-* } 227 } +// { dg-excess-errors "In instantiation of" } diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/assign_neg.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/assign_neg.cc index 0bad6ba2f32..588a27e0dde 100644 --- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/assign_neg.cc @@ -33,4 +33,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 32 } -// { dg-error "deleted function" "" { target *-*-* } 862 } +// { dg-error "deleted function" "" { target *-*-* } 864 } diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/copy_neg.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/copy_neg.cc index 655ca8c2f95..d0d0622cf59 100644 --- a/libstdc++-v3/testsuite/30_threads/packaged_task/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/cons/copy_neg.cc @@ -32,4 +32,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 31 } -// { dg-error "deleted function" "" { target *-*-* } 861 } +// { dg-error "deleted function" "" { target *-*-* } 863 } diff --git a/libstdc++-v3/testsuite/30_threads/promise/cons/assign_neg.cc b/libstdc++-v3/testsuite/30_threads/promise/cons/assign_neg.cc index f2fbf178c36..b97d3ba896e 100644 --- a/libstdc++-v3/testsuite/30_threads/promise/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/promise/cons/assign_neg.cc @@ -33,4 +33,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 32 } -// { dg-error "deleted function" "" { target *-*-* } 588 } +// { dg-error "deleted function" "" { target *-*-* } 590 } diff --git a/libstdc++-v3/testsuite/30_threads/promise/cons/copy_neg.cc b/libstdc++-v3/testsuite/30_threads/promise/cons/copy_neg.cc index 17757aed0ad..f94cffb09f3 100644 --- a/libstdc++-v3/testsuite/30_threads/promise/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/promise/cons/copy_neg.cc @@ -32,4 +32,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 31 } -// { dg-error "deleted function" "" { target *-*-* } 572 } +// { dg-error "deleted function" "" { target *-*-* } 574 } diff --git a/libstdc++-v3/testsuite/30_threads/shared_future/cons/assign_neg.cc b/libstdc++-v3/testsuite/30_threads/shared_future/cons/assign_neg.cc index 868e0b8a4b8..61563e3e3ab 100644 --- a/libstdc++-v3/testsuite/30_threads/shared_future/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/shared_future/cons/assign_neg.cc @@ -35,4 +35,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 34 } -// { dg-error "deleted function" "" { target *-*-* } 481 } +// { dg-error "deleted function" "" { target *-*-* } 483 } diff --git a/libstdc++-v3/testsuite/30_threads/unique_future/cons/assign_neg.cc b/libstdc++-v3/testsuite/30_threads/unique_future/cons/assign_neg.cc index f8f5a690cf4..9783124d2cb 100644 --- a/libstdc++-v3/testsuite/30_threads/unique_future/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/unique_future/cons/assign_neg.cc @@ -35,4 +35,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 34 } -// { dg-error "deleted function" "" { target *-*-* } 401 } +// { dg-error "deleted function" "" { target *-*-* } 403 } diff --git a/libstdc++-v3/testsuite/30_threads/unique_future/cons/copy_neg.cc b/libstdc++-v3/testsuite/30_threads/unique_future/cons/copy_neg.cc index 95b5a1d7d9a..4b598997522 100644 --- a/libstdc++-v3/testsuite/30_threads/unique_future/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/unique_future/cons/copy_neg.cc @@ -34,4 +34,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 33 } -// { dg-error "deleted function" "" { target *-*-* } 400 } +// { dg-error "deleted function" "" { target *-*-* } 402 } diff --git a/lto-plugin/ChangeLog b/lto-plugin/ChangeLog index 110c79e93ad..14cd0874971 100644 --- a/lto-plugin/ChangeLog +++ b/lto-plugin/ChangeLog @@ -1,3 +1,11 @@ +2009-10-26 Richard Guenther <rguenther@suse.de> + + * configure.ac: Use AM_MAINTAINER_MODE. + * acinclude.m4: Remove. + * configure: Re-generate. + * Makefile.in: Likewise. + * aclocal.m4: Likewise. + 2009-10-19 Rafael Avila de Espindola <espindola@google.com> PR40790 diff --git a/lto-plugin/Makefile.in b/lto-plugin/Makefile.in index 6ae87de40c1..804d441caee 100644 --- a/lto-plugin/Makefile.in +++ b/lto-plugin/Makefile.in @@ -155,6 +155,7 @@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ @@ -248,7 +249,7 @@ all: all-am .SUFFIXES: .c .lo .o .obj am--refresh: @: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -275,9 +276,9 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck -$(top_srcdir)/configure: $(am__configure_deps) +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): $(am__aclocal_m4_deps) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): install-libexecsubLTLIBRARIES: $(libexecsub_LTLIBRARIES) diff --git a/lto-plugin/acinclude.m4 b/lto-plugin/acinclude.m4 deleted file mode 100644 index c74f7dd83cf..00000000000 --- a/lto-plugin/acinclude.m4 +++ /dev/null @@ -1,7 +0,0 @@ -m4_include([../config/acx.m4]) -m4_include([../lt~obsolete.m4]) -m4_include([../ltsugar.m4]) -m4_include([../ltoptions.m4]) -m4_include([../ltversion.m4]) - -sinclude(../libtool.m4) diff --git a/lto-plugin/aclocal.m4 b/lto-plugin/aclocal.m4 index c38cda2ec48..8b9d65bf21e 100644 --- a/lto-plugin/aclocal.m4 +++ b/lto-plugin/aclocal.m4 @@ -566,6 +566,46 @@ if test x"${install_sh}" != xset; then fi AC_SUBST(install_sh)]) +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. diff --git a/lto-plugin/configure b/lto-plugin/configure index c7ecf3e85fe..91b84efab8e 100755 --- a/lto-plugin/configure +++ b/lto-plugin/configure @@ -783,6 +783,9 @@ CPPFLAGS LDFLAGS CFLAGS CC +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE am__untar am__tar AMTAR @@ -856,6 +859,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking with_build_libsubdir +enable_maintainer_mode enable_dependency_tracking enable_shared enable_static @@ -1495,6 +1499,8 @@ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-shared[=PKGS] build shared libraries [default=yes] @@ -2854,6 +2860,29 @@ am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4452,13 +4481,13 @@ if test "${lt_cv_nm_interface+set}" = set; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:4455: $ac_compile\"" >&5) + (eval echo "\"\$as_me:4484: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:4458: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:4487: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:4461: output\"" >&5) + (eval echo "\"\$as_me:4490: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5664,7 +5693,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5667 "configure"' > conftest.$ac_ext + echo '#line 5696 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7194,11 +7223,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7197: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7226: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7201: \$? = $ac_status" >&5 + echo "$as_me:7230: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7533,11 +7562,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7536: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7565: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7540: \$? = $ac_status" >&5 + echo "$as_me:7569: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7638,11 +7667,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7641: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7670: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7645: \$? = $ac_status" >&5 + echo "$as_me:7674: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7693,11 +7722,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7696: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7725: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7700: \$? = $ac_status" >&5 + echo "$as_me:7729: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -10075,7 +10104,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10078 "configure" +#line 10107 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10171,7 +10200,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 10174 "configure" +#line 10203 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10556,6 +10585,10 @@ else am__EXEEXT_FALSE= fi +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 diff --git a/lto-plugin/configure.ac b/lto-plugin/configure.ac index 2956ed06c5f..d35972a750a 100644 --- a/lto-plugin/configure.ac +++ b/lto-plugin/configure.ac @@ -2,6 +2,7 @@ AC_PREREQ(2.64) AC_INIT([LTO plugin for ld], 0.1,,[lto-plugin]) GCC_TOPLEV_SUBDIRS AM_INIT_AUTOMAKE([foreign]) +AM_MAINTAINER_MODE AC_PROG_CC AC_ARG_VAR(LIBELFLIBS,[How to link libelf]) AC_ARG_VAR(LIBELFINC,[How to find libelf include files]) |
