extend.texi (Named Address Spaces): New section.

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.

Co-Authored-By: Michael Meissner <meissner@linux.vnet.ibm.com>
Co-Authored-By: Ulrich Weigand <uweigand@de.ibm.com>

From-SVN: r153572
This commit is contained in:
Ben Elliston 2009-10-26 21:55:59 +00:00 committed by Ulrich Weigand
parent 89c74f4afa
commit 09e881c9e2
48 changed files with 914 additions and 172 deletions

View File

@ -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

View File

@ -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));

View File

@ -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;

View File

@ -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)))))

View File

@ -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:

View File

@ -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,

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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. */

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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)

View File

@ -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))

View File

@ -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
{

View File

@ -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;

View File

@ -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))

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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,

View File

@ -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))

View File

@ -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)
{

View File

@ -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) \

View File

@ -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);

View File

@ -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;

View File

@ -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, \

View File

@ -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. */

View File

@ -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)
{

View File

@ -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);

View File

@ -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)

View File

@ -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. */

View File

@ -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:

View File

@ -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:

View File

@ -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);

View File

@ -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));

View File

@ -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. */

View File

@ -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

View File

@ -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. */

View File

@ -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,8 +2186,27 @@ 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))

View File

@ -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))
{