+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
&& ! 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
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);
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));
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));
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)))
{
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
op0 = gen_rtx_MEM (mode, op0);
set_mem_attributes (op0, exp, 0);
+ set_mem_addr_space (op0, as);
return op0;
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
op0 = gen_rtx_MEM (mode, op0);
set_mem_attributes (op0, exp, 0);
+ set_mem_addr_space (op0, as);
return op0;
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,
&& 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)));
/* 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)))))
{
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:
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,
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:
* 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.
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
@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
* 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
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
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);
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)
{
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
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);
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));
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))));
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;
/* 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
attrs.offset = offset;
attrs.size = size;
attrs.align = align;
+ attrs.addrspace = addrspace;
slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT);
if (*slot == 0)
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
/* 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))
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. */
{
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. */
{
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. */
{
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. */
{
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));
}
\f
/* Return a memory reference like MEMREF, but with its mode changed to MODE
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))
}
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;
}
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.
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. */
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);
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)
{
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;
}
/* ??? 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;
}
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;
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;
}
\f
/* 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);
#endif /* defined(POINTERS_EXTEND_UNSIGNED) */
}
\f
-/* 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;
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;
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;
}
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;
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)
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. */
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
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;
}
/* 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);
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);
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)
{
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
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)));
}
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;
case INDIRECT_REF:
{
tree exp1 = treeop0;
+ addr_space_t as = ADDR_SPACE_GENERIC;
if (modifier != EXPAND_WRITE)
{
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. */
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;
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.
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)
{
|| 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)))
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;
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. */
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
/* 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;
break;
case FIXED_CONVERT_EXPR:
+ case ADDR_SPACE_CONVERT_EXPR:
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
CASE_CONVERT:
/* ??? 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);
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)
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))
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
{
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;
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));
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))
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)
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;
}
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
}
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:
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.
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))
*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;
/* 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
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;
}
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);
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 *);
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);
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);
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
}
\f
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:
#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,
}
/* 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;
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;
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;
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))
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.
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);
|| 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;
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. */
/* 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;
/* 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. */
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,
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))
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)
{
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)
{
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
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);
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) \
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);
- 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;
#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
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, \
/* 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. */
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)
{
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);
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)
/* 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. */
case MINUS_EXPR:
case MULT_EXPR:
+ case ADDR_SPACE_CONVERT_EXPR:
case FIXED_CONVERT_EXPR:
case FIX_TRUNC_EXPR:
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)
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}");
}
NIY;
break;
+ case ADDR_SPACE_CONVERT_EXPR:
case FIXED_CONVERT_EXPR:
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
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;
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
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))
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);
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);
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;
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;
}
}
/* 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
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;
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);
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;
}
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++)
{
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);
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;
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,
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))
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]
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);
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);
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);
}
}
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));
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));
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. */
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. */
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
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. */
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;
};
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. */
#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. */
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;
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))
{