diff options
48 files changed, 914 insertions, 172 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c001ccc9f7c..ebe6aec2ba4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,186 @@ +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 diff --git a/gcc/alias.c b/gcc/alias.c index 09ec775c5d0..b6d0b7eccc5 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -2188,6 +2188,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 +2286,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 +2369,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 +2435,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/cfgexpand.c b/gcc/cfgexpand.c index be46028fa58..21b900a540a 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2235,6 +2235,7 @@ 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; switch (TREE_CODE_CLASS (TREE_CODE (exp))) { @@ -2428,6 +2429,11 @@ expand_debug_expr (tree exp) if (!op0) return NULL; + if (POINTER_TYPE_P (TREE_TYPE (exp))) + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + else + as = ADDR_SPACE_GENERIC; + gcc_assert (GET_MODE (op0) == Pmode || GET_MODE (op0) == ptr_mode || GET_CODE (op0) == CONST_INT @@ -2442,6 +2448,7 @@ expand_debug_expr (tree exp) op0 = gen_rtx_MEM (mode, op0); set_mem_attributes (op0, exp, 0); + set_mem_addr_space (op0, as); return op0; @@ -2455,6 +2462,8 @@ expand_debug_expr (tree exp) if (!op0) return NULL; + as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); + gcc_assert (GET_MODE (op0) == Pmode || GET_MODE (op0) == ptr_mode || GET_CODE (op0) == CONST_INT @@ -2463,6 +2472,7 @@ expand_debug_expr (tree exp) 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..89dc4154947 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -4174,7 +4174,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 +4198,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 +4239,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/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/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/doc/extend.texi b/gcc/doc/extend.texi index 6883766cfc6..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 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 ba86a08487e..4a2fe56df95 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 @@ -9825,6 +9826,69 @@ 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. + +@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 diff --git a/gcc/dse.c b/gcc/dse.c index 9d3e2c07ed6..f11c34a6c4c 100644 --- a/gcc/dse.c +++ b/gcc/dse.c @@ -1173,7 +1173,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); diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index cdf19311b38..129ba7de927 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -12158,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) { @@ -12165,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 diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index b8682984eca..baad4a85eef 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -193,7 +193,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 +292,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 +310,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 +322,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 +330,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 +342,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 +1389,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 +1800,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 +1833,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 +1853,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 +1863,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 +1874,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 +1884,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 +1896,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 +1953,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 +1974,12 @@ 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); 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. @@ -2017,7 +2038,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,6 +2067,7 @@ 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); new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); @@ -2055,7 +2078,7 @@ 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) { @@ -2075,7 +2098,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 +2202,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 +2231,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 +2264,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..1115f222c4c 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -405,12 +405,12 @@ 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; @@ -431,12 +431,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 +447,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 +467,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; @@ -495,7 +495,7 @@ memory_address (enum machine_mode mode, rtx 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 +523,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. */ diff --git a/gcc/expr.c b/gcc/expr.c index 5d18435a99a..5e8fae123cb 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1215,7 +1215,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 @@ -2641,9 +2643,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 +3436,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); @@ -4298,20 +4304,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); @@ -4400,6 +4411,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) { @@ -7343,6 +7356,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 +8477,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 +8599,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 +8656,7 @@ 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; if (modifier != EXPAND_WRITE) { @@ -8617,19 +8667,23 @@ 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))); + 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 = 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 +8715,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 = 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; 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..aab4fac9edb 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -2647,8 +2647,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 +3187,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 +8696,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/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/ifcvt.c b/gcc/ifcvt.c index 1ef2d21f903..8b1b4500e6f 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1329,6 +1329,7 @@ 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) { a = XEXP (a, 0); @@ -1482,6 +1483,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/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/reload.c b/gcc/reload.c index 1435945d62c..166bcb98611 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: @@ -4760,8 +4768,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 +4828,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 +4876,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 +4905,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 +4923,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 +4967,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 +4990,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); @@ -5160,8 +5174,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 +5213,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 +5223,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,7 +5233,7 @@ 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)) { /* If AD is an address in the constant pool, the MEM rtx may be shared. Unshare it so we can safely alter it. */ @@ -6180,8 +6195,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/reload1.c b/gcc/reload1.c index e9a0aba83bc..2c881e4d4f0 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)) 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..e9536b54536 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) \ diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 7a734eb66e5..7da04f2835a 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); 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/target-def.h b/gcc/target-def.h index 96b43eb9a9d..fae4210c273 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -471,6 +471,32 @@ #define TARGET_VALID_POINTER_MODE default_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_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 +939,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..5b296d5df31 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -694,6 +694,26 @@ 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 { + /* 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..ab9c05bb029 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -831,6 +831,51 @@ default_builtin_support_vector_misalignment (enum machine_mode mode, return false; } +/* 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..eedc52b0ae7 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -119,4 +119,10 @@ 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_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/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..ca1e06a0b62 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. */ 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..c5e34229bf6 100644 --- a/gcc/tree-ssa-address.c +++ b/gcc/tree-ssa-address.c @@ -305,7 +305,8 @@ 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; @@ -313,7 +314,7 @@ valid_mem_ref_p (enum machine_mode mode, struct mem_address *addr) 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 +324,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 +457,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-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 42b2ef36252..7e536136c80 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -2642,6 +2642,7 @@ 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)); rtx x; gcc_assert (obj); @@ -2651,12 +2652,14 @@ produce_memory_decl_rtl (tree obj, int *regno) x = gen_rtx_SYMBOL_REF (Pmode, 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_rtx_MEM (DECL_MODE (obj), x); + set_mem_addr_space (x, as); } return x; @@ -2744,7 +2747,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 +3024,64 @@ 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); rtx addr; HOST_WIDE_INT i; - valid_mult[mode] = sbitmap_alloc (2 * MAX_RATIO + 1); - sbitmap_zero (valid_mult[mode]); + valid_mult = sbitmap_alloc (2 * MAX_RATIO + 1); + sbitmap_zero (valid_mult); addr = gen_rtx_fmt_ee (MULT, Pmode, 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); + 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 +3092,25 @@ 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]; + 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,16 +3119,22 @@ 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); @@ -3110,36 +3142,36 @@ get_address_cost (bool symbol_present, bool var_present, for (i = start; i <= 1 << 20; i <<= 1) { XEXP (addr, 1) = gen_int_mode (i, Pmode); - if (!memory_address_p (mem_mode, addr)) + 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)) + 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; } @@ -3151,22 +3183,26 @@ get_address_cost (bool symbol_present, bool var_present, if (HAVE_PRE_DECREMENT) { addr = gen_rtx_PRE_DEC (Pmode, reg0); - has_predec[mem_mode] = memory_address_p (mem_mode, addr); + 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); + 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); + 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); + has_postinc[mem_mode] + = memory_address_addr_space_p (mem_mode, addr, as); } for (i = 0; i < 16; i++) { @@ -3178,7 +3214,7 @@ 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)); + gen_int_mode (rat, Pmode)); if (var_p) addr = gen_rtx_fmt_ee (PLUS, Pmode, addr, reg1); @@ -3194,13 +3230,12 @@ get_address_cost (bool symbol_present, bool var_present, if (off_p) base = gen_rtx_fmt_e (CONST, Pmode, - gen_rtx_fmt_ee (PLUS, Pmode, - base, - gen_int_mode (off[mem_mode], - Pmode))); + gen_rtx_fmt_ee + (PLUS, Pmode, base, + gen_int_mode (off, Pmode))); } else if (off_p) - base = gen_int_mode (off[mem_mode], Pmode); + base = gen_int_mode (off, Pmode); else base = NULL_RTX; @@ -3212,17 +3247,17 @@ get_address_cost (bool symbol_present, bool var_present, 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, @@ -3244,12 +3279,12 @@ get_address_cost (bool symbol_present, bool var_present, 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 +3308,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,6 +3316,9 @@ 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); @@ -3309,10 +3347,10 @@ 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); @@ -3322,7 +3360,7 @@ get_address_cost (bool symbol_present, bool var_present, 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 +3780,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 +3816,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.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.c b/gcc/tree.c index 264e3cef04a..dfc88077e96 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -5424,6 +5424,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. */ @@ -7003,6 +7004,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 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..ad810b040c5 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. */ diff --git a/gcc/varasm.c b/gcc/varasm.c index 4c0b9a663a5..95239b2d432 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)) { |