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:
parent
89c74f4afa
commit
09e881c9e2
183
gcc/ChangeLog
183
gcc/ChangeLog
|
@ -1,3 +1,186 @@
|
|||
2009-10-26 Ben Elliston <bje@au.ibm.com>
|
||||
Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* doc/extend.texi (Named Address Spaces): New section.
|
||||
* coretypes.h (addr_space_t): New type.
|
||||
(ADDR_SPACE_GENERIC): New define.
|
||||
(ADDR_SPACE_GENERIC_P): New macro.
|
||||
|
||||
* doc/tm.texi (Named Address Spaces): New section.
|
||||
(TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Document.
|
||||
(TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Document.
|
||||
(TARGET_ADDR_SPACE_SUBSET_P): Document.
|
||||
(TARGET_ADDR_SPACE_CONVERT): Document.
|
||||
* target.h (struct gcc_target): Add addr_space substructure.
|
||||
* target-def.h (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Define.
|
||||
(TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Likewise.
|
||||
(TARGET_ADDR_SPACE_SUBSET_P): Likewise.
|
||||
(TARGET_ADDR_SPACE_CONVERT): Likewise.
|
||||
(TARGET_ADDR_SPACE_HOOKS): Likewise.
|
||||
(TARGET_INITIALIZER): Initialize addr_space hooks.
|
||||
* targhooks.c (default_addr_space_legitimate_address_p): New function.
|
||||
(default_addr_space_legitimize_address): Likewise.
|
||||
(default_addr_space_subset_p): Likewise.
|
||||
(default_addr_space_convert): Likewise.
|
||||
* targhooks.h (default_addr_space_legitimate_address_p): Add prototype.
|
||||
(default_addr_space_legitimize_address): Likewise.
|
||||
(default_addr_space_subset_p): Likewise.
|
||||
(default_addr_space_convert): Likewise.
|
||||
|
||||
* doc/rtl.texi (MEM_ADDR_SPACE): Document.
|
||||
* rtl.h (mem_attrs): Add ADDRSPACE memory attribute.
|
||||
(MEM_ADDR_SPACE): New macro.
|
||||
* emit-rtl.c (get_mem_attrs): Add ADDRSPACE argument and set
|
||||
address space memory attribute.
|
||||
(mem_attrs_htab_hash): Handle address space memory attribute.
|
||||
(mem_attrs_htab_eq): Likewise.
|
||||
(set_mem_attributes_minus_bitpos): Likewise.
|
||||
(set_mem_alias_set): Likewise.
|
||||
(set_mem_align): Likewise.
|
||||
(set_mem_expr): Likewise.
|
||||
(set_mem_offset): Likewise.
|
||||
(set_mem_size): Likewise.
|
||||
(adjust_address_1): Likewise.
|
||||
(offset_address): Likewise.
|
||||
(widen_memoy_address): Likewise.
|
||||
(get_spill_slot_decl): Likewise.
|
||||
(set_mem_attrs_for_spill): Likewise.
|
||||
(set_mem_addr_space): New function.
|
||||
* emit-rtl.h (set_mem_addr_space): Add prototype.
|
||||
* print-rtl.c (print_rtx): Print address space memory attribute.
|
||||
* expr.c (expand_assignment): Set address space memory attribute
|
||||
of generated MEM RTXes as appropriate.
|
||||
(expand_expr_real_1): Likewise.
|
||||
* cfgexpand.c (expand_debug_expr): Likewise.
|
||||
* tree-ssa-loop-ivopts.c (produce_memory_decl_rtl): Likewise.
|
||||
|
||||
* tree.h (struct tree_base): Add address_space bitfield. Reduce
|
||||
size of "spare" bitfield.
|
||||
(TYPE_ADDR_SPACE): New macro.
|
||||
(ENCODE_QUAL_ADDR_SPACE): Likewise.
|
||||
(DECODE_QUAL_ADDR_SPACE): Likewise.
|
||||
(CLEAR_QUAL_ADDR_SPACE): Likewise.
|
||||
(KEEP_QUAL_ADDR_SPACE): Likewise.
|
||||
(TYPE_QUALS): Encode type address space.
|
||||
(TYPE_QUALS_NO_ADDR_SPACE): New macro.
|
||||
* tree.c (set_type_quals): Set type address space.
|
||||
(build_array_type): Inherit array address space from element type.
|
||||
* print-tree.c (print_node_brief): Print type address space.
|
||||
(print_node): Likewise.
|
||||
* tree-pretty-print.c (dump_generic_node): Likewise.
|
||||
|
||||
* explow.c (memory_address): Rename to ...
|
||||
(memory_address_addr_space): ... this. Add ADDRSPACE argument.
|
||||
Use address-space aware variants of memory address routines.
|
||||
* recog.c (memory_address_p): Rename to ...
|
||||
(memory_address_addr_space_p): ... this. Add ADDSPACE argument.
|
||||
Use address-space aware variants of memory address routines.
|
||||
(offsettable_address_p): Rename to ...
|
||||
(offsettable_address_addr_space_p): ... this. Add ADDRSPACE argument.
|
||||
Use address-space aware variants of memory address routines.
|
||||
* reload.c (strict_memory_address_p): Rename to ...
|
||||
(strict_memory_address_addr_space_p): ... this. Add ADDSPACE argument.
|
||||
Use address-space aware variants of memory address routines.
|
||||
(maybe_memory_address_p): Rename to ...
|
||||
(maybe_memory_address_addr_space_p): ... this. Add ADDSPACE argument.
|
||||
Use address-space aware variants of memory address routines.
|
||||
* expr.h (memory_address_addr_space): Add prototype.
|
||||
(memory_address): Define as macro.
|
||||
* recog.h (memory_address_addr_space_p): Add prototype.
|
||||
(memory_address_p): Define as macro.
|
||||
(offsettable_address_addr_space_p): Add prototype.
|
||||
(offsettable_address_p): Define as macro.
|
||||
(strict_memory_address_addr_space_p): Add prototype.
|
||||
(strict_memory_address_p): Define as macro.
|
||||
|
||||
* combine.c (find_split_point): Use address-space aware variants
|
||||
of memory address routines.
|
||||
* emit-rtl.c (operand_subword): Likewise.
|
||||
(change_address_1): Likewise.
|
||||
(adjust_address_1): Likewise.
|
||||
(offset_address): Likewise.
|
||||
* expr.c (emit_move_insn): Likewise.
|
||||
(expand_assignment): Likewise.
|
||||
(expand_expr_real_1): Likewise.
|
||||
* recog.c (verify_changes): Likewise.
|
||||
(general_operand): Likewise.
|
||||
(offsettable_memref_p): Likewise.
|
||||
(offsettable_nonstrict_memref_p): Likewise.
|
||||
(constrain_operands): Likewise.
|
||||
* reload.c (get_secondary_mem): Likewise.
|
||||
(find_reloads_toplev): Likewise.
|
||||
(find_reloads_address): Likewise.
|
||||
(find_reloads_subreg_address): Likewise.
|
||||
* reload1.c (reload): Likewise.
|
||||
* rtlhooks.c (gen_lowpart_if_possible): Likewise.
|
||||
* rtl.h (address_cost): Add ADDRSPACE argument.
|
||||
* rtlanal.c (address_cost): Add ADDRSPACE argument. Use address-space
|
||||
aware variant of memory address routines.
|
||||
* loop-invariant.c (create_new_invariant): Update address_cost call.
|
||||
* tree-ssa-loop-ivopts.c (computation_cost): Likewise.
|
||||
* fwprop.c (should_replace_address): Add ADDRSPACE argument.
|
||||
Use address-space aware variant of memory address routines.
|
||||
(propagate_rtx_1): Update call to should_replace_address.
|
||||
* tree-flow.h (multiplier_allowed_in_address_p): Add ADDRSPACE
|
||||
argument.
|
||||
* tree-ssa-loop-ivopts.c (multiplier_allowed_in_address_p): Add
|
||||
ADDRSPACE argument. Use per-address-space instead of global cache.
|
||||
Use address-space aware variant of memory address routines.
|
||||
(get_address_cost): Likewise.
|
||||
(get_computation_cost_at): Update calls.
|
||||
* tree-ssa-address.c (valid_mem_ref_p): Add ADDRSPACE argument.
|
||||
Use address-space aware variant of memory address routines.
|
||||
(create_mem_ref_raw): Update call to valid_mem_ref_p.
|
||||
(most_expensive_mult_to_index): Update call to
|
||||
multiplier_allowed_in_address_p.
|
||||
|
||||
* dwarf2out.c (modified_type_die): Output DW_AT_address_class
|
||||
attribute to indicate named address spaces.
|
||||
|
||||
* varasm.c (get_variable_section): DECLs in named address spaces
|
||||
cannot be "common".
|
||||
|
||||
* reload.c (find_reloads_address): Do not use LEGITIMIZE_RELOAD_ADDRESS
|
||||
for addresses in a non-generic address space.
|
||||
|
||||
* expr.c (emit_block_move_hints): Do not use libcalls for
|
||||
memory in non-generic address spaces.
|
||||
(clear_storage_hints): Likewise.
|
||||
(expand_assignment): Likewise.
|
||||
|
||||
* fold-const.c (operand_equal_p): Expressions refering to different
|
||||
address spaces are not equivalent.
|
||||
|
||||
* rtl.c (rtx_equal_p_cb): MEMs refering to different address
|
||||
spaces are not equivalent.
|
||||
(rtx_equal_p): Likewise.
|
||||
* cse.c (exp_equiv_p): Likewise.
|
||||
* jump.c (rtx_renumbered_equal_p): Likewise.
|
||||
* reload.c (operands_match_p): Likewise.
|
||||
|
||||
* alias.c (nonoverlapping_memrefs_p): MEMs refering to different
|
||||
address spaces may alias.
|
||||
(true_dependence): Likewise.
|
||||
(canon_true_dependence): Likewise.
|
||||
(write_dependence_p): Likewise.
|
||||
|
||||
* dse.c (canon_address): Handle named address spaces.
|
||||
* ifcvt.c (noce_try_cmove_arith): Likewise.
|
||||
|
||||
* tree.def (ADDR_SPACE_CONVERT_EXPR): New tree code.
|
||||
* expr.c (expand_expr_real_2): Expand ADDR_SPACE_CONVERT_EXPR.
|
||||
* convert.c (convert_to_pointer): Generate ADDR_SPACE_CONVERT_EXPR
|
||||
to handle conversions between different address spaces.
|
||||
* fold-const.c (fold_convert_loc): Likewise.
|
||||
(fold_unary_loc): Handle ADDR_SPACE_CONVERT_EXPR.
|
||||
* tree-pretty-print.c (dump_generic_node): Likewise.
|
||||
* gimple-pretty-print.c (dump_unary_rhs): Likewise.
|
||||
* tree-cfg.c (verify_gimple_assign_unary): Likewise.
|
||||
* tree-inline.c (estimate_operator_cost): Likewise.
|
||||
* tree-ssa.c (useless_type_conversion_p): Conversions between pointers
|
||||
to different address spaces are not useless.
|
||||
|
||||
2009-10-26 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR bootstrap/41345
|
||||
|
|
25
gcc/alias.c
25
gcc/alias.c
|
@ -2188,6 +2188,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y)
|
|||
&& ! rtx_equal_p (rtlx, rtly))
|
||||
return 1;
|
||||
|
||||
/* If we have MEMs refering to different address spaces (which can
|
||||
potentially overlap), we cannot easily tell from the addresses
|
||||
whether the references overlap. */
|
||||
if (MEM_P (rtlx) && MEM_P (rtly)
|
||||
&& MEM_ADDR_SPACE (rtlx) != MEM_ADDR_SPACE (rtly))
|
||||
return 0;
|
||||
|
||||
/* Get the base and offsets of both decls. If either is a register, we
|
||||
know both are and are the same, so use that as the base. The only
|
||||
we can avoid overlap is if we can deduce that they are nonoverlapping
|
||||
|
@ -2279,6 +2286,12 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x,
|
|||
if (nonoverlapping_memrefs_p (mem, x))
|
||||
return 0;
|
||||
|
||||
/* If we have MEMs refering to different address spaces (which can
|
||||
potentially overlap), we cannot easily tell from the addresses
|
||||
whether the references overlap. */
|
||||
if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
|
||||
return 1;
|
||||
|
||||
if (mem_mode == VOIDmode)
|
||||
mem_mode = GET_MODE (mem);
|
||||
|
||||
|
@ -2356,6 +2369,12 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr,
|
|||
if (nonoverlapping_memrefs_p (x, mem))
|
||||
return 0;
|
||||
|
||||
/* If we have MEMs refering to different address spaces (which can
|
||||
potentially overlap), we cannot easily tell from the addresses
|
||||
whether the references overlap. */
|
||||
if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
|
||||
return 1;
|
||||
|
||||
if (! x_addr)
|
||||
x_addr = get_addr (XEXP (x, 0));
|
||||
|
||||
|
@ -2416,6 +2435,12 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep)
|
|||
if (nonoverlapping_memrefs_p (x, mem))
|
||||
return 0;
|
||||
|
||||
/* If we have MEMs refering to different address spaces (which can
|
||||
potentially overlap), we cannot easily tell from the addresses
|
||||
whether the references overlap. */
|
||||
if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x))
|
||||
return 1;
|
||||
|
||||
x_addr = get_addr (XEXP (x, 0));
|
||||
mem_addr = get_addr (XEXP (mem, 0));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)))))
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
27
gcc/explow.c
27
gcc/explow.c
|
@ -405,12 +405,12 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED,
|
|||
#endif /* defined(POINTERS_EXTEND_UNSIGNED) */
|
||||
}
|
||||
|
||||
/* Return something equivalent to X but valid as a memory address
|
||||
for something of mode MODE. When X is not itself valid, this
|
||||
works by copying X or subexpressions of it into registers. */
|
||||
/* Return something equivalent to X but valid as a memory address for something
|
||||
of mode MODE in the named address space AS. When X is not itself valid,
|
||||
this works by copying X or subexpressions of it into registers. */
|
||||
|
||||
rtx
|
||||
memory_address (enum machine_mode mode, rtx x)
|
||||
memory_address_addr_space (enum machine_mode mode, rtx x, addr_space_t as)
|
||||
{
|
||||
rtx oldx = x;
|
||||
|
||||
|
@ -431,12 +431,12 @@ memory_address (enum machine_mode mode, rtx x)
|
|||
x = break_out_memory_refs (x);
|
||||
|
||||
/* At this point, any valid address is accepted. */
|
||||
if (memory_address_p (mode, x))
|
||||
if (memory_address_addr_space_p (mode, x, as))
|
||||
goto done;
|
||||
|
||||
/* If it was valid before but breaking out memory refs invalidated it,
|
||||
use it the old way. */
|
||||
if (memory_address_p (mode, oldx))
|
||||
if (memory_address_addr_space_p (mode, oldx, as))
|
||||
{
|
||||
x = oldx;
|
||||
goto done;
|
||||
|
@ -447,9 +447,9 @@ memory_address (enum machine_mode mode, rtx x)
|
|||
below can handle all possible cases, but machine-dependent
|
||||
transformations can make better code. */
|
||||
{
|
||||
rtx orig_x = x;
|
||||
x = targetm.legitimize_address (x, oldx, mode);
|
||||
if (orig_x != x && memory_address_p (mode, x))
|
||||
rtx orig_x = x;
|
||||
x = targetm.addr_space.legitimize_address (x, oldx, mode, as);
|
||||
if (orig_x != x && memory_address_addr_space_p (mode, x, as))
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -467,12 +467,12 @@ memory_address (enum machine_mode mode, rtx x)
|
|||
rtx constant_term = const0_rtx;
|
||||
rtx y = eliminate_constant_term (x, &constant_term);
|
||||
if (constant_term == const0_rtx
|
||||
|| ! memory_address_p (mode, y))
|
||||
|| ! memory_address_addr_space_p (mode, y, as))
|
||||
x = force_operand (x, NULL_RTX);
|
||||
else
|
||||
{
|
||||
y = gen_rtx_PLUS (GET_MODE (x), copy_to_reg (y), constant_term);
|
||||
if (! memory_address_p (mode, y))
|
||||
if (! memory_address_addr_space_p (mode, y, as))
|
||||
x = force_operand (x, NULL_RTX);
|
||||
else
|
||||
x = y;
|
||||
|
@ -495,7 +495,7 @@ memory_address (enum machine_mode mode, rtx x)
|
|||
|
||||
done:
|
||||
|
||||
gcc_assert (memory_address_p (mode, x));
|
||||
gcc_assert (memory_address_addr_space_p (mode, x, as));
|
||||
/* If we didn't change the address, we are done. Otherwise, mark
|
||||
a reg as a pointer if we have REG or REG + CONST_INT. */
|
||||
if (oldx == x)
|
||||
|
@ -523,7 +523,8 @@ validize_mem (rtx ref)
|
|||
if (!MEM_P (ref))
|
||||
return ref;
|
||||
ref = use_anchored_address (ref);
|
||||
if (memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
|
||||
if (memory_address_addr_space_p (GET_MODE (ref), XEXP (ref, 0),
|
||||
MEM_ADDR_SPACE (ref)))
|
||||
return ref;
|
||||
|
||||
/* Don't alter REF itself, since that is probably a stack slot. */
|
||||
|
|
76
gcc/expr.c
76
gcc/expr.c
|
@ -1215,7 +1215,9 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
|
|||
else if (emit_block_move_via_movmem (x, y, size, align,
|
||||
expected_align, expected_size))
|
||||
;
|
||||
else if (may_use_call)
|
||||
else if (may_use_call
|
||||
&& ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
|
||||
&& ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y)))
|
||||
retval = emit_block_move_via_libcall (x, y, size,
|
||||
method == BLOCK_OP_TAILCALL);
|
||||
else
|
||||
|
@ -2641,9 +2643,11 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method,
|
|||
else if (set_storage_via_setmem (object, size, const0_rtx, align,
|
||||
expected_align, expected_size))
|
||||
;
|
||||
else
|
||||
else if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (object)))
|
||||
return set_storage_via_libcall (object, size, const0_rtx,
|
||||
method == BLOCK_OP_TAILCALL);
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -3432,12 +3436,14 @@ emit_move_insn (rtx x, rtx y)
|
|||
/* If X or Y are memory references, verify that their addresses are valid
|
||||
for the machine. */
|
||||
if (MEM_P (x)
|
||||
&& (! memory_address_p (GET_MODE (x), XEXP (x, 0))
|
||||
&& (! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
|
||||
MEM_ADDR_SPACE (x))
|
||||
&& ! push_operand (x, GET_MODE (x))))
|
||||
x = validize_mem (x);
|
||||
|
||||
if (MEM_P (y)
|
||||
&& ! memory_address_p (GET_MODE (y), XEXP (y, 0)))
|
||||
&& ! memory_address_addr_space_p (GET_MODE (y), XEXP (y, 0),
|
||||
MEM_ADDR_SPACE (y)))
|
||||
y = validize_mem (y);
|
||||
|
||||
gcc_assert (mode != BLKmode);
|
||||
|
@ -4298,20 +4304,25 @@ expand_assignment (tree to, tree from, bool nontemporal)
|
|||
|
||||
else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF)
|
||||
{
|
||||
addr_space_t as = ADDR_SPACE_GENERIC;
|
||||
enum machine_mode mode, op_mode1;
|
||||
enum insn_code icode;
|
||||
rtx reg, addr, mem, insn;
|
||||
|
||||
if (POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (to, 0))))
|
||||
as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0))));
|
||||
|
||||
reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL);
|
||||
reg = force_not_mem (reg);
|
||||
|
||||
mode = TYPE_MODE (TREE_TYPE (to));
|
||||
addr = expand_expr (TREE_OPERAND (to, 0), NULL_RTX, VOIDmode,
|
||||
EXPAND_SUM);
|
||||
addr = memory_address (mode, addr);
|
||||
addr = memory_address_addr_space (mode, addr, as);
|
||||
mem = gen_rtx_MEM (mode, addr);
|
||||
|
||||
set_mem_attributes (mem, to, 0);
|
||||
set_mem_addr_space (mem, as);
|
||||
|
||||
icode = movmisalign_optab->handlers[mode].insn_code;
|
||||
gcc_assert (icode != CODE_FOR_nothing);
|
||||
|
@ -4400,6 +4411,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
|
|||
the place the value is being stored, use a safe function when copying
|
||||
a value through a pointer into a structure value return block. */
|
||||
if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF
|
||||
&& ADDR_SPACE_GENERIC_P
|
||||
(TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (from, 0)))))
|
||||
&& cfun->returns_struct
|
||||
&& !cfun->returns_pcc_struct)
|
||||
{
|
||||
|
@ -7343,6 +7356,39 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
|
|||
|
||||
return REDUCE_BIT_FIELD (op0);
|
||||
|
||||
case ADDR_SPACE_CONVERT_EXPR:
|
||||
{
|
||||
tree treeop0_type = TREE_TYPE (treeop0);
|
||||
addr_space_t as_to;
|
||||
addr_space_t as_from;
|
||||
|
||||
gcc_assert (POINTER_TYPE_P (type));
|
||||
gcc_assert (POINTER_TYPE_P (treeop0_type));
|
||||
|
||||
as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
|
||||
as_from = TYPE_ADDR_SPACE (TREE_TYPE (treeop0_type));
|
||||
|
||||
/* Conversions between pointers to the same address space should
|
||||
have been implemented via CONVERT_EXPR / NOP_EXPR. */
|
||||
gcc_assert (as_to != as_from);
|
||||
|
||||
/* Ask target code to handle conversion between pointers
|
||||
to overlapping address spaces. */
|
||||
if (targetm.addr_space.subset_p (as_to, as_from)
|
||||
|| targetm.addr_space.subset_p (as_from, as_to))
|
||||
{
|
||||
op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier);
|
||||
op0 = targetm.addr_space.convert (op0, treeop0_type, type);
|
||||
gcc_assert (op0);
|
||||
return op0;
|
||||
}
|
||||
|
||||
/* For disjoint address spaces, converting anything but
|
||||
a null pointer invokes undefined behaviour. We simply
|
||||
always return a null pointer here. */
|
||||
return CONST0_RTX (mode);
|
||||
}
|
||||
|
||||
case POINTER_PLUS_EXPR:
|
||||
/* Even though the sizetype mode and the pointer's mode can be different
|
||||
expand is able to handle this correctly and get the correct result out
|
||||
|
@ -8431,7 +8477,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|
|||
decl_rtl = use_anchored_address (decl_rtl);
|
||||
if (modifier != EXPAND_CONST_ADDRESS
|
||||
&& modifier != EXPAND_SUM
|
||||
&& !memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0)))
|
||||
&& !memory_address_addr_space_p (DECL_MODE (exp),
|
||||
XEXP (decl_rtl, 0),
|
||||
MEM_ADDR_SPACE (decl_rtl)))
|
||||
temp = replace_equiv_address (decl_rtl,
|
||||
copy_rtx (XEXP (decl_rtl, 0)));
|
||||
}
|
||||
|
@ -8551,7 +8599,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|
|||
if (modifier != EXPAND_CONST_ADDRESS
|
||||
&& modifier != EXPAND_INITIALIZER
|
||||
&& modifier != EXPAND_SUM
|
||||
&& ! memory_address_p (mode, XEXP (temp, 0)))
|
||||
&& ! memory_address_addr_space_p (mode, XEXP (temp, 0),
|
||||
MEM_ADDR_SPACE (temp)))
|
||||
return replace_equiv_address (temp,
|
||||
copy_rtx (XEXP (temp, 0)));
|
||||
return temp;
|
||||
|
@ -8607,6 +8656,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|
|||
case INDIRECT_REF:
|
||||
{
|
||||
tree exp1 = treeop0;
|
||||
addr_space_t as = ADDR_SPACE_GENERIC;
|
||||
|
||||
if (modifier != EXPAND_WRITE)
|
||||
{
|
||||
|
@ -8617,19 +8667,23 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|
|||
return expand_expr (t, target, tmode, modifier);
|
||||
}
|
||||
|
||||
if (POINTER_TYPE_P (TREE_TYPE (exp1)))
|
||||
as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1)));
|
||||
|
||||
op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
|
||||
op0 = memory_address (mode, op0);
|
||||
op0 = memory_address_addr_space (mode, op0, as);
|
||||
|
||||
if (code == ALIGN_INDIRECT_REF)
|
||||
{
|
||||
int align = TYPE_ALIGN_UNIT (type);
|
||||
op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align));
|
||||
op0 = memory_address (mode, op0);
|
||||
op0 = memory_address_addr_space (mode, op0, as);
|
||||
}
|
||||
|
||||
temp = gen_rtx_MEM (mode, op0);
|
||||
|
||||
set_mem_attributes (temp, exp, 0);
|
||||
set_mem_addr_space (temp, as);
|
||||
|
||||
/* Resolve the misalignment now, so that we don't have to remember
|
||||
to resolve it later. Of course, this only works for reads. */
|
||||
|
@ -8661,13 +8715,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
|
|||
|
||||
case TARGET_MEM_REF:
|
||||
{
|
||||
addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
|
||||
struct mem_address addr;
|
||||
|
||||
get_address_description (exp, &addr);
|
||||
op0 = addr_for_mem_ref (&addr, true);
|
||||
op0 = memory_address (mode, op0);
|
||||
op0 = memory_address_addr_space (mode, op0, as);
|
||||
temp = gen_rtx_MEM (mode, op0);
|
||||
set_mem_attributes (temp, TMR_ORIGINAL (exp), 0);
|
||||
set_mem_addr_space (temp, as);
|
||||
}
|
||||
return temp;
|
||||
|
||||
|
|
12
gcc/expr.h
12
gcc/expr.h
|
@ -650,9 +650,15 @@ extern rtx force_label_rtx (tree);
|
|||
The constant terms are added and stored via a second arg. */
|
||||
extern rtx eliminate_constant_term (rtx, rtx *);
|
||||
|
||||
/* Convert arg to a valid memory address for specified machine mode,
|
||||
by emitting insns to perform arithmetic if nec. */
|
||||
extern rtx memory_address (enum machine_mode, rtx);
|
||||
/* Convert arg to a valid memory address for specified machine mode that points
|
||||
to a specific named address space, by emitting insns to perform arithmetic
|
||||
if necessary. */
|
||||
extern rtx memory_address_addr_space (enum machine_mode, rtx, addr_space_t);
|
||||
|
||||
/* Like memory_address_addr_space, except assume the memory address points to
|
||||
the generic named address space. */
|
||||
#define memory_address(MODE,RTX) \
|
||||
memory_address_addr_space ((MODE), (RTX), ADDR_SPACE_GENERIC)
|
||||
|
||||
/* Return a memory reference like MEMREF, but with its mode changed
|
||||
to MODE and its address changed to ADDR.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
46
gcc/recog.c
46
gcc/recog.c
|
@ -376,7 +376,9 @@ verify_changes (int num)
|
|||
|
||||
if (MEM_P (object))
|
||||
{
|
||||
if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
|
||||
if (! memory_address_addr_space_p (GET_MODE (object),
|
||||
XEXP (object, 0),
|
||||
MEM_ADDR_SPACE (object)))
|
||||
break;
|
||||
}
|
||||
else if (REG_P (changes[i].old)
|
||||
|
@ -978,7 +980,7 @@ general_operand (rtx op, enum machine_mode mode)
|
|||
return 0;
|
||||
|
||||
/* Use the mem's mode, since it will be reloaded thus. */
|
||||
if (memory_address_p (GET_MODE (op), y))
|
||||
if (memory_address_addr_space_p (GET_MODE (op), y, MEM_ADDR_SPACE (op)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1262,19 +1264,22 @@ pop_operand (rtx op, enum machine_mode mode)
|
|||
return XEXP (op, 0) == stack_pointer_rtx;
|
||||
}
|
||||
|
||||
/* Return 1 if ADDR is a valid memory address for mode MODE. */
|
||||
/* Return 1 if ADDR is a valid memory address
|
||||
for mode MODE in address space AS. */
|
||||
|
||||
int
|
||||
memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr)
|
||||
memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
|
||||
rtx addr, addr_space_t as)
|
||||
{
|
||||
#ifdef GO_IF_LEGITIMATE_ADDRESS
|
||||
gcc_assert (ADDR_SPACE_GENERIC_P (as));
|
||||
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
|
||||
return 0;
|
||||
|
||||
win:
|
||||
return 1;
|
||||
#else
|
||||
return targetm.legitimate_address_p (mode, addr, 0);
|
||||
return targetm.addr_space.legitimate_address_p (mode, addr, 0, as);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1871,7 +1876,8 @@ int
|
|||
offsettable_memref_p (rtx op)
|
||||
{
|
||||
return ((MEM_P (op))
|
||||
&& offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)));
|
||||
&& offsettable_address_addr_space_p (1, GET_MODE (op), XEXP (op, 0),
|
||||
MEM_ADDR_SPACE (op)));
|
||||
}
|
||||
|
||||
/* Similar, but don't require a strictly valid mem ref:
|
||||
|
@ -1881,12 +1887,13 @@ int
|
|||
offsettable_nonstrict_memref_p (rtx op)
|
||||
{
|
||||
return ((MEM_P (op))
|
||||
&& offsettable_address_p (0, GET_MODE (op), XEXP (op, 0)));
|
||||
&& offsettable_address_addr_space_p (0, GET_MODE (op), XEXP (op, 0),
|
||||
MEM_ADDR_SPACE (op)));
|
||||
}
|
||||
|
||||
/* Return 1 if Y is a memory address which contains no side effects
|
||||
and would remain valid after the addition of a positive integer
|
||||
less than the size of that mode.
|
||||
and would remain valid for address space AS after the addition of
|
||||
a positive integer less than the size of that mode.
|
||||
|
||||
We assume that the original address is valid and do not check it.
|
||||
We do check that it is valid for narrower modes.
|
||||
|
@ -1895,14 +1902,16 @@ offsettable_nonstrict_memref_p (rtx op)
|
|||
for the sake of use in reload.c. */
|
||||
|
||||
int
|
||||
offsettable_address_p (int strictp, enum machine_mode mode, rtx y)
|
||||
offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
|
||||
addr_space_t as)
|
||||
{
|
||||
enum rtx_code ycode = GET_CODE (y);
|
||||
rtx z;
|
||||
rtx y1 = y;
|
||||
rtx *y2;
|
||||
int (*addressp) (enum machine_mode, rtx) =
|
||||
(strictp ? strict_memory_address_p : memory_address_p);
|
||||
int (*addressp) (enum machine_mode, rtx, addr_space_t) =
|
||||
(strictp ? strict_memory_address_addr_space_p
|
||||
: memory_address_addr_space_p);
|
||||
unsigned int mode_sz = GET_MODE_SIZE (mode);
|
||||
|
||||
if (CONSTANT_ADDRESS_P (y))
|
||||
|
@ -1932,7 +1941,7 @@ offsettable_address_p (int strictp, enum machine_mode mode, rtx y)
|
|||
*y2 = plus_constant (*y2, mode_sz - 1);
|
||||
/* Use QImode because an odd displacement may be automatically invalid
|
||||
for any wider mode. But it should be valid for a single byte. */
|
||||
good = (*addressp) (QImode, y);
|
||||
good = (*addressp) (QImode, y, as);
|
||||
|
||||
/* In any case, restore old contents of memory. */
|
||||
*y2 = y1;
|
||||
|
@ -1957,7 +1966,7 @@ offsettable_address_p (int strictp, enum machine_mode mode, rtx y)
|
|||
|
||||
/* Use QImode because an odd displacement may be automatically invalid
|
||||
for any wider mode. But it should be valid for a single byte. */
|
||||
return (*addressp) (QImode, z);
|
||||
return (*addressp) (QImode, z, as);
|
||||
}
|
||||
|
||||
/* Return 1 if ADDR is an address-expression whose effect depends
|
||||
|
@ -2502,11 +2511,14 @@ constrain_operands (int strict)
|
|||
if (MEM_P (op))
|
||||
{
|
||||
if (strict > 0
|
||||
&& !strict_memory_address_p (GET_MODE (op),
|
||||
XEXP (op, 0)))
|
||||
&& !strict_memory_address_addr_space_p
|
||||
(GET_MODE (op), XEXP (op, 0),
|
||||
MEM_ADDR_SPACE (op)))
|
||||
break;
|
||||
if (strict == 0
|
||||
&& !memory_address_p (GET_MODE (op), XEXP (op, 0)))
|
||||
&& !memory_address_addr_space_p
|
||||
(GET_MODE (op), XEXP (op, 0),
|
||||
MEM_ADDR_SPACE (op)))
|
||||
break;
|
||||
win = 1;
|
||||
}
|
||||
|
|
15
gcc/recog.h
15
gcc/recog.h
|
@ -84,8 +84,13 @@ extern int num_validated_changes (void);
|
|||
extern void cancel_changes (int);
|
||||
extern int constrain_operands (int);
|
||||
extern int constrain_operands_cached (int);
|
||||
extern int memory_address_p (enum machine_mode, rtx);
|
||||
extern int strict_memory_address_p (enum machine_mode, rtx);
|
||||
extern int memory_address_addr_space_p (enum machine_mode, rtx, addr_space_t);
|
||||
#define memory_address_p(mode,addr) \
|
||||
memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC)
|
||||
extern int strict_memory_address_addr_space_p (enum machine_mode, rtx,
|
||||
addr_space_t);
|
||||
#define strict_memory_address_p(mode,addr) \
|
||||
strict_memory_address_addr_space_p ((mode), (addr), ADDR_SPACE_GENERIC)
|
||||
extern int validate_replace_rtx_subexp (rtx, rtx, rtx, rtx *);
|
||||
extern int validate_replace_rtx (rtx, rtx, rtx);
|
||||
extern int validate_replace_rtx_part (rtx, rtx, rtx *, rtx);
|
||||
|
@ -101,7 +106,11 @@ extern int reg_fits_class_p (rtx, enum reg_class, int, enum machine_mode);
|
|||
|
||||
extern int offsettable_memref_p (rtx);
|
||||
extern int offsettable_nonstrict_memref_p (rtx);
|
||||
extern int offsettable_address_p (int, enum machine_mode, rtx);
|
||||
extern int offsettable_address_addr_space_p (int, enum machine_mode, rtx,
|
||||
addr_space_t);
|
||||
#define offsettable_address_p(strict,mode,addr) \
|
||||
offsettable_address_addr_space_p ((strict), (mode), (addr), \
|
||||
ADDR_SPACE_GENERIC)
|
||||
extern int mode_dependent_address_p (rtx);
|
||||
|
||||
extern int recog (rtx, rtx, int *);
|
||||
|
|
66
gcc/reload.c
66
gcc/reload.c
|
@ -268,7 +268,8 @@ static bool alternative_allows_const_pool_ref (rtx, const char *, int);
|
|||
static rtx find_reloads_toplev (rtx, int, enum reload_type, int, int, rtx,
|
||||
int *);
|
||||
static rtx make_memloc (rtx, int);
|
||||
static int maybe_memory_address_p (enum machine_mode, rtx, rtx *);
|
||||
static int maybe_memory_address_addr_space_p (enum machine_mode, rtx,
|
||||
addr_space_t, rtx *);
|
||||
static int find_reloads_address (enum machine_mode, rtx *, rtx, rtx *,
|
||||
int, enum reload_type, int, rtx);
|
||||
static rtx subst_reg_equivs (rtx, rtx);
|
||||
|
@ -612,7 +613,8 @@ get_secondary_mem (rtx x ATTRIBUTE_UNUSED, enum machine_mode mode,
|
|||
didn't give us a new MEM, make a new one if it isn't valid. */
|
||||
|
||||
loc = eliminate_regs (secondary_memlocs[(int) mode], VOIDmode, NULL_RTX);
|
||||
mem_valid = strict_memory_address_p (mode, XEXP (loc, 0));
|
||||
mem_valid = strict_memory_address_addr_space_p (mode, XEXP (loc, 0),
|
||||
MEM_ADDR_SPACE (loc));
|
||||
|
||||
if (! mem_valid && loc == secondary_memlocs[(int) mode])
|
||||
loc = copy_rtx (loc);
|
||||
|
@ -2129,21 +2131,23 @@ hard_reg_set_here_p (unsigned int beg_regno, unsigned int end_regno, rtx x)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if ADDR is a valid memory address for mode MODE,
|
||||
and check that each pseudo reg has the proper kind of
|
||||
hard reg. */
|
||||
/* Return 1 if ADDR is a valid memory address for mode MODE
|
||||
in address space AS, and check that each pseudo reg has the
|
||||
proper kind of hard reg. */
|
||||
|
||||
int
|
||||
strict_memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr)
|
||||
strict_memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
|
||||
rtx addr, addr_space_t as)
|
||||
{
|
||||
#ifdef GO_IF_LEGITIMATE_ADDRESS
|
||||
gcc_assert (ADDR_SPACE_GENERIC_P (as));
|
||||
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
|
||||
return 0;
|
||||
|
||||
win:
|
||||
return 1;
|
||||
#else
|
||||
return targetm.legitimate_address_p (mode, addr, 1);
|
||||
return targetm.addr_space.legitimate_address_p (mode, addr, 1, as);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2247,6 +2251,10 @@ operands_match_p (rtx x, rtx y)
|
|||
if (GET_MODE (x) != GET_MODE (y))
|
||||
return 0;
|
||||
|
||||
/* MEMs refering to different address space are not equivalent. */
|
||||
if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
|
||||
return 0;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case CONST_INT:
|
||||
|
@ -4760,8 +4768,9 @@ find_reloads_toplev (rtx x, int opnum, enum reload_type type,
|
|||
#endif
|
||||
&& (reg_equiv_address[regno] != 0
|
||||
|| (reg_equiv_mem[regno] != 0
|
||||
&& (! strict_memory_address_p (GET_MODE (x),
|
||||
XEXP (reg_equiv_mem[regno], 0))
|
||||
&& (! strict_memory_address_addr_space_p
|
||||
(GET_MODE (x), XEXP (reg_equiv_mem[regno], 0),
|
||||
MEM_ADDR_SPACE (reg_equiv_mem[regno]))
|
||||
|| ! offsettable_memref_p (reg_equiv_mem[regno])
|
||||
|| num_not_at_initial_offset))))
|
||||
x = find_reloads_subreg_address (x, 1, opnum, type, ind_levels,
|
||||
|
@ -4819,18 +4828,19 @@ make_memloc (rtx ad, int regno)
|
|||
}
|
||||
|
||||
/* Returns true if AD could be turned into a valid memory reference
|
||||
to mode MODE by reloading the part pointed to by PART into a
|
||||
register. */
|
||||
to mode MODE in address space AS by reloading the part pointed to
|
||||
by PART into a register. */
|
||||
|
||||
static int
|
||||
maybe_memory_address_p (enum machine_mode mode, rtx ad, rtx *part)
|
||||
maybe_memory_address_addr_space_p (enum machine_mode mode, rtx ad,
|
||||
addr_space_t as, rtx *part)
|
||||
{
|
||||
int retv;
|
||||
rtx tem = *part;
|
||||
rtx reg = gen_rtx_REG (GET_MODE (tem), max_reg_num ());
|
||||
|
||||
*part = reg;
|
||||
retv = memory_address_p (mode, ad);
|
||||
retv = memory_address_addr_space_p (mode, ad, as);
|
||||
*part = tem;
|
||||
|
||||
return retv;
|
||||
|
@ -4866,6 +4876,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
rtx *loc, int opnum, enum reload_type type,
|
||||
int ind_levels, rtx insn)
|
||||
{
|
||||
addr_space_t as = memrefloc? MEM_ADDR_SPACE (*memrefloc)
|
||||
: ADDR_SPACE_GENERIC;
|
||||
int regno;
|
||||
int removed_and = 0;
|
||||
int op_index;
|
||||
|
@ -4893,7 +4905,9 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
if (reg_equiv_address[regno] != 0 || num_not_at_initial_offset)
|
||||
{
|
||||
tem = make_memloc (ad, regno);
|
||||
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
|
||||
if (! strict_memory_address_addr_space_p (GET_MODE (tem),
|
||||
XEXP (tem, 0),
|
||||
MEM_ADDR_SPACE (tem)))
|
||||
{
|
||||
rtx orig = tem;
|
||||
|
||||
|
@ -4909,7 +4923,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
address: only reg or reg+constant. */
|
||||
|
||||
if (ind_levels > 0
|
||||
&& strict_memory_address_p (mode, tem)
|
||||
&& strict_memory_address_addr_space_p (mode, tem, as)
|
||||
&& (REG_P (XEXP (tem, 0))
|
||||
|| (GET_CODE (XEXP (tem, 0)) == PLUS
|
||||
&& REG_P (XEXP (XEXP (tem, 0), 0))
|
||||
|
@ -4953,7 +4967,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (strict_memory_address_p (mode, ad))
|
||||
if (strict_memory_address_addr_space_p (mode, ad, as))
|
||||
{
|
||||
/* The address appears valid, so reloads are not needed.
|
||||
But the address may contain an eliminable register.
|
||||
|
@ -4976,14 +4990,14 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
return 0;
|
||||
|
||||
/* Check result for validity after substitution. */
|
||||
if (strict_memory_address_p (mode, ad))
|
||||
if (strict_memory_address_addr_space_p (mode, ad, as))
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef LEGITIMIZE_RELOAD_ADDRESS
|
||||
do
|
||||
{
|
||||
if (memrefloc)
|
||||
if (memrefloc && ADDR_SPACE_GENERIC_P (as))
|
||||
{
|
||||
LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
|
||||
ind_levels, win);
|
||||
|
@ -5160,8 +5174,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
|| operand == arg_pointer_rtx
|
||||
#endif
|
||||
|| operand == stack_pointer_rtx)
|
||||
&& ! maybe_memory_address_p (mode, ad,
|
||||
&XEXP (XEXP (ad, 0), 1 - op_index)))
|
||||
&& ! maybe_memory_address_addr_space_p
|
||||
(mode, ad, as, &XEXP (XEXP (ad, 0), 1 - op_index)))
|
||||
{
|
||||
rtx offset_reg;
|
||||
enum reg_class cls;
|
||||
|
@ -5199,7 +5213,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
tem = ad;
|
||||
if (GET_CODE (ad) == PLUS)
|
||||
tem = subst_indexed_address (ad);
|
||||
if (tem != ad && strict_memory_address_p (mode, tem))
|
||||
if (tem != ad && strict_memory_address_addr_space_p (mode, tem, as))
|
||||
{
|
||||
/* Ok, we win that way. Replace any additional eliminable
|
||||
registers. */
|
||||
|
@ -5209,7 +5223,8 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
|
||||
/* Make sure that didn't make the address invalid again. */
|
||||
|
||||
if (! subst_reg_equivs_changed || strict_memory_address_p (mode, tem))
|
||||
if (! subst_reg_equivs_changed
|
||||
|| strict_memory_address_addr_space_p (mode, tem, as))
|
||||
{
|
||||
*loc = tem;
|
||||
return 0;
|
||||
|
@ -5218,7 +5233,7 @@ find_reloads_address (enum machine_mode mode, rtx *memrefloc, rtx ad,
|
|||
|
||||
/* If constants aren't valid addresses, reload the constant address
|
||||
into a register. */
|
||||
if (CONSTANT_P (ad) && ! strict_memory_address_p (mode, ad))
|
||||
if (CONSTANT_P (ad) && ! strict_memory_address_addr_space_p (mode, ad, as))
|
||||
{
|
||||
/* If AD is an address in the constant pool, the MEM rtx may be shared.
|
||||
Unshare it so we can safely alter it. */
|
||||
|
@ -6180,8 +6195,9 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum,
|
|||
the address, there is nothing further to do. */
|
||||
if (reloaded == 0
|
||||
&& reg_equiv_mem[regno] != 0
|
||||
&& !strict_memory_address_p (GET_MODE (x),
|
||||
XEXP (reg_equiv_mem[regno], 0)))
|
||||
&& !strict_memory_address_addr_space_p
|
||||
(GET_MODE (x), XEXP (reg_equiv_mem[regno], 0),
|
||||
MEM_ADDR_SPACE (reg_equiv_mem[regno])))
|
||||
push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0,
|
||||
base_reg_class (GET_MODE (tem), MEM, SCRATCH),
|
||||
GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, \
|
||||
|
|
20
gcc/target.h
20
gcc/target.h
|
@ -694,6 +694,26 @@ struct gcc_target
|
|||
/* True if MODE is valid for a pointer in __attribute__((mode("MODE"))). */
|
||||
bool (* valid_pointer_mode) (enum machine_mode mode);
|
||||
|
||||
/* Support for named address spaces. */
|
||||
struct addr_space {
|
||||
/* True if an address is a valid memory address to a given named address
|
||||
space for a given mode. */
|
||||
bool (* legitimate_address_p) (enum machine_mode, rtx, bool, addr_space_t);
|
||||
|
||||
/* Return an updated address to convert an invalid pointer to a named
|
||||
address space to a valid one. If NULL_RTX is returned use machine
|
||||
independent methods to make the address valid. */
|
||||
rtx (* legitimize_address) (rtx, rtx, enum machine_mode, addr_space_t);
|
||||
|
||||
/* True if one named address space is a subset of another named address. */
|
||||
bool (* subset_p) (addr_space_t, addr_space_t);
|
||||
|
||||
/* Function to convert an rtl expression from one address space to
|
||||
another. */
|
||||
rtx (* convert) (rtx, tree, tree);
|
||||
|
||||
} addr_space;
|
||||
|
||||
/* True if MODE is valid for the target. By "valid", we mean able to
|
||||
be manipulated in non-trivial ways. In particular, this means all
|
||||
the arithmetic is supported. */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
29
gcc/tree.h
29
gcc/tree.h
|
@ -392,7 +392,12 @@ struct GTY(()) tree_base {
|
|||
unsigned packed_flag : 1;
|
||||
unsigned user_align : 1;
|
||||
|
||||
unsigned spare : 21;
|
||||
unsigned spare : 13;
|
||||
|
||||
/* This field is only used with type nodes; the only reason it is present
|
||||
in tree_base instead of tree_type is to save space. The size of the
|
||||
field must be large enough to hold addr_space_t values. */
|
||||
unsigned address_space : 8;
|
||||
|
||||
union tree_ann_d *ann;
|
||||
};
|
||||
|
@ -2169,6 +2174,9 @@ extern enum machine_mode vector_type_mode (const_tree);
|
|||
the term. */
|
||||
#define TYPE_RESTRICT(NODE) (TYPE_CHECK (NODE)->type.restrict_flag)
|
||||
|
||||
/* The address space the type is in. */
|
||||
#define TYPE_ADDR_SPACE(NODE) (TYPE_CHECK (NODE)->base.address_space)
|
||||
|
||||
/* There is a TYPE_QUAL value for each type qualifier. They can be
|
||||
combined by bitwise-or to form the complete set of qualifiers for a
|
||||
type. */
|
||||
|
@ -2178,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))
|
||||
|
|
15
gcc/varasm.c
15
gcc/varasm.c
|
@ -1168,11 +1168,17 @@ align_variable (tree decl, bool dont_output_data)
|
|||
static section *
|
||||
get_variable_section (tree decl, bool prefer_noswitch_p)
|
||||
{
|
||||
addr_space_t as = ADDR_SPACE_GENERIC;
|
||||
int reloc;
|
||||
|
||||
/* If the decl has been given an explicit section name, then it
|
||||
isn't common, and shouldn't be handled as such. */
|
||||
if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL)
|
||||
if (TREE_TYPE (decl) != error_mark_node)
|
||||
as = TYPE_ADDR_SPACE (TREE_TYPE (decl));
|
||||
|
||||
/* If the decl has been given an explicit section name, or it resides
|
||||
in a non-generic address space, then it isn't common, and shouldn't
|
||||
be handled as such. */
|
||||
if (DECL_COMMON (decl) && DECL_SECTION_NAME (decl) == NULL
|
||||
&& ADDR_SPACE_GENERIC_P (as))
|
||||
{
|
||||
if (DECL_THREAD_LOCAL_P (decl))
|
||||
return tls_comm_section;
|
||||
|
@ -1196,7 +1202,8 @@ get_variable_section (tree decl, bool prefer_noswitch_p)
|
|||
if (IN_NAMED_SECTION (decl))
|
||||
return get_named_section (decl, NULL, reloc);
|
||||
|
||||
if (!DECL_THREAD_LOCAL_P (decl)
|
||||
if (ADDR_SPACE_GENERIC_P (as)
|
||||
&& !DECL_THREAD_LOCAL_P (decl)
|
||||
&& !(prefer_noswitch_p && targetm.have_switchable_bss_sections)
|
||||
&& bss_initializer_p (decl))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue