re PR middle-end/42834 (memcpy folding overeager)

2010-07-01  Richard Guenther  <rguenther@suse.de>

	PR middle-end/42834
	PR middle-end/44468
	* doc/gimple.texi (is_gimple_mem_ref_addr): Document.
	* doc/generic.texi (References to storage): Document MEM_REF.
	* tree-pretty-print.c (dump_generic_node): Handle MEM_REF.
	(print_call_name): Likewise.
	* tree.c (recompute_tree_invariant_for_addr_expr): Handle MEM_REF.
	(build_simple_mem_ref_loc): New function.
	(mem_ref_offset): Likewise.
	* tree.h (build_simple_mem_ref_loc): Declare.
	(build_simple_mem_ref): Define.
	(mem_ref_offset): Declare.
	* fold-const.c: Include tree-flow.h.
	(operand_equal_p): Handle MEM_REF.
	(build_fold_addr_expr_with_type_loc): Likewise.
	(fold_comparison): Likewise.
	(fold_unary_loc): Fold
	VIEW_CONVERT_EXPR <T1, MEM_REF <T2, ...>> to MEM_REF <T1, ...>.
	(fold_binary_loc): Fold MEM[&MEM[p, CST1], CST2] to MEM[p, CST1 + CST2],
	fold MEM[&a.b, CST2] to MEM[&a, offsetof (a, b) + CST2].
	* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle MEM_REF.
	(ptr_deref_may_alias_ref_p_1): Likewise.
	(ao_ref_base_alias_set): Properly differentiate base object for
	offset and TBAA.
	(ao_ref_init_from_ptr_and_size): Use MEM_REF.
	(indirect_ref_may_alias_decl_p): Handle MEM_REFs properly.
	(indirect_refs_may_alias_p): Likewise.
	(refs_may_alias_p_1): Likewise.  Remove pointer SSA name def
	chasing code.
	(ref_maybe_used_by_call_p_1): Handle MEM_REF.
	(call_may_clobber_ref_p_1): Likewise.
	* dwarf2out.c (loc_list_from_tree): Handle MEM_REF.
	* expr.c (expand_assignment): Handle MEM_REF.
	(store_expr): Handle MEM_REFs from STRING_CSTs.
	(store_field): If expanding a MEM_REF of a non-addressable
	decl use bitfield operations.
	(get_inner_reference): Handle MEM_REF.
	(expand_expr_addr_expr_1): Likewise.
	(expand_expr_real_1): Likewise.
	* tree-eh.c (tree_could_trap_p): Handle MEM_REF.
	* alias.c (ao_ref_from_mem): Handle MEM_REF.
	(get_alias_set): Likewise.  Properly handle VIEW_CONVERT_EXPRs.
	* tree-data-ref.c (dr_analyze_innermost): Handle MEM_REF.
	(dr_analyze_indices): Likewise.
	(dr_analyze_alias): Likewise.
	(object_address_invariant_in_loop_p): Likewise.
	* gimplify.c (mark_addressable): Handle MEM_REF.
	(gimplify_cond_expr): Build MEM_REFs.
	(gimplify_modify_expr_to_memcpy): Likewise.
	(gimplify_init_ctor_preeval_1): Handle MEM_REF.
	(gimple_fold_indirect_ref): Adjust.
	(gimplify_expr): Handle MEM_REF.  Gimplify INDIRECT_REF to MEM_REF.
	* tree.def (MEM_REF): New tree code.
	* tree-dfa.c: Include toplev.h.
	(get_ref_base_and_extent): Handle MEM_REF.
	(get_addr_base_and_unit_offset): New function.
	* emit-rtl.c (set_mem_attributes_minus_bitpos): Handle MEM_REF.
	* gimple-fold.c (may_propagate_address_into_dereference): Handle
	MEM_REF.
	(maybe_fold_offset_to_array_ref): Allow possibly out-of bounds
	accesses if the array has just one dimension.  Remove always true
	parameter.  Do not require type compatibility here.
	(maybe_fold_offset_to_component_ref): Remove.
	(maybe_fold_stmt_indirect): Remove.
	(maybe_fold_reference): Remove INDIRECT_REF handling.
	Fold back to non-MEM_REF.
	(maybe_fold_offset_to_address): Simplify.  Deal with type
	mismatches here.
	(maybe_fold_reference): Likewise.
	(maybe_fold_stmt_addition): Likewise.  Also handle
	&ARRAY + I in addition to &ARRAY[0] + I.
	(fold_gimple_assign): Handle ADDR_EXPR of MEM_REFs.
	(gimple_get_relevant_ref_binfo): Handle MEM_REF.
	* cfgexpand.c (expand_debug_expr): Handle MEM_REF.
	* tree-ssa.c (useless_type_conversion_p): Make most pointer
	conversions useless.
	(warn_uninitialized_var): Handle MEM_REF.
	(maybe_rewrite_mem_ref_base): New function.
	(execute_update_addresses_taken): Implement re-writing of MEM_REFs
	to SSA form.
	* tree-inline.c (remap_gimple_op_r): Handle MEM_REF, remove
	INDIRECT_REF handling.
	(copy_tree_body_r): Handle MEM_REF.
	* gimple.c (is_gimple_addressable): Adjust.
	(is_gimple_address): Likewise.
	(is_gimple_invariant_address): ADDR_EXPRs of MEM_REFs with
	invariant base are invariant.
	(is_gimple_min_lval): Adjust.
	(is_gimple_mem_ref_addr): New function.
	(get_base_address): Handle MEM_REF.
	(count_ptr_derefs): Likewise.
	(get_base_loadstore): Likewise.
	* gimple.h (is_gimple_mem_ref_addr): Declare.
	(gimple_call_fndecl): Handle invariant MEM_REF addresses.
	* tree-cfg.c (verify_address): New function, split out from ...
	(verify_expr): ... here.  Use for verifying ADDR_EXPRs and
	the address operand of MEM_REFs.  Verify MEM_REFs.  Reject
	INDIRECT_REFs.
	(verify_types_in_gimple_min_lval): Handle MEM_REF.  Disallow
	INDIRECT_REF.  Allow conversions.
	(verify_types_in_gimple_reference): Verify VIEW_CONVERT_EXPR of
	a register does not change its size.
	(verify_types_in_gimple_reference): Verify MEM_REF.
	(verify_gimple_assign_single): Disallow INDIRECT_REF.
	Handle MEM_REF.
	* tree-ssa-operands.c (opf_non_addressable, opf_not_non_addressable):
	New.
	(mark_address_taken): Handle MEM_REF.
	(get_indirect_ref_operands): Pass through opf_not_non_addressable.
	(get_asm_expr_operands): Pass opf_not_non_addressable.
	(get_expr_operands): Handle opf_[not_]non_addressable.
	Handle MEM_REF.  Remove INDIRECT_REF handling.
	* tree-vrp.c: (check_array_ref): Handle MEM_REF.
	(search_for_addr_array): Likewise.
	(check_array_bounds): Likewise.
	(vrp_stmt_computes_nonzero): Adjust for MEM_REF.
	* tree-ssa-loop-im.c (for_each_index): Handle MEM_REF.
	(ref_always_accessed_p): Likewise.
	(gen_lsm_tmp_name): Likewise.  Handle ADDR_EXPR.
	* tree-complex.c (extract_component): Do not handle INDIRECT_REF.
	Handle MEM_REF.
	* cgraphbuild.c (mark_load): Properly check for NULL result
	from get_base_address.
	(mark_store): Likewise.
	* tree-ssa-loop-niter.c (array_at_struct_end_p): Handle MEM_REF.
	* tree-loop-distribution.c (generate_builtin): Exchange INDIRECT_REF
	handling for MEM_REF.
	* tree-scalar-evolution.c (follow_ssa_edge_expr): Handle
	&MEM[ptr + CST] similar to POINTER_PLUS_EXPR.
	* builtins.c (stabilize_va_list_loc): Use the function ABI
	valist type if we couldn't canonicalize the argument type.
	Always dereference with the canonical va-list type.
	(maybe_emit_free_warning): Handle MEM_REF.
	(fold_builtin_memory_op): Simplify and handle MEM_REFs in folding
	memmove to memcpy.
	* builtins.c (fold_builtin_memory_op): Use ref-all types
	for all memcpy foldings.
	* omp-low.c (build_receiver_ref): Adjust for MEM_REF.
	(build_outer_var_ref): Likewise.
	(scan_omp_1_op): Likewise.
	(lower_rec_input_clauses): Likewise.
	(lower_lastprivate_clauses): Likewise.
	(lower_reduction_clauses): Likewise.
	(lower_copyprivate_clauses): Likewise.
	(expand_omp_atomic_pipeline): Likewise.
	(expand_omp_atomic_mutex): Likewise.
	(create_task_copyfn): Likewise.
	* tree-ssa-sccvn.c (copy_reference_ops_from_ref): Handle MEM_REF.
	Remove old union trick.  Initialize constant offsets.
	(ao_ref_init_from_vn_reference): Likewise.  Do not handle
	INDIRECT_REF.  Init base_alias_set properly.
	(vn_reference_lookup_3): Replace INDIRECT_REF handling with
	MEM_REF.
	(vn_reference_fold_indirect): Adjust for MEM_REFs.
	(valueize_refs): Fold MEM_REFs.  Re-evaluate constant offset
	for ARRAY_REFs.
	(may_insert): Remove.
	(visit_reference_op_load): Do not test may_insert.
	(run_scc_vn): Remove parameter, do not fiddle with may_insert.
	* tree-ssa-sccvn.h (struct vn_reference_op_struct): Add
	a field to store the constant offset this op applies.
	(run_scc_vn): Adjust prototype.
	* cgraphunit.c (thunk_adjust): Adjust for MEM_REF.
	* tree-ssa-ccp.c (ccp_fold): Replace INDIRECT_REF folding with
	MEM_REF.  Propagate &foo + CST as &MEM[&foo, CST].  Do not
	bother about volatile qualifiers on pointers.
	(fold_const_aggregate_ref): Handle MEM_REF, do not handle INDIRECT_REF.
	* tree-ssa-loop-ivopts.c
	* tree-ssa-loop-ivopts.c (determine_base_object): Adjust
	for MEM_REF.
	(strip_offset_1): Likewise.
	(find_interesting_uses_address): Replace INDIRECT_REF handling with
	MEM_REF handling.
	(get_computation_cost_at): Likewise.
	* ipa-pure-const.c (check_op): Handle MEM_REF.
	* tree-stdarg.c (check_all_va_list_escapes): Adjust for MEM_REF.
	* tree-ssa-sink.c (is_hidden_global_store): Handle MEM_REF
	and constants.
	* ipa-inline.c (likely_eliminated_by_inlining_p): Handle MEM_REF.
	* tree-parloops.c (take_address_of): Adjust for MEM_REF.
	(eliminate_local_variables_1): Likewise.
	(create_call_for_reduction_1): Likewise.
	(create_loads_for_reductions): Likewise.
	(create_loads_and_stores_for_name): Likewise.
	* matrix-reorg.c (may_flatten_matrices_1): Sanitize.
	(ssa_accessed_in_tree): Handle MEM_REF.
	(ssa_accessed_in_assign_rhs): Likewise.
	(update_type_size): Likewise.
	(analyze_accesses_for_call_stmt): Likewise.
	(analyze_accesses_for_assign_stmt): Likewise.
	(transform_access_sites): Likewise.
	(transform_allocation_sites): Likewise.
	* tree-affine.c (tree_to_aff_combination): Handle MEM_REF.
	* tree-vect-data-refs.c (vect_create_addr_base_for_vector_ref): Do
	not handle INDIRECT_REF.
	* tree-ssa-phiopt.c (add_or_mark_expr): Handle MEM_REF.
	(cond_store_replacement): Likewise.
	* tree-ssa-pre.c (create_component_ref_by_pieces_1): Handle
	MEM_REF, no not handle INDIRECT_REFs.
	(insert_into_preds_of_block): Properly initialize avail.
	(phi_translate_1): Fold MEM_REFs.  Re-evaluate constant offset
	for ARRAY_REFs.  Properly handle reference lookups that
	require a bit re-interpretation.
	(can_PRE_operation): Do not handle INDIRECT_REF.  Handle MEM_REF.
	* tree-sra.c
	* tree-sra.c (build_access_from_expr_1): Handle MEM_REF.
	(build_ref_for_offset_1): Remove.
	(build_ref_for_offset): Build MEM_REFs.
	(gate_intra_sra): Disable for now.
	(sra_ipa_modify_expr): Handle MEM_REF.
	(ipa_early_sra_gate): Disable for now.
	* tree-sra.c (create_access): Swap INDIRECT_REF handling for
	MEM_REF handling.
	(disqualify_base_of_expr): Likewise.
	(ptr_parm_has_direct_uses): Swap INDIRECT_REF handling for
	MEM_REF handling.
	(sra_ipa_modify_expr): Remove INDIRECT_REF handling.
	Use mem_ref_offset.  Remove bogus folding.
	(build_access_from_expr_1): Properly handle MEM_REF for
	non IPA-SRA.
	(make_fancy_name_1): Add support for MEM_REF.
	* tree-predcom.c (ref_at_iteration): Handle MEM_REFs.
	* tree-mudflap.c (mf_xform_derefs_1): Adjust for MEM_REF.
	* ipa-prop.c (compute_complex_assign_jump_func): Handle MEM_REF.
	(compute_complex_ancestor_jump_func): Likewise.
	(ipa_analyze_virtual_call_uses): Likewise.
	* tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Replace
	INDIRECT_REF folding with more generalized MEM_REF folding.
	(tree_ssa_forward_propagate_single_use_vars): Adjust accordingly.
	(forward_propagate_addr_into_variable_array_index): Also handle
	&ARRAY + I in addition to &ARRAY[0] + I.
	* tree-ssa-dce.c (ref_may_be_aliased): Handle MEM_REF.
	* tree-ssa-ter.c (find_replaceable_in_bb): Avoid TER if that
	creates assignments with overlap.
	* tree-nested.c (get_static_chain): Adjust for MEM_REF.
	(get_frame_field): Likewise.
	(get_nonlocal_debug_decl): Likewise.
	(convert_nonlocal_reference_op): Likewise.
	(struct nesting_info): Add mem_refs pointer-set.
	(create_nesting_tree): Allocate it.
	(convert_local_reference_op): Insert to be folded mem-refs.
	(fold_mem_refs): New function.
	(finalize_nesting_tree_1): Perform defered folding of mem-refs 
	(free_nesting_tree): Free the pointer-set.
	* tree-vect-stmts.c (vectorizable_store): Adjust for MEM_REF.
	(vectorizable_load): Likewise.
	* tree-ssa-phiprop.c (phiprop_insert_phi): Adjust for MEM_REF.
	(propagate_with_phi): Likewise.
	* tree-object-size.c (addr_object_size): Handle MEM_REFs
	instead of INDIRECT_REFs.
	(compute_object_offset): Handle MEM_REF.
	(plus_stmt_object_size): Handle MEM_REF.
	(collect_object_sizes_for): Dispatch to plus_stmt_object_size
	for &MEM_REF.
	* tree-flow.h (get_addr_base_and_unit_offset): Declare.
	(symbol_marked_for_renaming): Likewise.
	* Makefile.in (tree-dfa.o): Add $(TOPLEV_H).
	(fold-const.o): Add $(TREE_FLOW_H).
	* tree-ssa-structalias.c (get_constraint_for_1): Handle MEM_REF.
	(find_func_clobbers): Likewise.
	* ipa-struct-reorg.c (decompose_indirect_ref_acc): Handle MEM_REF.
	(decompose_access): Likewise.
	(replace_field_acc): Likewise.
	(replace_field_access_stmt): Likewise.
	(insert_new_var_in_stmt): Likewise.
	(get_stmt_accesses): Likewise.
	(reorg_structs_drive): Disable.
	* config/i386/i386.c (ix86_va_start): Adjust for MEM_REF.
	(ix86_canonical_va_list_type): Likewise.

	cp/
	* cp-gimplify.c (cp_gimplify_expr): Open-code the rhs
	predicate we are looking for, allow non-gimplified
	INDIRECT_REFs.

	testsuite/
	* gcc.c-torture/execute/20100316-1.c: New testcase.
	* gcc.c-torture/execute/pr44468.c: Likewise.
	* gcc.c-torture/compile/20100609-1.c: Likewise.
	* gcc.dg/volatile2.c: Adjust.
	* gcc.dg/plugin/selfassign.c: Likewise.
	* gcc.dg/pr36902.c: Likewise.
	* gcc.dg/tree-ssa/foldaddr-2.c: Remove.
	* gcc.dg/tree-ssa/foldaddr-3.c: Likewise.
	* gcc.dg/tree-ssa/forwprop-8.c: Adjust.
	* gcc.dg/tree-ssa/pr17141-1.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-13.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-14.c: Likewise.
	* gcc.dg/tree-ssa/ssa-ccp-21.c: Likewise.
	* gcc.dg/tree-ssa/pta-ptrarith-1.c: Likewise.
	* gcc.dg/tree-ssa/20030807-7.c: Likewise.
	* gcc.dg/tree-ssa/forwprop-10.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-1.c: Likewise.
	* gcc.dg/tree-ssa/pta-ptrarith-2.c: Likewise.
	* gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.
	* gcc.dg/tree-ssa/forwprop-1.c: Likewise.
	* gcc.dg/tree-ssa/forwprop-2.c: Likewise.
	* gcc.dg/tree-ssa/struct-aliasing-1.c: Likewise.
	* gcc.dg/tree-ssa/ssa-ccp-25.c: Likewise.
	* gcc.dg/tree-ssa/ssa-pre-26.c: Likewise.
	* gcc.dg/tree-ssa/struct-aliasing-2.c: Likewise.
	* gcc.dg/tree-ssa/ssa-ccp-26.c: Likewise.
	* gcc.dg/tree-ssa/ssa-sccvn-4.c: Likewise.
	* gcc.dg/tree-ssa/ssa-pre-7.c: Likewise.
	* gcc.dg/tree-ssa/forwprop-5.c: Likewise.
	* gcc.dg/struct/w_prof_two_strs.c: XFAIL.
	* gcc.dg/struct/wo_prof_escape_arg_to_local.c: Likewise.
	* gcc.dg/struct/wo_prof_global_var.c: Likewise.
	* gcc.dg/struct/wo_prof_malloc_size_var.c: Likewise.
	* gcc.dg/struct/w_prof_local_array.c: Likewise.
	* gcc.dg/struct/w_prof_single_str_global.c: Likewise.
	* gcc.dg/struct/wo_prof_escape_str_init.c: Likewise.
	* gcc.dg/struct/wo_prof_array_through_pointer.c: Likewise.
	* gcc.dg/struct/w_prof_global_array.c: Likewise.
	* gcc.dg/struct/wo_prof_array_field.c: Likewise.
	* gcc.dg/struct/wo_prof_single_str_local.c: Likewise.
	* gcc.dg/struct/w_prof_local_var.c: Likewise.
	* gcc.dg/struct/wo_prof_two_strs.c: Likewise.
	* gcc.dg/struct/wo_prof_empty_str.c: Likewise.
	* gcc.dg/struct/wo_prof_local_array.c: Likewise.
	* gcc.dg/struct/w_prof_global_var.c: Likewise.
	* gcc.dg/struct/wo_prof_single_str_global.c: Likewise.
	* gcc.dg/struct/wo_prof_escape_substr_value.c: Likewise.
	* gcc.dg/struct/wo_prof_global_array.c: Likewise.
	* gcc.dg/struct/wo_prof_escape_return.c: Likewise.
	* gcc.dg/struct/wo_prof_escape_substr_array.c: Likewise.
	* gcc.dg/struct/wo_prof_double_malloc.c: Likewise.
	* gcc.dg/struct/w_ratio_cold_str.c: Likewise.
	* gcc.dg/struct/wo_prof_escape_substr_pointer.c: Likewise.
	* gcc.dg/struct/wo_prof_local_var.c: Likewise.
	* gcc.dg/tree-prof/stringop-1.c: Adjust.
	* g++.dg/tree-ssa/pr31146.C: Likewise.
	* g++.dg/tree-ssa/copyprop-1.C: Likewise.
	* g++.dg/tree-ssa/pr33604.C: Likewise.
	* g++.dg/plugin/selfassign.c: Likewise.
	* gfortran.dg/array_memcpy_3.f90: Likewise.
	* gfortran.dg/array_memcpy_4.f90: Likewise.
	* c-c++-common/torture/pr42834.c: New testcase.

From-SVN: r161655
This commit is contained in:
Richard Guenther 2010-07-01 08:49:19 +00:00 committed by Richard Biener
parent 952b984e86
commit 70f348148c
136 changed files with 3111 additions and 1468 deletions

View File

@ -1,3 +1,275 @@
2010-07-01 Richard Guenther <rguenther@suse.de>
PR middle-end/42834
PR middle-end/44468
* doc/gimple.texi (is_gimple_mem_ref_addr): Document.
* doc/generic.texi (References to storage): Document MEM_REF.
* tree-pretty-print.c (dump_generic_node): Handle MEM_REF.
(print_call_name): Likewise.
* tree.c (recompute_tree_invariant_for_addr_expr): Handle MEM_REF.
(build_simple_mem_ref_loc): New function.
(mem_ref_offset): Likewise.
* tree.h (build_simple_mem_ref_loc): Declare.
(build_simple_mem_ref): Define.
(mem_ref_offset): Declare.
* fold-const.c: Include tree-flow.h.
(operand_equal_p): Handle MEM_REF.
(build_fold_addr_expr_with_type_loc): Likewise.
(fold_comparison): Likewise.
(fold_unary_loc): Fold
VIEW_CONVERT_EXPR <T1, MEM_REF <T2, ...>> to MEM_REF <T1, ...>.
(fold_binary_loc): Fold MEM[&MEM[p, CST1], CST2] to MEM[p, CST1 + CST2],
fold MEM[&a.b, CST2] to MEM[&a, offsetof (a, b) + CST2].
* tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Handle MEM_REF.
(ptr_deref_may_alias_ref_p_1): Likewise.
(ao_ref_base_alias_set): Properly differentiate base object for
offset and TBAA.
(ao_ref_init_from_ptr_and_size): Use MEM_REF.
(indirect_ref_may_alias_decl_p): Handle MEM_REFs properly.
(indirect_refs_may_alias_p): Likewise.
(refs_may_alias_p_1): Likewise. Remove pointer SSA name def
chasing code.
(ref_maybe_used_by_call_p_1): Handle MEM_REF.
(call_may_clobber_ref_p_1): Likewise.
* dwarf2out.c (loc_list_from_tree): Handle MEM_REF.
* expr.c (expand_assignment): Handle MEM_REF.
(store_expr): Handle MEM_REFs from STRING_CSTs.
(store_field): If expanding a MEM_REF of a non-addressable
decl use bitfield operations.
(get_inner_reference): Handle MEM_REF.
(expand_expr_addr_expr_1): Likewise.
(expand_expr_real_1): Likewise.
* tree-eh.c (tree_could_trap_p): Handle MEM_REF.
* alias.c (ao_ref_from_mem): Handle MEM_REF.
(get_alias_set): Likewise. Properly handle VIEW_CONVERT_EXPRs.
* tree-data-ref.c (dr_analyze_innermost): Handle MEM_REF.
(dr_analyze_indices): Likewise.
(dr_analyze_alias): Likewise.
(object_address_invariant_in_loop_p): Likewise.
* gimplify.c (mark_addressable): Handle MEM_REF.
(gimplify_cond_expr): Build MEM_REFs.
(gimplify_modify_expr_to_memcpy): Likewise.
(gimplify_init_ctor_preeval_1): Handle MEM_REF.
(gimple_fold_indirect_ref): Adjust.
(gimplify_expr): Handle MEM_REF. Gimplify INDIRECT_REF to MEM_REF.
* tree.def (MEM_REF): New tree code.
* tree-dfa.c: Include toplev.h.
(get_ref_base_and_extent): Handle MEM_REF.
(get_addr_base_and_unit_offset): New function.
* emit-rtl.c (set_mem_attributes_minus_bitpos): Handle MEM_REF.
* gimple-fold.c (may_propagate_address_into_dereference): Handle
MEM_REF.
(maybe_fold_offset_to_array_ref): Allow possibly out-of bounds
accesses if the array has just one dimension. Remove always true
parameter. Do not require type compatibility here.
(maybe_fold_offset_to_component_ref): Remove.
(maybe_fold_stmt_indirect): Remove.
(maybe_fold_reference): Remove INDIRECT_REF handling.
Fold back to non-MEM_REF.
(maybe_fold_offset_to_address): Simplify. Deal with type
mismatches here.
(maybe_fold_reference): Likewise.
(maybe_fold_stmt_addition): Likewise. Also handle
&ARRAY + I in addition to &ARRAY[0] + I.
(fold_gimple_assign): Handle ADDR_EXPR of MEM_REFs.
(gimple_get_relevant_ref_binfo): Handle MEM_REF.
* cfgexpand.c (expand_debug_expr): Handle MEM_REF.
* tree-ssa.c (useless_type_conversion_p): Make most pointer
conversions useless.
(warn_uninitialized_var): Handle MEM_REF.
(maybe_rewrite_mem_ref_base): New function.
(execute_update_addresses_taken): Implement re-writing of MEM_REFs
to SSA form.
* tree-inline.c (remap_gimple_op_r): Handle MEM_REF, remove
INDIRECT_REF handling.
(copy_tree_body_r): Handle MEM_REF.
* gimple.c (is_gimple_addressable): Adjust.
(is_gimple_address): Likewise.
(is_gimple_invariant_address): ADDR_EXPRs of MEM_REFs with
invariant base are invariant.
(is_gimple_min_lval): Adjust.
(is_gimple_mem_ref_addr): New function.
(get_base_address): Handle MEM_REF.
(count_ptr_derefs): Likewise.
(get_base_loadstore): Likewise.
* gimple.h (is_gimple_mem_ref_addr): Declare.
(gimple_call_fndecl): Handle invariant MEM_REF addresses.
* tree-cfg.c (verify_address): New function, split out from ...
(verify_expr): ... here. Use for verifying ADDR_EXPRs and
the address operand of MEM_REFs. Verify MEM_REFs. Reject
INDIRECT_REFs.
(verify_types_in_gimple_min_lval): Handle MEM_REF. Disallow
INDIRECT_REF. Allow conversions.
(verify_types_in_gimple_reference): Verify VIEW_CONVERT_EXPR of
a register does not change its size.
(verify_types_in_gimple_reference): Verify MEM_REF.
(verify_gimple_assign_single): Disallow INDIRECT_REF.
Handle MEM_REF.
* tree-ssa-operands.c (opf_non_addressable, opf_not_non_addressable):
New.
(mark_address_taken): Handle MEM_REF.
(get_indirect_ref_operands): Pass through opf_not_non_addressable.
(get_asm_expr_operands): Pass opf_not_non_addressable.
(get_expr_operands): Handle opf_[not_]non_addressable.
Handle MEM_REF. Remove INDIRECT_REF handling.
* tree-vrp.c: (check_array_ref): Handle MEM_REF.
(search_for_addr_array): Likewise.
(check_array_bounds): Likewise.
(vrp_stmt_computes_nonzero): Adjust for MEM_REF.
* tree-ssa-loop-im.c (for_each_index): Handle MEM_REF.
(ref_always_accessed_p): Likewise.
(gen_lsm_tmp_name): Likewise. Handle ADDR_EXPR.
* tree-complex.c (extract_component): Do not handle INDIRECT_REF.
Handle MEM_REF.
* cgraphbuild.c (mark_load): Properly check for NULL result
from get_base_address.
(mark_store): Likewise.
* tree-ssa-loop-niter.c (array_at_struct_end_p): Handle MEM_REF.
* tree-loop-distribution.c (generate_builtin): Exchange INDIRECT_REF
handling for MEM_REF.
* tree-scalar-evolution.c (follow_ssa_edge_expr): Handle
&MEM[ptr + CST] similar to POINTER_PLUS_EXPR.
* builtins.c (stabilize_va_list_loc): Use the function ABI
valist type if we couldn't canonicalize the argument type.
Always dereference with the canonical va-list type.
(maybe_emit_free_warning): Handle MEM_REF.
(fold_builtin_memory_op): Simplify and handle MEM_REFs in folding
memmove to memcpy.
* builtins.c (fold_builtin_memory_op): Use ref-all types
for all memcpy foldings.
* omp-low.c (build_receiver_ref): Adjust for MEM_REF.
(build_outer_var_ref): Likewise.
(scan_omp_1_op): Likewise.
(lower_rec_input_clauses): Likewise.
(lower_lastprivate_clauses): Likewise.
(lower_reduction_clauses): Likewise.
(lower_copyprivate_clauses): Likewise.
(expand_omp_atomic_pipeline): Likewise.
(expand_omp_atomic_mutex): Likewise.
(create_task_copyfn): Likewise.
* tree-ssa-sccvn.c (copy_reference_ops_from_ref): Handle MEM_REF.
Remove old union trick. Initialize constant offsets.
(ao_ref_init_from_vn_reference): Likewise. Do not handle
INDIRECT_REF. Init base_alias_set properly.
(vn_reference_lookup_3): Replace INDIRECT_REF handling with
MEM_REF.
(vn_reference_fold_indirect): Adjust for MEM_REFs.
(valueize_refs): Fold MEM_REFs. Re-evaluate constant offset
for ARRAY_REFs.
(may_insert): Remove.
(visit_reference_op_load): Do not test may_insert.
(run_scc_vn): Remove parameter, do not fiddle with may_insert.
* tree-ssa-sccvn.h (struct vn_reference_op_struct): Add
a field to store the constant offset this op applies.
(run_scc_vn): Adjust prototype.
* cgraphunit.c (thunk_adjust): Adjust for MEM_REF.
* tree-ssa-ccp.c (ccp_fold): Replace INDIRECT_REF folding with
MEM_REF. Propagate &foo + CST as &MEM[&foo, CST]. Do not
bother about volatile qualifiers on pointers.
(fold_const_aggregate_ref): Handle MEM_REF, do not handle INDIRECT_REF.
* tree-ssa-loop-ivopts.c
* tree-ssa-loop-ivopts.c (determine_base_object): Adjust
for MEM_REF.
(strip_offset_1): Likewise.
(find_interesting_uses_address): Replace INDIRECT_REF handling with
MEM_REF handling.
(get_computation_cost_at): Likewise.
* ipa-pure-const.c (check_op): Handle MEM_REF.
* tree-stdarg.c (check_all_va_list_escapes): Adjust for MEM_REF.
* tree-ssa-sink.c (is_hidden_global_store): Handle MEM_REF
and constants.
* ipa-inline.c (likely_eliminated_by_inlining_p): Handle MEM_REF.
* tree-parloops.c (take_address_of): Adjust for MEM_REF.
(eliminate_local_variables_1): Likewise.
(create_call_for_reduction_1): Likewise.
(create_loads_for_reductions): Likewise.
(create_loads_and_stores_for_name): Likewise.
* matrix-reorg.c (may_flatten_matrices_1): Sanitize.
(ssa_accessed_in_tree): Handle MEM_REF.
(ssa_accessed_in_assign_rhs): Likewise.
(update_type_size): Likewise.
(analyze_accesses_for_call_stmt): Likewise.
(analyze_accesses_for_assign_stmt): Likewise.
(transform_access_sites): Likewise.
(transform_allocation_sites): Likewise.
* tree-affine.c (tree_to_aff_combination): Handle MEM_REF.
* tree-vect-data-refs.c (vect_create_addr_base_for_vector_ref): Do
not handle INDIRECT_REF.
* tree-ssa-phiopt.c (add_or_mark_expr): Handle MEM_REF.
(cond_store_replacement): Likewise.
* tree-ssa-pre.c (create_component_ref_by_pieces_1): Handle
MEM_REF, no not handle INDIRECT_REFs.
(insert_into_preds_of_block): Properly initialize avail.
(phi_translate_1): Fold MEM_REFs. Re-evaluate constant offset
for ARRAY_REFs. Properly handle reference lookups that
require a bit re-interpretation.
(can_PRE_operation): Do not handle INDIRECT_REF. Handle MEM_REF.
* tree-sra.c
* tree-sra.c (build_access_from_expr_1): Handle MEM_REF.
(build_ref_for_offset_1): Remove.
(build_ref_for_offset): Build MEM_REFs.
(gate_intra_sra): Disable for now.
(sra_ipa_modify_expr): Handle MEM_REF.
(ipa_early_sra_gate): Disable for now.
* tree-sra.c (create_access): Swap INDIRECT_REF handling for
MEM_REF handling.
(disqualify_base_of_expr): Likewise.
(ptr_parm_has_direct_uses): Swap INDIRECT_REF handling for
MEM_REF handling.
(sra_ipa_modify_expr): Remove INDIRECT_REF handling.
Use mem_ref_offset. Remove bogus folding.
(build_access_from_expr_1): Properly handle MEM_REF for
non IPA-SRA.
(make_fancy_name_1): Add support for MEM_REF.
* tree-predcom.c (ref_at_iteration): Handle MEM_REFs.
* tree-mudflap.c (mf_xform_derefs_1): Adjust for MEM_REF.
* ipa-prop.c (compute_complex_assign_jump_func): Handle MEM_REF.
(compute_complex_ancestor_jump_func): Likewise.
(ipa_analyze_virtual_call_uses): Likewise.
* tree-ssa-forwprop.c (forward_propagate_addr_expr_1): Replace
INDIRECT_REF folding with more generalized MEM_REF folding.
(tree_ssa_forward_propagate_single_use_vars): Adjust accordingly.
(forward_propagate_addr_into_variable_array_index): Also handle
&ARRAY + I in addition to &ARRAY[0] + I.
* tree-ssa-dce.c (ref_may_be_aliased): Handle MEM_REF.
* tree-ssa-ter.c (find_replaceable_in_bb): Avoid TER if that
creates assignments with overlap.
* tree-nested.c (get_static_chain): Adjust for MEM_REF.
(get_frame_field): Likewise.
(get_nonlocal_debug_decl): Likewise.
(convert_nonlocal_reference_op): Likewise.
(struct nesting_info): Add mem_refs pointer-set.
(create_nesting_tree): Allocate it.
(convert_local_reference_op): Insert to be folded mem-refs.
(fold_mem_refs): New function.
(finalize_nesting_tree_1): Perform defered folding of mem-refs
(free_nesting_tree): Free the pointer-set.
* tree-vect-stmts.c (vectorizable_store): Adjust for MEM_REF.
(vectorizable_load): Likewise.
* tree-ssa-phiprop.c (phiprop_insert_phi): Adjust for MEM_REF.
(propagate_with_phi): Likewise.
* tree-object-size.c (addr_object_size): Handle MEM_REFs
instead of INDIRECT_REFs.
(compute_object_offset): Handle MEM_REF.
(plus_stmt_object_size): Handle MEM_REF.
(collect_object_sizes_for): Dispatch to plus_stmt_object_size
for &MEM_REF.
* tree-flow.h (get_addr_base_and_unit_offset): Declare.
(symbol_marked_for_renaming): Likewise.
* Makefile.in (tree-dfa.o): Add $(TOPLEV_H).
(fold-const.o): Add $(TREE_FLOW_H).
* tree-ssa-structalias.c (get_constraint_for_1): Handle MEM_REF.
(find_func_clobbers): Likewise.
* ipa-struct-reorg.c (decompose_indirect_ref_acc): Handle MEM_REF.
(decompose_access): Likewise.
(replace_field_acc): Likewise.
(replace_field_access_stmt): Likewise.
(insert_new_var_in_stmt): Likewise.
(get_stmt_accesses): Likewise.
(reorg_structs_drive): Disable.
* config/i386/i386.c (ix86_va_start): Adjust for MEM_REF.
(ix86_canonical_va_list_type): Likewise.
2010-06-30 Joern Rennecke <joern.rennecke@embecosm.com>
PR other/44566

View File

@ -2510,7 +2510,7 @@ tree-dfa.o : tree-dfa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(TREE_INLINE_H) $(HASHTAB_H) pointer-set.h $(FLAGS_H) $(FUNCTION_H) \
$(TIMEVAR_H) convert.h $(TM_H) coretypes.h langhooks.h $(TREE_DUMP_H) \
$(TREE_PASS_H) $(PARAMS_H) $(CGRAPH_H) $(BASIC_BLOCK_H) $(GIMPLE_H) \
tree-pretty-print.h
tree-pretty-print.h $(TOPLEV_H)
tree-ssa-operands.o : tree-ssa-operands.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \
$(FLAGS_H) $(FUNCTION_H) $(TM_H) $(TIMEVAR_H) $(TREE_PASS_H) $(TOPLEV_H) \
@ -2789,7 +2789,7 @@ tree-diagnostic.o : tree-diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(FLAGS_H) $(TOPLEV_H) $(HASHTAB_H) $(EXPR_H) $(RTL_H) \
$(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h $(TARGET_H) \
$(GIMPLE_H) realmpfr.h
$(GIMPLE_H) realmpfr.h $(TREE_FLOW_H)
diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
version.h $(INPUT_H) intl.h $(DIAGNOSTIC_H) diagnostic.def
opts.o : opts.c opts.h options.h $(TOPLEV_H) $(CONFIG_H) $(SYSTEM_H) \

View File

@ -279,7 +279,8 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
/* If this is a pointer dereference of a non-SSA_NAME punt.
??? We could replace it with a pointer to anything. */
if (INDIRECT_REF_P (base)
if ((INDIRECT_REF_P (base)
|| TREE_CODE (base) == MEM_REF)
&& TREE_CODE (TREE_OPERAND (base, 0)) != SSA_NAME)
return false;
@ -293,10 +294,7 @@ ao_ref_from_mem (ao_ref *ref, const_rtx mem)
void *namep;
namep = pointer_map_contains (cfun->gimple_df->decls_to_pointers, base);
if (namep)
{
ref->base_alias_set = get_alias_set (base);
ref->base = build1 (INDIRECT_REF, TREE_TYPE (base), *(tree *)namep);
}
ref->base = build_simple_mem_ref (*(tree *)namep);
}
ref->ref_alias_set = MEM_ALIAS_SET (mem);
@ -648,8 +646,8 @@ get_alias_set (tree t)
{
tree inner;
/* Remove any nops, then give the language a chance to do
something with this tree before we look at it. */
/* Give the language a chance to do something with this tree
before we look at it. */
STRIP_NOPS (t);
set = lang_hooks.get_alias_set (t);
if (set != -1)
@ -659,21 +657,41 @@ get_alias_set (tree t)
if (TREE_CODE (t) == TARGET_MEM_REF)
t = TMR_ORIGINAL (t);
/* First see if the actual object referenced is an INDIRECT_REF from a
restrict-qualified pointer or a "void *". */
/* Get the base object of the reference. */
inner = t;
while (handled_component_p (inner))
{
/* If there is a VIEW_CONVERT_EXPR in the chain we cannot use
the type of any component references that wrap it to
determine the alias-set. */
if (TREE_CODE (inner) == VIEW_CONVERT_EXPR)
t = TREE_OPERAND (inner, 0);
inner = TREE_OPERAND (inner, 0);
STRIP_NOPS (inner);
}
/* Handle pointer dereferences here, they can override the
alias-set. */
if (INDIRECT_REF_P (inner))
{
set = get_deref_alias_set_1 (TREE_OPERAND (inner, 0));
if (set != -1)
return set;
}
else if (TREE_CODE (inner) == MEM_REF)
{
set = get_deref_alias_set_1 (TREE_OPERAND (inner, 1));
if (set != -1)
return set;
}
/* If the innermost reference is a MEM_REF that has a
conversion embedded treat it like a VIEW_CONVERT_EXPR above,
using the memory access type for determining the alias-set. */
if (TREE_CODE (inner) == MEM_REF
&& (TYPE_MAIN_VARIANT (TREE_TYPE (inner))
!= TYPE_MAIN_VARIANT
(TREE_TYPE (TREE_TYPE (TREE_OPERAND (inner, 1))))))
return get_deref_alias_set (TREE_OPERAND (inner, 1));
/* Otherwise, pick up the outermost object that we could have a pointer
to, processing conversions as above. */

View File

@ -4455,7 +4455,10 @@ stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
{
tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
gcc_assert (vatype != NULL_TREE);
/* The current way of determining the type of valist is completely
bogus. We should have the information on the va builtin instead. */
if (!vatype)
vatype = targetm.fn_abi_va_list (cfun->decl);
if (TREE_CODE (vatype) == ARRAY_TYPE)
{
@ -4474,21 +4477,21 @@ stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
}
else
{
tree pt;
tree pt = build_pointer_type (vatype);
if (! needs_lvalue)
{
if (! TREE_SIDE_EFFECTS (valist))
return valist;
pt = build_pointer_type (vatype);
valist = fold_build1_loc (loc, ADDR_EXPR, pt, valist);
TREE_SIDE_EFFECTS (valist) = 1;
}
if (TREE_SIDE_EFFECTS (valist))
valist = save_expr (valist);
valist = build_fold_indirect_ref_loc (loc, valist);
valist = fold_build2_loc (loc, MEM_REF,
vatype, valist, build_int_cst (pt, 0));
}
return valist;
@ -8346,6 +8349,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
{
tree srctype, desttype;
int src_align, dest_align;
tree off0;
if (endp == 3)
{
@ -8371,37 +8375,26 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
}
/* If *src and *dest can't overlap, optimize into memcpy as well. */
srcvar = build_fold_indirect_ref_loc (loc, src);
destvar = build_fold_indirect_ref_loc (loc, dest);
if (srcvar
&& !TREE_THIS_VOLATILE (srcvar)
&& destvar
&& !TREE_THIS_VOLATILE (destvar))
if (TREE_CODE (src) == ADDR_EXPR
&& TREE_CODE (dest) == ADDR_EXPR)
{
tree src_base, dest_base, fn;
HOST_WIDE_INT src_offset = 0, dest_offset = 0;
HOST_WIDE_INT size = -1;
HOST_WIDE_INT maxsize = -1;
src_base = srcvar;
if (handled_component_p (src_base))
src_base = get_ref_base_and_extent (src_base, &src_offset,
&size, &maxsize);
dest_base = destvar;
if (handled_component_p (dest_base))
dest_base = get_ref_base_and_extent (dest_base, &dest_offset,
&size, &maxsize);
srcvar = TREE_OPERAND (src, 0);
src_base = get_ref_base_and_extent (srcvar, &src_offset,
&size, &maxsize);
destvar = TREE_OPERAND (dest, 0);
dest_base = get_ref_base_and_extent (destvar, &dest_offset,
&size, &maxsize);
if (host_integerp (len, 1))
{
maxsize = tree_low_cst (len, 1);
if (maxsize
> INTTYPE_MAXIMUM (HOST_WIDE_INT) / BITS_PER_UNIT)
maxsize = -1;
else
maxsize *= BITS_PER_UNIT;
}
maxsize = tree_low_cst (len, 1);
else
maxsize = -1;
src_offset /= BITS_PER_UNIT;
dest_offset /= BITS_PER_UNIT;
if (SSA_VAR_P (src_base)
&& SSA_VAR_P (dest_base))
{
@ -8410,13 +8403,25 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
dest_offset, maxsize))
return NULL_TREE;
}
else if (TREE_CODE (src_base) == INDIRECT_REF
&& TREE_CODE (dest_base) == INDIRECT_REF)
else if (TREE_CODE (src_base) == MEM_REF
&& TREE_CODE (dest_base) == MEM_REF)
{
double_int off;
if (! operand_equal_p (TREE_OPERAND (src_base, 0),
TREE_OPERAND (dest_base, 0), 0)
|| ranges_overlap_p (src_offset, maxsize,
dest_offset, maxsize))
TREE_OPERAND (dest_base, 0), 0))
return NULL_TREE;
off = double_int_add (mem_ref_offset (src_base),
shwi_to_double_int (src_offset));
if (!double_int_fits_in_shwi_p (off))
return NULL_TREE;
src_offset = off.low;
off = double_int_add (mem_ref_offset (dest_base),
shwi_to_double_int (dest_offset));
if (!double_int_fits_in_shwi_p (off))
return NULL_TREE;
dest_offset = off.low;
if (ranges_overlap_p (src_offset, maxsize,
dest_offset, maxsize))
return NULL_TREE;
}
else
@ -8472,12 +8477,12 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
dest = build1 (NOP_EXPR, build_pointer_type (desttype), dest);
}
if (!srctype || !desttype
|| TREE_ADDRESSABLE (srctype)
|| TREE_ADDRESSABLE (desttype)
|| !TYPE_SIZE_UNIT (srctype)
|| !TYPE_SIZE_UNIT (desttype)
|| TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
|| TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
|| TYPE_VOLATILE (srctype)
|| TYPE_VOLATILE (desttype))
|| TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST)
return NULL_TREE;
src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
@ -8489,97 +8494,44 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
if (!ignore)
dest = builtin_save_expr (dest);
srcvar = NULL_TREE;
if (tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
{
srcvar = build_fold_indirect_ref_loc (loc, src);
if (TREE_THIS_VOLATILE (srcvar))
return NULL_TREE;
else if (!tree_int_cst_equal (tree_expr_size (srcvar), len))
srcvar = NULL_TREE;
/* With memcpy, it is possible to bypass aliasing rules, so without
this check i.e. execute/20060930-2.c would be misoptimized,
because it use conflicting alias set to hold argument for the
memcpy call. This check is probably unnecessary with
-fno-strict-aliasing. Similarly for destvar. See also
PR29286. */
else if (!var_decl_component_p (srcvar))
srcvar = NULL_TREE;
}
/* Build accesses at offset zero with a ref-all character type. */
off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
ptr_mode, true), 0);
destvar = NULL_TREE;
if (tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
{
destvar = build_fold_indirect_ref_loc (loc, dest);
if (TREE_THIS_VOLATILE (destvar))
return NULL_TREE;
else if (!tree_int_cst_equal (tree_expr_size (destvar), len))
destvar = NULL_TREE;
else if (!var_decl_component_p (destvar))
destvar = NULL_TREE;
}
destvar = dest;
STRIP_NOPS (destvar);
if (TREE_CODE (destvar) == ADDR_EXPR
&& var_decl_component_p (TREE_OPERAND (destvar, 0))
&& tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
destvar = fold_build2 (MEM_REF, desttype, destvar, off0);
else
destvar = NULL_TREE;
srcvar = src;
STRIP_NOPS (srcvar);
if (TREE_CODE (srcvar) == ADDR_EXPR
&& var_decl_component_p (TREE_OPERAND (srcvar, 0))
&& tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
srcvar, off0);
else
srcvar = NULL_TREE;
if (srcvar == NULL_TREE && destvar == NULL_TREE)
return NULL_TREE;
if (srcvar == NULL_TREE)
{
tree srcptype;
if (TREE_ADDRESSABLE (TREE_TYPE (destvar)))
return NULL_TREE;
srctype = build_qualified_type (desttype, 0);
if (src_align < (int) TYPE_ALIGN (srctype))
{
if (AGGREGATE_TYPE_P (srctype)
|| SLOW_UNALIGNED_ACCESS (TYPE_MODE (srctype), src_align))
return NULL_TREE;
srctype = build_variant_type_copy (srctype);
TYPE_ALIGN (srctype) = src_align;
TYPE_USER_ALIGN (srctype) = 1;
TYPE_PACKED (srctype) = 1;
}
srcptype = build_pointer_type_for_mode (srctype, ptr_mode, true);
src = fold_convert_loc (loc, srcptype, src);
srcvar = build_fold_indirect_ref_loc (loc, src);
STRIP_NOPS (src);
srcvar = fold_build2 (MEM_REF, desttype, src, off0);
}
else if (destvar == NULL_TREE)
{
tree destptype;
if (TREE_ADDRESSABLE (TREE_TYPE (srcvar)))
return NULL_TREE;
desttype = build_qualified_type (srctype, 0);
if (dest_align < (int) TYPE_ALIGN (desttype))
{
if (AGGREGATE_TYPE_P (desttype)
|| SLOW_UNALIGNED_ACCESS (TYPE_MODE (desttype), dest_align))
return NULL_TREE;
desttype = build_variant_type_copy (desttype);
TYPE_ALIGN (desttype) = dest_align;
TYPE_USER_ALIGN (desttype) = 1;
TYPE_PACKED (desttype) = 1;
}
destptype = build_pointer_type_for_mode (desttype, ptr_mode, true);
dest = fold_convert_loc (loc, destptype, dest);
destvar = build_fold_indirect_ref_loc (loc, dest);
STRIP_NOPS (dest);
destvar = fold_build2 (MEM_REF, srctype, dest, off0);
}
if (srctype == desttype
|| (gimple_in_ssa_p (cfun)
&& useless_type_conversion_p (desttype, srctype)))
expr = srcvar;
else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
|| POINTER_TYPE_P (TREE_TYPE (srcvar)))
&& (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
|| POINTER_TYPE_P (TREE_TYPE (destvar))))
expr = fold_convert_loc (loc, TREE_TYPE (destvar), srcvar);
else
expr = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
TREE_TYPE (destvar), srcvar);
expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
}
if (ignore)
@ -12068,7 +12020,7 @@ maybe_emit_free_warning (tree exp)
return;
arg = get_base_address (TREE_OPERAND (arg, 0));
if (arg == NULL || INDIRECT_REF_P (arg))
if (arg == NULL || INDIRECT_REF_P (arg) || TREE_CODE (arg) == MEM_REF)
return;
if (SSA_VAR_P (arg))

View File

@ -2438,6 +2438,11 @@ expand_debug_expr (tree exp)
return op0;
}
case MEM_REF:
/* ??? FIXME. */
if (!integer_zerop (TREE_OPERAND (exp, 1)))
return NULL;
/* Fallthru. */
case INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:

View File

@ -275,7 +275,7 @@ mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t,
void *data ATTRIBUTE_UNUSED)
{
t = get_base_address (t);
if (TREE_CODE (t) == VAR_DECL
if (t && TREE_CODE (t) == VAR_DECL
&& (TREE_STATIC (t) || DECL_EXTERNAL (t)))
{
struct varpool_node *vnode = varpool_node (t);
@ -300,7 +300,7 @@ mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t,
void *data ATTRIBUTE_UNUSED)
{
t = get_base_address (t);
if (TREE_CODE (t) == VAR_DECL
if (t && TREE_CODE (t) == VAR_DECL
&& (TREE_STATIC (t) || DECL_EXTERNAL (t)))
{
struct varpool_node *vnode = varpool_node (t);

View File

@ -1364,8 +1364,7 @@ thunk_adjust (gimple_stmt_iterator * bsi,
vtabletmp2 = create_tmp_var (TREE_TYPE (TREE_TYPE (vtabletmp)),
"vtableaddr");
stmt = gimple_build_assign (vtabletmp2,
build1 (INDIRECT_REF,
TREE_TYPE (vtabletmp2), vtabletmp));
build_simple_mem_ref (vtabletmp));
gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
mark_symbols_for_renaming (stmt);
find_referenced_vars_in (stmt);
@ -1384,9 +1383,7 @@ thunk_adjust (gimple_stmt_iterator * bsi,
vtabletmp3 = create_tmp_var (TREE_TYPE (TREE_TYPE (vtabletmp2)),
"vcalloffset");
stmt = gimple_build_assign (vtabletmp3,
build1 (INDIRECT_REF,
TREE_TYPE (vtabletmp3),
vtabletmp2));
build_simple_mem_ref (vtabletmp2));
gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
mark_symbols_for_renaming (stmt);
find_referenced_vars_in (stmt);

View File

@ -6025,7 +6025,7 @@ alpha_stdarg_optimize_hook (struct stdarg_info *si, const_gimple stmt)
rhs = gimple_assign_rhs1 (stmt);
while (handled_component_p (rhs))
rhs = TREE_OPERAND (rhs, 0);
if (TREE_CODE (rhs) != INDIRECT_REF
if (TREE_CODE (rhs) != MEM_REF
|| TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME)
return false;

View File

@ -7093,11 +7093,17 @@ ix86_va_start (tree valist, rtx nextarg)
f_ovf = TREE_CHAIN (f_fpr);
f_sav = TREE_CHAIN (f_ovf);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
valist = build_simple_mem_ref (valist);
TREE_TYPE (valist) = TREE_TYPE (sysv_va_list_type_node);
/* The following should be folded into the MEM_REF offset. */
gpr = build3 (COMPONENT_REF, TREE_TYPE (f_gpr), unshare_expr (valist),
f_gpr, NULL_TREE);
fpr = build3 (COMPONENT_REF, TREE_TYPE (f_fpr), unshare_expr (valist),
f_fpr, NULL_TREE);
ovf = build3 (COMPONENT_REF, TREE_TYPE (f_ovf), unshare_expr (valist),
f_ovf, NULL_TREE);
sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), unshare_expr (valist),
f_sav, NULL_TREE);
/* Count number of gp and fp argument registers used. */
words = crtl->args.info.words;
@ -30619,10 +30625,12 @@ ix86_canonical_va_list_type (tree type)
tree wtype, htype;
/* Resolve references and pointers to va_list type. */
if (INDIRECT_REF_P (type))
if (TREE_CODE (type) == MEM_REF)
type = TREE_TYPE (type);
else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
type = TREE_TYPE (type);
else if (POINTER_TYPE_P (type) && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
type = TREE_TYPE (type);
if (TARGET_64BIT)
{

View File

@ -13682,7 +13682,7 @@ rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
case RESULT_DECL:
case SSA_NAME:
case REAL_CST:
case INDIRECT_REF:
case MEM_REF:
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
case VIEW_CONVERT_EXPR:

View File

@ -7886,7 +7886,7 @@ sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
lab_false = create_artificial_label (UNKNOWN_LOCATION);
lab_over = create_artificial_label (UNKNOWN_LOCATION);
valist = build1 (INDIRECT_REF, ptr_type_node, addr);
valist = build_simple_mem_ref (addr);
if (pass_as_float)
{

View File

@ -4171,7 +4171,7 @@ spu_gimplify_va_arg_expr (tree valist, tree type, gimple_seq * pre_p,
f_args = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
f_skip = TREE_CHAIN (f_args);
valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
valist = build_simple_mem_ref (valist);
args =
build3 (COMPONENT_REF, TREE_TYPE (f_args), valist, f_args, NULL_TREE);
skip =

View File

@ -1,3 +1,9 @@
2010-07-01 Richard Guenther <rguenther@suse.de>
* cp-gimplify.c (cp_gimplify_expr): Open-code the rhs
predicate we are looking for, allow non-gimplified
INDIRECT_REFs.
2010-06-30 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44628

View File

@ -575,7 +575,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR,
TREE_TYPE (op0), op1);
else if ((rhs_predicate_for (op0)) (op1)
else if ((is_gimple_lvalue (op1) || INDIRECT_REF_P (op1))
&& !(TREE_CODE (op1) == CALL_EXPR
&& CALL_EXPR_RETURN_SLOT_OPT (op1))
&& is_really_empty_class (TREE_TYPE (op0)))

View File

@ -1116,6 +1116,7 @@ target system bytes are not the same width as host system bytes.
@subsection References to storage
@tindex ADDR_EXPR
@tindex INDIRECT_REF
@tindex MEM_REF
@tindex ARRAY_REF
@tindex ARRAY_RANGE_REF
@tindex TARGET_MEM_REF
@ -1176,6 +1177,13 @@ These nodes are used to represent the object pointed to by a pointer.
The operand is the pointer being dereferenced; it will always have
pointer or reference type.
@item MEM_REF
These nodes are used to represent the object pointed to by a pointer
offset by a constant.
The first operand is the pointer being dereferenced; it will always have
pointer or reference type. The second operand is a pointer constant.
Its type is specifying the type to be used for type-based alias analysis.
@item COMPONENT_REF
These nodes represent non-static data member accesses. The first
operand is the object (rather than a pointer to it); the second operand

View File

@ -452,8 +452,8 @@ becomes
The same rule holds for arguments to a @code{GIMPLE_CALL}.
The target of an assignment is usually a variable, but can also be an
@code{INDIRECT_REF} or a compound lvalue as described below.
The target of an assignment is usually a variable, but can also be a
@code{MEM_REF} or a compound lvalue as described below.
@menu
* Compound Expressions::
@ -664,6 +664,11 @@ Return true if t is a valid expression to use as the function
called by a @code{GIMPLE_CALL}.
@end deftypefn
@deftypefn {GIMPLE function} is_gimple_mem_ref_addr (tree t)
Return true if t is a valid expression to use as first operand
of a @code{MEM_REF} expression.
@end deftypefn
@deftypefn {GIMPLE function} is_gimple_constant (tree t)
Return true if t is a valid gimple constant.
@end deftypefn

View File

@ -15160,6 +15160,11 @@ loc_list_from_tree (tree loc, int want_address)
}
break;
case MEM_REF:
/* ??? FIXME. */
if (!integer_zerop (TREE_OPERAND (loc, 1)))
return 0;
/* Fallthru. */
case INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:

View File

@ -1614,6 +1614,35 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
|| TREE_CODE (t) == ALIGN_INDIRECT_REF
|| TYPE_ALIGN_OK (type))
align = MAX (align, TYPE_ALIGN (type));
else if (TREE_CODE (t) == MEM_REF)
{
HOST_WIDE_INT aoff = BITS_PER_UNIT;
if (host_integerp (TREE_OPERAND (t, 1), 1))
{
HOST_WIDE_INT ioff = TREE_INT_CST_LOW (TREE_OPERAND (t, 1));
aoff = (ioff & -ioff) * BITS_PER_UNIT;
}
if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
&& DECL_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
align = MAX (align,
DECL_ALIGN (TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
else if (TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
&& CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (t, 0), 0)))
{
align = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (t, 0), 0)));
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (TREE_OPERAND (TREE_OPERAND (t, 0), 0), align);
#endif
}
else
/* This technically isn't correct. We can't really derive
alignment information from types. */
align = MAX (align,
TYPE_ALIGN (TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 1)))));
if (!integer_zerop (TREE_OPERAND (t, 1))
&& aoff < align)
align = aoff;
}
else
if (TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
{
@ -1654,6 +1683,9 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
|| TREE_CODE (base) == BIT_FIELD_REF)
base = TREE_OPERAND (base, 0);
if (TREE_CODE (base) == MEM_REF
&& TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR)
base = TREE_OPERAND (TREE_OPERAND (base, 0), 0);
if (DECL_P (base))
{
if (CODE_CONTAINS_STRUCT (TREE_CODE (base), TS_DECL_WITH_VIS))
@ -1774,7 +1806,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
}
/* If this is an indirect reference, record it. */
else if (TREE_CODE (t) == INDIRECT_REF
else if (TREE_CODE (t) == MEM_REF
|| TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
{
expr = t;
@ -1784,7 +1816,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
}
/* If this is an indirect reference, record it. */
else if (TREE_CODE (t) == INDIRECT_REF
else if (TREE_CODE (t) == MEM_REF
|| TREE_CODE (t) == MISALIGNED_INDIRECT_REF)
{
expr = t;

View File

@ -4213,6 +4213,10 @@ expand_assignment (tree to, tree from, bool nontemporal)
an array element in an unaligned packed structure field, has the same
problem. */
if (handled_component_p (to)
/* ??? We only need to handle MEM_REF here if the access is not
a full access of the base object. */
|| (TREE_CODE (to) == MEM_REF
&& TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR)
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
enum machine_mode mode1;
@ -4686,6 +4690,51 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
BLOCK_OP_NORMAL);
return NULL_RTX;
}
else if (TREE_CODE (exp) == MEM_REF
&& TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == STRING_CST
&& integer_zerop (TREE_OPERAND (exp, 1))
&& !nontemporal && !call_param_p
&& TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
{
/* Optimize initialization of an array with a STRING_CST. */
HOST_WIDE_INT exp_len, str_copy_len;
rtx dest_mem;
tree str = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
exp_len = int_expr_size (exp);
if (exp_len <= 0)
goto normal_expr;
str_copy_len = strlen (TREE_STRING_POINTER (str));
if (str_copy_len < TREE_STRING_LENGTH (str) - 1)
goto normal_expr;
str_copy_len = TREE_STRING_LENGTH (str);
if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
{
str_copy_len += STORE_MAX_PIECES - 1;
str_copy_len &= ~(STORE_MAX_PIECES - 1);
}
str_copy_len = MIN (str_copy_len, exp_len);
if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str,
CONST_CAST(char *, TREE_STRING_POINTER (str)),
MEM_ALIGN (target), false))
goto normal_expr;
dest_mem = target;
dest_mem = store_by_pieces (dest_mem,
str_copy_len, builtin_strncpy_read_str,
CONST_CAST(char *, TREE_STRING_POINTER (str)),
MEM_ALIGN (target), false,
exp_len > str_copy_len ? 1 : 0);
if (exp_len > str_copy_len)
clear_storage (adjust_address (dest_mem, BLKmode, 0),
GEN_INT (exp_len - str_copy_len),
BLOCK_OP_NORMAL);
return NULL_RTX;
}
else
{
rtx tmp_target;
@ -5852,7 +5901,15 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
operations. */
|| (bitsize >= 0
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
&& compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
&& compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0)
/* If we are expanding a MEM_REF of a non-BLKmode non-addressable
decl we must use bitfield operations. */
|| (bitsize >= 0
&& TREE_CODE (exp) == MEM_REF
&& TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& DECL_P (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
&& !TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (exp, 0),0 ))
&& DECL_MODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != BLKmode))
{
rtx temp;
gimple nop_def;
@ -6113,6 +6170,24 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
goto done;
break;
case MEM_REF:
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
{
tree off = TREE_OPERAND (exp, 1);
if (!integer_zerop (off))
{
double_int boff, coff = mem_ref_offset (exp);
boff = double_int_lshift (coff,
BITS_PER_UNIT == 8
? 3 : exact_log2 (BITS_PER_UNIT),
HOST_BITS_PER_DOUBLE_INT, true);
bit_offset = double_int_add (bit_offset, boff);
}
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
}
goto done;
default:
goto done;
}
@ -6873,6 +6948,16 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
/* This case will happen via recursion for &a->b. */
return expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
case MEM_REF:
{
tree tem = TREE_OPERAND (exp, 0);
if (!integer_zerop (TREE_OPERAND (exp, 1)))
tem = build2 (POINTER_PLUS_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
tem,
double_int_to_tree (sizetype, mem_ref_offset (exp)));
return expand_expr (tem, target, tmode, modifier);
}
case CONST_DECL:
/* Expand the initializer like constants above. */
return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0);
@ -8684,6 +8769,71 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
}
return temp;
case MEM_REF:
{
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))));
enum machine_mode address_mode;
tree base = TREE_OPERAND (exp, 0);
/* Handle expansion of non-aliased memory with non-BLKmode. That
might end up in a register. */
if (TREE_CODE (base) == ADDR_EXPR)
{
HOST_WIDE_INT offset = mem_ref_offset (exp).low;
tree bit_offset;
base = TREE_OPERAND (base, 0);
if (!DECL_P (base))
{
HOST_WIDE_INT off;
base = get_addr_base_and_unit_offset (base, &off);
gcc_assert (base);
offset += off;
}
/* If we are expanding a MEM_REF of a non-BLKmode non-addressable
decl we must use bitfield operations. */
if (DECL_P (base)
&& !TREE_ADDRESSABLE (base)
&& DECL_MODE (base) != BLKmode
&& DECL_RTL_SET_P (base)
&& !MEM_P (DECL_RTL (base)))
{
tree bftype;
if (offset == 0
&& host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
&& (GET_MODE_BITSIZE (DECL_MODE (base))
== TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))
return expand_expr (build1 (VIEW_CONVERT_EXPR,
TREE_TYPE (exp), base),
target, tmode, modifier);
bit_offset = bitsize_int (offset * BITS_PER_UNIT);
bftype = TREE_TYPE (base);
if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
bftype = TREE_TYPE (exp);
return expand_expr (build3 (BIT_FIELD_REF, bftype,
base,
TYPE_SIZE (TREE_TYPE (exp)),
bit_offset),
target, tmode, modifier);
}
}
address_mode = targetm.addr_space.address_mode (as);
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, address_mode,
EXPAND_NORMAL);
if (!integer_zerop (TREE_OPERAND (exp, 1)))
{
rtx off;
off = immed_double_int_const (mem_ref_offset (exp), address_mode);
op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
}
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);
if (TREE_THIS_VOLATILE (exp))
MEM_VOLATILE_P (temp) = 1;
return temp;
}
case ARRAY_REF:
{

View File

@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "md5.h"
#include "gimple.h"
#include "tree-flow.h"
/* Nonzero if we are folding constants inside an initializer; zero
otherwise. */
@ -2591,6 +2592,17 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
case IMAGPART_EXPR:
return OP_SAME (0);
case MEM_REF:
/* Require equal access sizes. We can have incomplete types
for array references of variable-sized arrays from the
Fortran frontent though. */
return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1))
|| (TYPE_SIZE (TREE_TYPE (arg0))
&& TYPE_SIZE (TREE_TYPE (arg1))
&& operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
TYPE_SIZE (TREE_TYPE (arg1)), flags)))
&& OP_SAME (0) && OP_SAME (1));
case ARRAY_REF:
case ARRAY_RANGE_REF:
/* Operands 2 and 3 may be null.
@ -7596,6 +7608,9 @@ build_fold_addr_expr_with_type_loc (location_t loc, tree t, tree ptrtype)
SET_EXPR_LOCATION (t, loc);
}
}
else if (TREE_CODE (t) == MEM_REF
&& integer_zerop (TREE_OPERAND (t, 1)))
return TREE_OPERAND (t, 0);
else if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
{
t = build_fold_addr_expr_loc (loc, TREE_OPERAND (t, 0));
@ -8014,6 +8029,9 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
return fold_build1_loc (loc, VIEW_CONVERT_EXPR,
type, TREE_OPERAND (op0, 0));
if (TREE_CODE (op0) == MEM_REF)
return fold_build2_loc (loc, MEM_REF, type,
TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1));
/* For integral conversions with the same precision or pointer
conversions use a NOP_EXPR instead. */
@ -8665,6 +8683,11 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
else if (TREE_CODE (arg0) == POINTER_PLUS_EXPR)
{
base0 = TREE_OPERAND (arg0, 0);
if (TREE_CODE (base0) == ADDR_EXPR)
{
base0 = TREE_OPERAND (base0, 0);
indirect_base0 = true;
}
offset0 = TREE_OPERAND (arg0, 1);
}
@ -8682,6 +8705,11 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
else if (TREE_CODE (arg1) == POINTER_PLUS_EXPR)
{
base1 = TREE_OPERAND (arg1, 0);
if (TREE_CODE (base1) == ADDR_EXPR)
{
base1 = TREE_OPERAND (base1, 0);
indirect_base1 = true;
}
offset1 = TREE_OPERAND (arg1, 1);
}
@ -9524,6 +9552,36 @@ fold_binary_loc (location_t loc,
switch (code)
{
case MEM_REF:
/* MEM[&MEM[p, CST1], CST2] -> MEM[p, CST1 + CST2]. */
if (TREE_CODE (arg0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 0)) == MEM_REF)
{
tree iref = TREE_OPERAND (arg0, 0);
return fold_build2 (MEM_REF, type,
TREE_OPERAND (iref, 0),
int_const_binop (PLUS_EXPR, arg1,
TREE_OPERAND (iref, 1), 0));
}
/* MEM[&a.b, CST2] -> MEM[&a, offsetof (a, b) + CST2]. */
if (TREE_CODE (arg0) == ADDR_EXPR
&& handled_component_p (TREE_OPERAND (arg0, 0)))
{
tree base;
HOST_WIDE_INT coffset;
base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0),
&coffset);
if (!base)
return NULL_TREE;
return fold_build2 (MEM_REF, type,
build_fold_addr_expr (base),
int_const_binop (PLUS_EXPR, arg1,
size_int (coffset), 0));
}
return NULL_TREE;
case POINTER_PLUS_EXPR:
/* 0 +p index -> (type)index */
if (integer_zerop (arg0))

View File

@ -82,7 +82,7 @@ get_symbol_constant_value (tree sym)
bool
may_propagate_address_into_dereference (tree addr, tree deref)
{
gcc_assert (INDIRECT_REF_P (deref)
gcc_assert (TREE_CODE (deref) == MEM_REF
&& TREE_CODE (addr) == ADDR_EXPR);
/* Don't propagate if ADDR's operand has incomplete type. */
@ -108,15 +108,12 @@ may_propagate_address_into_dereference (tree addr, tree deref)
/* A subroutine of fold_stmt. Attempts to fold *(A+O) to A[X].
BASE is an array type. OFFSET is a byte displacement. ORIG_TYPE
is the desired result type.
BASE is an array type. OFFSET is a byte displacement.
LOC is the location of the original expression. */
static tree
maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset,
tree orig_type,
bool allow_negative_idx)
maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset)
{
tree min_idx, idx, idx_type, elt_offset = integer_zero_node;
tree array_type, elt_type, elt_size;
@ -145,8 +142,6 @@ maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset,
if (TREE_CODE (array_type) != ARRAY_TYPE)
return NULL_TREE;
elt_type = TREE_TYPE (array_type);
if (!useless_type_conversion_p (orig_type, elt_type))
return NULL_TREE;
/* Use signed size type for intermediate computation on the index. */
idx_type = ssizetype;
@ -219,34 +214,22 @@ maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset,
char *(c[4]);
c[3][2];
should not be simplified into (*c)[14] or tree-vrp will
give false warnings. The same is true for
struct A { long x; char d[0]; } *a;
(char *)a - 4;
which should be not folded to &a->d[-8]. */
if (domain_type
&& TYPE_MAX_VALUE (domain_type)
&& TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST)
give false warnings.
This is only an issue for multi-dimensional arrays. */
if (TREE_CODE (elt_type) == ARRAY_TYPE
&& domain_type)
{
tree up_bound = TYPE_MAX_VALUE (domain_type);
if (tree_int_cst_lt (up_bound, idx)
/* Accesses after the end of arrays of size 0 (gcc
extension) and 1 are likely intentional ("struct
hack"). */
&& compare_tree_int (up_bound, 1) > 0)
if (TYPE_MAX_VALUE (domain_type)
&& TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST
&& tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), idx))
return NULL_TREE;
else if (TYPE_MIN_VALUE (domain_type)
&& TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST
&& tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type)))
return NULL_TREE;
else if (compare_tree_int (idx, 0) < 0)
return NULL_TREE;
}
if (domain_type
&& TYPE_MIN_VALUE (domain_type))
{
if (!allow_negative_idx
&& TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST
&& tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type)))
return NULL_TREE;
}
else if (!allow_negative_idx
&& compare_tree_int (idx, 0) < 0)
return NULL_TREE;
{
tree t = build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE);
@ -256,340 +239,55 @@ maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset,
}
/* Attempt to fold *(S+O) to S.X.
BASE is a record type. OFFSET is a byte displacement. ORIG_TYPE
is the desired result type.
LOC is the location of the original expression. */
static tree
maybe_fold_offset_to_component_ref (location_t loc, tree record_type,
tree base, tree offset, tree orig_type)
{
tree f, t, field_type, tail_array_field, field_offset;
tree ret;
tree new_base;
if (TREE_CODE (record_type) != RECORD_TYPE
&& TREE_CODE (record_type) != UNION_TYPE
&& TREE_CODE (record_type) != QUAL_UNION_TYPE)
return NULL_TREE;
/* Short-circuit silly cases. */
if (useless_type_conversion_p (record_type, orig_type))
return NULL_TREE;
tail_array_field = NULL_TREE;
for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f))
{
int cmp;
if (TREE_CODE (f) != FIELD_DECL)
continue;
if (DECL_BIT_FIELD (f))
continue;
if (!DECL_FIELD_OFFSET (f))
continue;
field_offset = byte_position (f);
if (TREE_CODE (field_offset) != INTEGER_CST)
continue;
/* ??? Java creates "interesting" fields for representing base classes.
They have no name, and have no context. With no context, we get into
trouble with nonoverlapping_component_refs_p. Skip them. */
if (!DECL_FIELD_CONTEXT (f))
continue;
/* The previous array field isn't at the end. */
tail_array_field = NULL_TREE;
/* Check to see if this offset overlaps with the field. */
cmp = tree_int_cst_compare (field_offset, offset);
if (cmp > 0)
continue;
field_type = TREE_TYPE (f);
/* Here we exactly match the offset being checked. If the types match,
then we can return that field. */
if (cmp == 0
&& useless_type_conversion_p (orig_type, field_type))
{
t = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
return t;
}
/* Don't care about offsets into the middle of scalars. */
if (!AGGREGATE_TYPE_P (field_type))
continue;
/* Check for array at the end of the struct. This is often
used as for flexible array members. We should be able to
turn this into an array access anyway. */
if (TREE_CODE (field_type) == ARRAY_TYPE)
tail_array_field = f;
/* Check the end of the field against the offset. */
if (!DECL_SIZE_UNIT (f)
|| TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST)
continue;
t = int_const_binop (MINUS_EXPR, offset, field_offset, 1);
if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f)))
continue;
/* If we matched, then set offset to the displacement into
this field. */
new_base = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
SET_EXPR_LOCATION (new_base, loc);
/* Recurse to possibly find the match. */
ret = maybe_fold_offset_to_array_ref (loc, new_base, t, orig_type,
f == TYPE_FIELDS (record_type));
if (ret)
return ret;
ret = maybe_fold_offset_to_component_ref (loc, field_type, new_base, t,
orig_type);
if (ret)
return ret;
}
if (!tail_array_field)
return NULL_TREE;
f = tail_array_field;
field_type = TREE_TYPE (f);
offset = int_const_binop (MINUS_EXPR, offset, byte_position (f), 1);
/* If we get here, we've got an aggregate field, and a possibly
nonzero offset into them. Recurse and hope for a valid match. */
base = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE);
SET_EXPR_LOCATION (base, loc);
t = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type,
f == TYPE_FIELDS (record_type));
if (t)
return t;
return maybe_fold_offset_to_component_ref (loc, field_type, base, offset,
orig_type);
}
/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type
or BASE[index] or by combination of those.
/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE[index].
LOC is the location of original expression.
Before attempting the conversion strip off existing ADDR_EXPRs and
handled component refs. */
Before attempting the conversion strip off existing ADDR_EXPRs. */
tree
maybe_fold_offset_to_reference (location_t loc, tree base, tree offset,
tree orig_type)
{
tree ret;
tree type;
STRIP_NOPS (base);
if (TREE_CODE (base) != ADDR_EXPR)
return NULL_TREE;
base = TREE_OPERAND (base, 0);
/* Handle case where existing COMPONENT_REF pick e.g. wrong field of union,
so it needs to be removed and new COMPONENT_REF constructed.
The wrong COMPONENT_REF are often constructed by folding the
(type *)&object within the expression (type *)&object+offset */
if (handled_component_p (base))
{
HOST_WIDE_INT sub_offset, size, maxsize;
tree newbase;
newbase = get_ref_base_and_extent (base, &sub_offset,
&size, &maxsize);
gcc_assert (newbase);
if (size == maxsize
&& size != -1
&& !(sub_offset & (BITS_PER_UNIT - 1)))
{
base = newbase;
if (sub_offset)
offset = int_const_binop (PLUS_EXPR, offset,
build_int_cst (TREE_TYPE (offset),
sub_offset / BITS_PER_UNIT), 1);
}
}
if (useless_type_conversion_p (orig_type, TREE_TYPE (base))
if (types_compatible_p (orig_type, TREE_TYPE (base))
&& integer_zerop (offset))
return base;
type = TREE_TYPE (base);
ret = maybe_fold_offset_to_component_ref (loc, type, base, offset, orig_type);
if (!ret)
ret = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type, true);
return ret;
ret = maybe_fold_offset_to_array_ref (loc, base, offset);
if (ret && types_compatible_p (orig_type, TREE_TYPE (ret)))
return ret;
return NULL_TREE;
}
/* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type
or &BASE[index] or by combination of those.
LOC is the location of the original expression.
Before attempting the conversion strip off existing component refs. */
/* Attempt to express (ORIG_TYPE)ADDR+OFFSET as (*ADDR)[index].
LOC is the location of the original expression. */
tree
maybe_fold_offset_to_address (location_t loc, tree addr, tree offset,
tree orig_type)
{
tree t;
tree base, ret;
gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr))
&& POINTER_TYPE_P (orig_type));
t = maybe_fold_offset_to_reference (loc, addr, offset,
TREE_TYPE (orig_type));
if (t != NULL_TREE)
STRIP_NOPS (addr);
if (TREE_CODE (addr) != ADDR_EXPR)
return NULL_TREE;
base = TREE_OPERAND (addr, 0);
ret = maybe_fold_offset_to_array_ref (loc, base, offset);
if (ret)
{
tree orig = addr;
tree ptr_type;
/* For __builtin_object_size to function correctly we need to
make sure not to fold address arithmetic so that we change
reference from one array to another. This would happen for
example for
struct X { char s1[10]; char s2[10] } s;
char *foo (void) { return &s.s2[-4]; }
where we need to avoid generating &s.s1[6]. As the C and
C++ frontends create different initial trees
(char *) &s.s1 + -4 vs. &s.s1[-4] we have to do some
sophisticated comparisons here. Note that checking for the
condition after the fact is easier than trying to avoid doing
the folding. */
STRIP_NOPS (orig);
if (TREE_CODE (orig) == ADDR_EXPR)
orig = TREE_OPERAND (orig, 0);
if ((TREE_CODE (orig) == ARRAY_REF
|| (TREE_CODE (orig) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
&& (TREE_CODE (t) == ARRAY_REF
|| TREE_CODE (t) == COMPONENT_REF)
&& !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
? TREE_OPERAND (orig, 0) : orig,
TREE_CODE (t) == ARRAY_REF
? TREE_OPERAND (t, 0) : t, 0))
ret = build_fold_addr_expr (ret);
if (!useless_type_conversion_p (orig_type, TREE_TYPE (ret)))
return NULL_TREE;
ptr_type = build_pointer_type (TREE_TYPE (t));
if (!useless_type_conversion_p (orig_type, ptr_type))
return NULL_TREE;
return build_fold_addr_expr_with_type_loc (loc, t, ptr_type);
SET_EXPR_LOCATION (ret, loc);
}
return NULL_TREE;
}
/* A subroutine of fold_stmt. Attempt to simplify *(BASE+OFFSET).
Return the simplified expression, or NULL if nothing could be done. */
static tree
maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
{
tree t;
bool volatile_p = TREE_THIS_VOLATILE (expr);
location_t loc = EXPR_LOCATION (expr);
/* We may well have constructed a double-nested PLUS_EXPR via multiple
substitutions. Fold that down to one. Remove NON_LVALUE_EXPRs that
are sometimes added. */
base = fold (base);
STRIP_TYPE_NOPS (base);
TREE_OPERAND (expr, 0) = base;
/* One possibility is that the address reduces to a string constant. */
t = fold_read_from_constant_string (expr);
if (t)
return t;
/* Add in any offset from a POINTER_PLUS_EXPR. */
if (TREE_CODE (base) == POINTER_PLUS_EXPR)
{
tree offset2;
offset2 = TREE_OPERAND (base, 1);
if (TREE_CODE (offset2) != INTEGER_CST)
return NULL_TREE;
base = TREE_OPERAND (base, 0);
offset = fold_convert (sizetype,
int_const_binop (PLUS_EXPR, offset, offset2, 1));
}
if (TREE_CODE (base) == ADDR_EXPR)
{
tree base_addr = base;
/* Strip the ADDR_EXPR. */
base = TREE_OPERAND (base, 0);
/* Fold away CONST_DECL to its value, if the type is scalar. */
if (TREE_CODE (base) == CONST_DECL
&& is_gimple_min_invariant (DECL_INITIAL (base)))
return DECL_INITIAL (base);
/* If there is no offset involved simply return the folded base. */
if (integer_zerop (offset))
return base;
/* Try folding *(&B+O) to B.X. */
t = maybe_fold_offset_to_reference (loc, base_addr, offset,
TREE_TYPE (expr));
if (t)
{
/* Preserve volatileness of the original expression.
We can end up with a plain decl here which is shared
and we shouldn't mess with its flags. */
if (!SSA_VAR_P (t))
TREE_THIS_VOLATILE (t) = volatile_p;
return t;
}
}
else
{
/* We can get here for out-of-range string constant accesses,
such as "_"[3]. Bail out of the entire substitution search
and arrange for the entire statement to be replaced by a
call to __builtin_trap. In all likelihood this will all be
constant-folded away, but in the meantime we can't leave with
something that get_expr_operands can't understand. */
t = base;
STRIP_NOPS (t);
if (TREE_CODE (t) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)
{
/* FIXME: Except that this causes problems elsewhere with dead
code not being deleted, and we die in the rtl expanders
because we failed to remove some ssa_name. In the meantime,
just return zero. */
/* FIXME2: This condition should be signaled by
fold_read_from_constant_string directly, rather than
re-checking for it here. */
return integer_zero_node;
}
/* Try folding *(B+O) to B->X. Still an improvement. */
if (POINTER_TYPE_P (TREE_TYPE (base)))
{
t = maybe_fold_offset_to_reference (loc, base, offset,
TREE_TYPE (expr));
if (t)
return t;
}
}
/* Otherwise we had an offset that we could not simplify. */
return NULL_TREE;
return ret;
}
@ -622,18 +320,17 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1)
/* Or op0 should now be A[0] and the non-constant offset defined
via a multiplication by the array element size. */
if (TREE_CODE (op0) == ARRAY_REF
&& integer_zerop (TREE_OPERAND (op0, 1))
&& TREE_CODE (op1) == SSA_NAME
&& host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (op0)), 1))
{
gimple offset_def = SSA_NAME_DEF_STMT (op1);
if (!is_gimple_assign (offset_def))
return NULL_TREE;
/* As we will end up creating a variable index array access
in the outermost array dimension make sure there isn't
a more inner array that the index could overflow to. */
if (TREE_CODE (TREE_OPERAND (op0, 0)) == ARRAY_REF)
&& TREE_CODE (TREE_OPERAND (op0, 0)) != ARRAY_REF
&& integer_zerop (TREE_OPERAND (op0, 1))
&& TREE_CODE (op1) == SSA_NAME)
{
gimple offset_def = SSA_NAME_DEF_STMT (op1);
tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (op0));
if (!host_integerp (elsz, 1)
|| !is_gimple_assign (offset_def))
return NULL_TREE;
/* Do not build array references of something that we can't
@ -644,15 +341,14 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1)
if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
&& TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
&& tree_int_cst_equal (gimple_assign_rhs2 (offset_def),
TYPE_SIZE_UNIT (TREE_TYPE (op0))))
&& tree_int_cst_equal (gimple_assign_rhs2 (offset_def), elsz))
return build_fold_addr_expr
(build4 (ARRAY_REF, TREE_TYPE (op0),
TREE_OPERAND (op0, 0),
gimple_assign_rhs1 (offset_def),
TREE_OPERAND (op0, 2),
TREE_OPERAND (op0, 3)));
else if (integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (op0)))
else if (integer_onep (elsz)
&& gimple_assign_rhs_code (offset_def) != MULT_EXPR)
return build_fold_addr_expr
(build4 (ARRAY_REF, TREE_TYPE (op0),
@ -661,6 +357,38 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1)
TREE_OPERAND (op0, 2),
TREE_OPERAND (op0, 3)));
}
else if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
/* Dto. */
&& TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) != ARRAY_TYPE
&& TREE_CODE (op1) == SSA_NAME)
{
gimple offset_def = SSA_NAME_DEF_STMT (op1);
tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (op0)));
if (!host_integerp (elsz, 1)
|| !is_gimple_assign (offset_def))
return NULL_TREE;
/* Do not build array references of something that we can't
see the true number of array dimensions for. */
if (!DECL_P (op0)
&& !handled_component_p (op0))
return NULL_TREE;
if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
&& TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
&& tree_int_cst_equal (gimple_assign_rhs2 (offset_def), elsz))
return build_fold_addr_expr
(build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)),
op0, gimple_assign_rhs1 (offset_def),
integer_zero_node, NULL_TREE));
else if (integer_onep (elsz)
&& gimple_assign_rhs_code (offset_def) != MULT_EXPR)
return build_fold_addr_expr
(build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)),
op0, op1,
integer_zero_node, NULL_TREE));
}
return NULL_TREE;
}
@ -715,13 +443,12 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1)
ptd_type = TREE_TYPE (TREE_TYPE (op0));
/* At which point we can try some of the same things as for indirects. */
t = maybe_fold_offset_to_array_ref (loc, op0, op1, ptd_type, true);
if (!t)
t = maybe_fold_offset_to_component_ref (loc, TREE_TYPE (op0), op0, op1,
ptd_type);
t = maybe_fold_offset_to_array_ref (loc, op0, op1);
if (t)
{
t = build1 (ADDR_EXPR, res_type, t);
t = build_fold_addr_expr (t);
if (!useless_type_conversion_p (res_type, TREE_TYPE (t)))
return NULL_TREE;
SET_EXPR_LOCATION (t, loc);
}
@ -759,19 +486,39 @@ maybe_fold_reference (tree expr, bool is_lhs)
while (handled_component_p (*t))
t = &TREE_OPERAND (*t, 0);
if (TREE_CODE (*t) == INDIRECT_REF)
/* Fold back MEM_REFs to reference trees. */
if (TREE_CODE (*t) == MEM_REF
&& TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
&& integer_zerop (TREE_OPERAND (*t, 1))
&& (TREE_THIS_VOLATILE (*t)
== TREE_THIS_VOLATILE (TREE_OPERAND (TREE_OPERAND (*t, 0), 0)))
&& !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*t, 1)))
&& (TYPE_MAIN_VARIANT (TREE_TYPE (*t))
== TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (*t, 1)))))
/* We have to look out here to not drop a required conversion
from the rhs to the lhs if is_lhs, but we don't have the
rhs here to verify that. Thus require strict type
compatibility. */
&& types_compatible_p (TREE_TYPE (*t),
TREE_TYPE (TREE_OPERAND
(TREE_OPERAND (*t, 0), 0))))
{
tree tem = maybe_fold_stmt_indirect (*t, TREE_OPERAND (*t, 0),
integer_zero_node);
/* Avoid folding *"abc" = 5 into 'a' = 5. */
if (is_lhs && tem && CONSTANT_CLASS_P (tem))
tem = NULL_TREE;
if (!tem
&& TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR)
/* If we had a good reason for propagating the address here,
make sure we end up with valid gimple. See PR34989. */
tem = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
tree tem;
*t = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
tem = maybe_fold_reference (expr, is_lhs);
if (tem)
return tem;
return expr;
}
/* Canonicalize MEM_REFs invariant address operand. */
else if (TREE_CODE (*t) == MEM_REF
&& TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
&& !DECL_P (TREE_OPERAND (TREE_OPERAND (*t, 0), 0))
&& !CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (*t, 0), 0)))
{
tree tem = fold_binary (MEM_REF, TREE_TYPE (*t),
TREE_OPERAND (*t, 0),
TREE_OPERAND (*t, 1));
if (tem)
{
*t = tem;
@ -863,10 +610,18 @@ fold_gimple_assign (gimple_stmt_iterator *si)
else if (TREE_CODE (rhs) == ADDR_EXPR)
{
tree tem = maybe_fold_reference (TREE_OPERAND (rhs, 0), true);
if (tem)
tree ref = TREE_OPERAND (rhs, 0);
tree tem = maybe_fold_reference (ref, true);
if (tem
&& TREE_CODE (tem) == MEM_REF
&& integer_zerop (TREE_OPERAND (tem, 1)))
result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (tem, 0));
else if (tem)
result = fold_convert (TREE_TYPE (rhs),
build_fold_addr_expr_loc (loc, tem));
else if (TREE_CODE (ref) == MEM_REF
&& integer_zerop (TREE_OPERAND (ref, 1)))
result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (ref, 0));
}
else if (TREE_CODE (rhs) == CONSTRUCTOR
@ -1580,7 +1335,7 @@ gimple_get_relevant_ref_binfo (tree ref, tree known_binfo)
return TYPE_BINFO (TREE_TYPE (ref));
else if (known_binfo
&& (TREE_CODE (ref) == SSA_NAME
|| TREE_CODE (ref) == INDIRECT_REF))
|| TREE_CODE (ref) == MEM_REF))
return known_binfo;
else
return NULL_TREE;

View File

@ -2595,7 +2595,8 @@ is_gimple_condexpr (tree t)
bool
is_gimple_addressable (tree t)
{
return (is_gimple_id (t) || handled_component_p (t) || INDIRECT_REF_P (t));
return (is_gimple_id (t) || handled_component_p (t)
|| TREE_CODE (t) == MEM_REF);
}
/* Return true if T is a valid gimple constant. */
@ -2646,7 +2647,7 @@ is_gimple_address (const_tree t)
op = TREE_OPERAND (op, 0);
}
if (CONSTANT_CLASS_P (op) || INDIRECT_REF_P (op))
if (CONSTANT_CLASS_P (op) || TREE_CODE (op) == MEM_REF)
return true;
switch (TREE_CODE (op))
@ -2706,8 +2707,18 @@ is_gimple_invariant_address (const_tree t)
return false;
op = strip_invariant_refs (TREE_OPERAND (t, 0));
if (!op)
return false;
return op && (CONSTANT_CLASS_P (op) || decl_address_invariant_p (op));
if (TREE_CODE (op) == MEM_REF)
{
const_tree op0 = TREE_OPERAND (op, 0);
return (TREE_CODE (op0) == ADDR_EXPR
&& (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
|| decl_address_invariant_p (TREE_OPERAND (op0, 0))));
}
return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
}
/* Return true if T is a gimple invariant address at IPA level
@ -2924,7 +2935,7 @@ is_gimple_min_lval (tree t)
{
if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
return false;
return (is_gimple_id (t) || TREE_CODE (t) == INDIRECT_REF);
return (is_gimple_id (t) || TREE_CODE (t) == MEM_REF);
}
/* Return true if T is a typecast operation. */
@ -2944,6 +2955,18 @@ is_gimple_call_addr (tree t)
return (TREE_CODE (t) == OBJ_TYPE_REF || is_gimple_val (t));
}
/* Return true if T is a valid address operand of a MEM_REF. */
bool
is_gimple_mem_ref_addr (tree t)
{
return (is_gimple_reg (t)
|| TREE_CODE (t) == INTEGER_CST
|| (TREE_CODE (t) == ADDR_EXPR
&& (CONSTANT_CLASS_P (TREE_OPERAND (t, 0))
|| decl_address_invariant_p (TREE_OPERAND (t, 0)))));
}
/* If T makes a function call, return the corresponding CALL_EXPR operand.
Otherwise, return NULL_TREE. */
@ -2975,10 +2998,15 @@ get_base_address (tree t)
while (handled_component_p (t))
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == MEM_REF
&& TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
if (SSA_VAR_P (t)
|| TREE_CODE (t) == STRING_CST
|| TREE_CODE (t) == CONSTRUCTOR
|| INDIRECT_REF_P (t))
|| INDIRECT_REF_P (t)
|| TREE_CODE (t) == MEM_REF)
return t;
else
return NULL_TREE;
@ -4418,7 +4446,7 @@ count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
return NULL_TREE;
}
if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
if (TREE_CODE (*tp) == MEM_REF && TREE_OPERAND (*tp, 0) == count_p->ptr)
{
if (wi_p->is_lhs)
count_p->num_stores++;
@ -4491,6 +4519,7 @@ get_base_loadstore (tree op)
op = TREE_OPERAND (op, 0);
if (DECL_P (op)
|| INDIRECT_REF_P (op)
|| TREE_CODE (op) == MEM_REF
|| TREE_CODE (op) == TARGET_MEM_REF)
return op;
return NULL_TREE;

View File

@ -933,6 +933,8 @@ extern bool is_gimple_ip_invariant (const_tree);
extern bool is_gimple_val (tree);
/* Returns true iff T is a GIMPLE asm statement input. */
extern bool is_gimple_asm_val (tree);
/* Returns true iff T is a valid address operand of a MEM_REF. */
bool is_gimple_mem_ref_addr (tree);
/* Returns true iff T is a valid rhs for a MODIFY_EXPR where the LHS is a
GIMPLE temporary, a renamed user variable, or something else,
respectively. */
@ -2037,7 +2039,18 @@ gimple_call_fndecl (const_gimple gs)
{
tree addr = gimple_call_fn (gs);
if (TREE_CODE (addr) == ADDR_EXPR)
return TREE_OPERAND (addr, 0);
{
tree fndecl = TREE_OPERAND (addr, 0);
if (TREE_CODE (fndecl) == MEM_REF)
{
if (TREE_CODE (TREE_OPERAND (fndecl, 0)) == ADDR_EXPR
&& integer_zerop (TREE_OPERAND (fndecl, 1)))
return TREE_OPERAND (TREE_OPERAND (fndecl, 0), 0);
else
return NULL_TREE;
}
return TREE_OPERAND (addr, 0);
}
return NULL_TREE;
}
@ -4857,8 +4870,8 @@ void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
tree gimple_fold_builtin (gimple);
bool fold_stmt (gimple_stmt_iterator *);
bool fold_stmt_inplace (gimple);
tree maybe_fold_offset_to_reference (location_t, tree, tree, tree);
tree maybe_fold_offset_to_address (location_t, tree, tree, tree);
tree maybe_fold_offset_to_reference (location_t, tree, tree, tree);
tree maybe_fold_stmt_addition (location_t, tree, tree, tree);
tree get_symbol_constant_value (tree);
bool may_propagate_address_into_dereference (tree, tree);

View File

@ -110,10 +110,13 @@ mark_addressable (tree x)
{
while (handled_component_p (x))
x = TREE_OPERAND (x, 0);
if (TREE_CODE (x) == MEM_REF
&& TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR)
x = TREE_OPERAND (TREE_OPERAND (x, 0), 0);
if (TREE_CODE (x) != VAR_DECL
&& TREE_CODE (x) != PARM_DECL
&& TREE_CODE (x) != RESULT_DECL)
return ;
return;
TREE_ADDRESSABLE (x) = 1;
}
@ -2961,7 +2964,7 @@ gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
= build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_);
tmp = create_tmp_var (type, "iftmp");
result = build_fold_indirect_ref_loc (loc, tmp);
result = build_simple_mem_ref_loc (loc, tmp);
}
/* Build the new then clause, `tmp = then_;'. But don't build the
@ -3185,7 +3188,7 @@ gimplify_modify_expr_to_memcpy (tree *expr_p, tree size, bool want_value,
gimple_call_set_lhs (gs, t);
gimplify_seq_add_stmt (seq_p, gs);
*expr_p = build1 (INDIRECT_REF, TREE_TYPE (to), t);
*expr_p = build_simple_mem_ref (t);
return GS_ALL_DONE;
}
@ -3269,13 +3272,16 @@ gimplify_init_ctor_preeval_1 (tree *tp, int *walk_subtrees, void *xdata)
/* If the constructor component is indirect, determine if we have a
potential overlap with the lhs. The only bits of information we
have to go on at this point are addressability and alias sets. */
if (TREE_CODE (t) == INDIRECT_REF
if ((INDIRECT_REF_P (t)
|| TREE_CODE (t) == MEM_REF)
&& (!data->lhs_base_decl || TREE_ADDRESSABLE (data->lhs_base_decl))
&& alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
return t;
/* If the constructor component is a call, determine if it can hide a
potential overlap with the lhs through an INDIRECT_REF like above. */
potential overlap with the lhs through an INDIRECT_REF like above.
??? Ugh - this is completely broken. In fact this whole analysis
doesn't look conservative. */
if (TREE_CODE (t) == CALL_EXPR)
{
tree type, fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (t)));
@ -4004,7 +4010,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
tree
gimple_fold_indirect_ref (tree t)
{
tree type = TREE_TYPE (TREE_TYPE (t));
tree ptype = TREE_TYPE (t), type = TREE_TYPE (ptype);
tree sub = t;
tree subtype;
@ -4047,51 +4053,52 @@ gimple_fold_indirect_ref (tree t)
}
}
/* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
/* *(p + CST) -> ... */
if (TREE_CODE (sub) == POINTER_PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
{
tree op00 = TREE_OPERAND (sub, 0);
tree op01 = TREE_OPERAND (sub, 1);
tree op00type;
tree addr = TREE_OPERAND (sub, 0);
tree off = TREE_OPERAND (sub, 1);
tree addrtype;
STRIP_NOPS (op00);
op00type = TREE_TYPE (op00);
if (TREE_CODE (op00) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE
&& useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
STRIP_NOPS (addr);
addrtype = TREE_TYPE (addr);
/* ((foo*)&vectorfoo)[1] -> BIT_FIELD_REF<vectorfoo,...> */
if (TREE_CODE (addr) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (addrtype)) == VECTOR_TYPE
&& useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
{
HOST_WIDE_INT offset = tree_low_cst (op01, 0);
tree part_width = TYPE_SIZE (type);
unsigned HOST_WIDE_INT part_widthi
= tree_low_cst (part_width, 0) / BITS_PER_UNIT;
unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
tree index = bitsize_int (indexi);
if (offset / part_widthi
<= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type)))
return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
part_width, index);
HOST_WIDE_INT offset = tree_low_cst (off, 0);
tree part_width = TYPE_SIZE (type);
unsigned HOST_WIDE_INT part_widthi
= tree_low_cst (part_width, 0) / BITS_PER_UNIT;
unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
tree index = bitsize_int (indexi);
if (offset / part_widthi
<= TYPE_VECTOR_SUBPARTS (TREE_TYPE (addrtype)))
return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (addr, 0),
part_width, index);
}
}
/* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
if (TREE_CODE (sub) == POINTER_PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
{
tree op00 = TREE_OPERAND (sub, 0);
tree op01 = TREE_OPERAND (sub, 1);
tree op00type;
/* ((foo*)&complexfoo)[1] -> __imag__ complexfoo */
if (TREE_CODE (addr) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (addrtype)) == COMPLEX_TYPE
&& useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (addrtype))))
{
tree size = TYPE_SIZE_UNIT (type);
if (tree_int_cst_equal (size, off))
return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (addr, 0));
}
STRIP_NOPS (op00);
op00type = TREE_TYPE (op00);
if (TREE_CODE (op00) == ADDR_EXPR
&& TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
&& useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
{
tree size = TYPE_SIZE_UNIT (type);
if (tree_int_cst_equal (size, op01))
return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0));
}
/* *(p + CST) -> MEM_REF <p, CST>. */
if (TREE_CODE (addr) != ADDR_EXPR
|| DECL_P (TREE_OPERAND (addr, 0)))
return fold_build2 (MEM_REF, type,
addr,
build_int_cst_wide (ptype,
TREE_INT_CST_LOW (off),
TREE_INT_CST_HIGH (off)));
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
@ -6558,7 +6565,8 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
|| gimple_test_f == is_gimple_mem_rhs_or_call
|| gimple_test_f == is_gimple_reg_rhs
|| gimple_test_f == is_gimple_reg_rhs_or_call
|| gimple_test_f == is_gimple_asm_val)
|| gimple_test_f == is_gimple_asm_val
|| gimple_test_f == is_gimple_mem_ref_addr)
gcc_assert (fallback & fb_rvalue);
else if (gimple_test_f == is_gimple_min_lval
|| gimple_test_f == is_gimple_lvalue)
@ -6764,21 +6772,59 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
recalculate_side_effects (*expr_p);
break;
case INDIRECT_REF:
*expr_p = fold_indirect_ref_loc (input_location, *expr_p);
if (*expr_p != save_expr)
{
ret = GS_OK;
break;
}
/* else fall through. */
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
/* We can only reach this through re-gimplification from
tree optimizers. */
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
is_gimple_reg, fb_rvalue);
recalculate_side_effects (*expr_p);
break;
case INDIRECT_REF:
{
bool volatilep = TREE_THIS_VOLATILE (*expr_p);
tree saved_ptr_type = TREE_TYPE (TREE_OPERAND (*expr_p, 0));
*expr_p = fold_indirect_ref_loc (input_location, *expr_p);
if (*expr_p != save_expr)
{
ret = GS_OK;
break;
}
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
is_gimple_reg, fb_rvalue);
recalculate_side_effects (*expr_p);
*expr_p = fold_build2_loc (input_location, MEM_REF,
TREE_TYPE (*expr_p),
TREE_OPERAND (*expr_p, 0),
build_int_cst (saved_ptr_type, 0));
TREE_THIS_VOLATILE (*expr_p) = volatilep;
ret = GS_OK;
break;
}
/* We arrive here through the various re-gimplifcation paths. */
case MEM_REF:
/* First try re-folding the whole thing. */
tmp = fold_binary (MEM_REF, TREE_TYPE (*expr_p),
TREE_OPERAND (*expr_p, 0),
TREE_OPERAND (*expr_p, 1));
if (tmp)
{
*expr_p = tmp;
recalculate_side_effects (*expr_p);
ret = GS_OK;
break;
}
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
is_gimple_mem_ref_addr, fb_rvalue);
recalculate_side_effects (*expr_p);
ret = GS_ALL_DONE;
break;
/* Constants need not be gimplified. */
case INTEGER_CST:
case REAL_CST:

View File

@ -1832,10 +1832,12 @@ likely_eliminated_by_inlining_p (gimple stmt)
bool rhs_free = false;
bool lhs_free = false;
while (handled_component_p (inner_lhs) || TREE_CODE (inner_lhs) == INDIRECT_REF)
while (handled_component_p (inner_lhs)
|| TREE_CODE (inner_lhs) == MEM_REF)
inner_lhs = TREE_OPERAND (inner_lhs, 0);
while (handled_component_p (inner_rhs)
|| TREE_CODE (inner_rhs) == ADDR_EXPR || TREE_CODE (inner_rhs) == INDIRECT_REF)
|| TREE_CODE (inner_rhs) == ADDR_EXPR
|| TREE_CODE (inner_rhs) == MEM_REF)
inner_rhs = TREE_OPERAND (inner_rhs, 0);
@ -1855,7 +1857,8 @@ likely_eliminated_by_inlining_p (gimple stmt)
|| (TREE_CODE (inner_lhs) == SSA_NAME
&& TREE_CODE (SSA_NAME_VAR (inner_lhs)) == RESULT_DECL))
lhs_free = true;
if (lhs_free && (is_gimple_reg (rhs) || is_gimple_min_invariant (rhs)))
if (lhs_free
&& (is_gimple_reg (rhs) || is_gimple_min_invariant (rhs)))
rhs_free = true;
if (lhs_free && rhs_free)
return true;

View File

@ -405,11 +405,12 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
if (TREE_CODE (type) != RECORD_TYPE)
return;
op1 = get_ref_base_and_extent (op1, &offset, &size, &max_size);
if (TREE_CODE (op1) != INDIRECT_REF
if (TREE_CODE (op1) != MEM_REF
/* If this is a varying address, punt. */
|| max_size == -1
|| max_size != size)
return;
offset += mem_ref_offset (op1).low * BITS_PER_UNIT;
op1 = TREE_OPERAND (op1, 0);
if (TREE_CODE (op1) != SSA_NAME
|| !SSA_NAME_IS_DEFAULT_DEF (op1))
@ -481,11 +482,12 @@ compute_complex_ancestor_jump_func (struct ipa_node_params *info,
expr = TREE_OPERAND (expr, 0);
expr = get_ref_base_and_extent (expr, &offset, &size, &max_size);
if (TREE_CODE (expr) != INDIRECT_REF
if (TREE_CODE (expr) != MEM_REF
/* If this is a varying address, punt. */
|| max_size == -1
|| max_size != size)
return;
offset += mem_ref_offset (expr).low * BITS_PER_UNIT;
parm = TREE_OPERAND (expr, 0);
if (TREE_CODE (parm) != SSA_NAME
|| !SSA_NAME_IS_DEFAULT_DEF (parm))
@ -1179,7 +1181,7 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
obj = TREE_OPERAND (obj, 0);
}
while (TREE_CODE (obj) == COMPONENT_REF);
if (TREE_CODE (obj) != INDIRECT_REF)
if (TREE_CODE (obj) != MEM_REF)
return;
obj = TREE_OPERAND (obj, 0);
}

View File

@ -324,7 +324,7 @@ check_op (funct_state local, tree t, bool checking_write)
return;
}
else if (t
&& INDIRECT_REF_P (t)
&& (INDIRECT_REF_P (t) || TREE_CODE (t) == MEM_REF)
&& TREE_CODE (TREE_OPERAND (t, 0)) == SSA_NAME
&& !ptr_deref_may_alias_global_p (TREE_OPERAND (t, 0)))
{

View File

@ -421,6 +421,10 @@ decompose_indirect_ref_acc (tree str_decl, struct field_access_site *acc)
if (!is_result_of_mult (before_cast, &acc->num, struct_size))
return false;
/* ??? Add TREE_OPERAND (acc->ref, 1) to acc->offset. */
if (!integer_zerop (TREE_OPERAND (acc->ref, 1)))
return false;
return true;
}
@ -434,7 +438,7 @@ decompose_access (tree str_decl, struct field_access_site *acc)
{
gcc_assert (acc->ref);
if (TREE_CODE (acc->ref) == INDIRECT_REF)
if (TREE_CODE (acc->ref) == MEM_REF)
return decompose_indirect_ref_acc (str_decl, acc);
else if (TREE_CODE (acc->ref) == ARRAY_REF)
return true;
@ -969,12 +973,12 @@ replace_field_acc (struct field_access_site *acc, tree new_type)
type_wrapper_t *wr_p = NULL;
struct ref_pos r_pos;
while (TREE_CODE (ref_var) == INDIRECT_REF
while (TREE_CODE (ref_var) == MEM_REF
|| TREE_CODE (ref_var) == ARRAY_REF)
{
type_wrapper_t wr;
if ( TREE_CODE (ref_var) == INDIRECT_REF)
if (TREE_CODE (ref_var) == MEM_REF)
{
wr.wrap = 0;
wr.domain = 0;
@ -1001,7 +1005,7 @@ replace_field_acc (struct field_access_site *acc, tree new_type)
new_ref = build4 (ARRAY_REF, type, new_ref,
wr_p->domain, NULL_TREE, NULL_TREE);
else /* Pointer. */
new_ref = build1 (INDIRECT_REF, type, new_ref);
new_ref = build_simple_mem_ref (new_ref);
VEC_pop (type_wrapper_t, wrapper);
}
@ -1041,7 +1045,7 @@ static void
replace_field_access_stmt (struct field_access_site *acc, tree new_type)
{
if (TREE_CODE (acc->ref) == INDIRECT_REF
if (TREE_CODE (acc->ref) == MEM_REF
||TREE_CODE (acc->ref) == ARRAY_REF
||TREE_CODE (acc->ref) == VAR_DECL)
replace_field_acc (acc, new_type);
@ -1277,13 +1281,11 @@ insert_new_var_in_stmt (gimple stmt, tree var, tree new_var)
pos = find_pos_in_stmt (stmt, var, &r_pos);
gcc_assert (pos);
while (r_pos.container && (TREE_CODE(r_pos.container) == INDIRECT_REF
while (r_pos.container && (TREE_CODE(r_pos.container) == MEM_REF
|| TREE_CODE(r_pos.container) == ADDR_EXPR))
{
tree type = TREE_TYPE (TREE_TYPE (new_var));
if (TREE_CODE(r_pos.container) == INDIRECT_REF)
new_var = build1 (INDIRECT_REF, type, new_var);
if (TREE_CODE(r_pos.container) == MEM_REF)
new_var = build_simple_mem_ref (new_var);
else
new_var = build_fold_addr_expr (new_var);
pos = find_pos_in_stmt (stmt, r_pos.container, &r_pos);
@ -2530,7 +2532,7 @@ get_stmt_accesses (tree *tp, int *walk_subtrees, void *data)
tree field_decl = TREE_OPERAND (t, 1);
if ((TREE_CODE (ref) == INDIRECT_REF
if ((TREE_CODE (ref) == MEM_REF
|| TREE_CODE (ref) == ARRAY_REF
|| TREE_CODE (ref) == VAR_DECL)
&& TREE_CODE (field_decl) == FIELD_DECL)
@ -4031,7 +4033,10 @@ reorg_structs (void)
static unsigned int
reorg_structs_drive (void)
{
reorg_structs ();
/* IPA struct-reorg is completely broken - its analysis phase is
non-conservative (which is not the only reason it is broken). */
if (0)
reorg_structs ();
return 0;
}

View File

@ -218,7 +218,7 @@ collect_data_for_malloc_call (gimple stmt, struct malloc_call_data *m_data)
initial address and index of each dimension. */
struct access_site_info
{
/* The statement (INDIRECT_REF or POINTER_PLUS_EXPR). */
/* The statement (MEM_REF or POINTER_PLUS_EXPR). */
gimple stmt;
/* In case of POINTER_PLUS_EXPR, what is the offset. */
@ -334,7 +334,7 @@ struct ssa_acc_in_tree
/* The variable whose accesses in the tree we are looking for. */
tree ssa_var;
/* The tree and code inside it the ssa_var is accessed, currently
it could be an INDIRECT_REF or CALL_EXPR. */
it could be an MEM_REF or CALL_EXPR. */
enum tree_code t_code;
tree t_tree;
/* The place in the containing tree. */
@ -413,33 +413,18 @@ mtt_info_eq (const void *mtt1, const void *mtt2)
static bool
may_flatten_matrices_1 (gimple stmt)
{
tree t;
switch (gimple_code (stmt))
{
case GIMPLE_ASSIGN:
if (!gimple_assign_cast_p (stmt))
case GIMPLE_CALL:
if (!gimple_has_lhs (stmt))
return true;
t = gimple_assign_rhs1 (stmt);
while (CONVERT_EXPR_P (t))
if (TREE_CODE (TREE_TYPE (gimple_get_lhs (stmt))) == VECTOR_TYPE)
{
if (TREE_TYPE (t) && POINTER_TYPE_P (TREE_TYPE (t)))
{
tree pointee;
pointee = TREE_TYPE (t);
while (POINTER_TYPE_P (pointee))
pointee = TREE_TYPE (pointee);
if (TREE_CODE (pointee) == VECTOR_TYPE)
{
if (dump_file)
fprintf (dump_file,
"Found vector type, don't flatten matrix\n");
return false;
}
}
t = TREE_OPERAND (t, 0);
if (dump_file)
fprintf (dump_file,
"Found vector type, don't flatten matrix\n");
return false;
}
break;
case GIMPLE_ASM:
@ -602,7 +587,7 @@ mark_min_matrix_escape_level (struct matrix_info *mi, int l, gimple s)
/* Find if the SSA variable is accessed inside the
tree and record the tree containing it.
The only relevant uses are the case of SSA_NAME, or SSA inside
INDIRECT_REF, PLUS_EXPR, POINTER_PLUS_EXPR, MULT_EXPR. */
MEM_REF, PLUS_EXPR, POINTER_PLUS_EXPR, MULT_EXPR. */
static void
ssa_accessed_in_tree (tree t, struct ssa_acc_in_tree *a)
{
@ -613,7 +598,7 @@ ssa_accessed_in_tree (tree t, struct ssa_acc_in_tree *a)
if (t == a->ssa_var)
a->var_found = true;
break;
case INDIRECT_REF:
case MEM_REF:
if (SSA_VAR_P (TREE_OPERAND (t, 0))
&& TREE_OPERAND (t, 0) == a->ssa_var)
a->var_found = true;
@ -660,7 +645,7 @@ ssa_accessed_in_assign_rhs (gimple stmt, struct ssa_acc_in_tree *a)
tree op1, op2;
case SSA_NAME:
case INDIRECT_REF:
case MEM_REF:
CASE_CONVERT:
case VIEW_CONVERT_EXPR:
ssa_accessed_in_tree (gimple_assign_rhs1 (stmt), a);
@ -984,7 +969,7 @@ get_index_from_offset (tree offset, gimple def_stmt)
/* update MI->dimension_type_size[CURRENT_INDIRECT_LEVEL] with the size
of the type related to the SSA_VAR, or the type related to the
lhs of STMT, in the case that it is an INDIRECT_REF. */
lhs of STMT, in the case that it is an MEM_REF. */
static void
update_type_size (struct matrix_info *mi, gimple stmt, tree ssa_var,
int current_indirect_level)
@ -992,9 +977,9 @@ update_type_size (struct matrix_info *mi, gimple stmt, tree ssa_var,
tree lhs;
HOST_WIDE_INT type_size;
/* Update type according to the type of the INDIRECT_REF expr. */
/* Update type according to the type of the MEM_REF expr. */
if (is_gimple_assign (stmt)
&& TREE_CODE (gimple_assign_lhs (stmt)) == INDIRECT_REF)
&& TREE_CODE (gimple_assign_lhs (stmt)) == MEM_REF)
{
lhs = gimple_assign_lhs (stmt);
gcc_assert (POINTER_TYPE_P
@ -1073,7 +1058,7 @@ analyze_accesses_for_call_stmt (struct matrix_info *mi, tree ssa_var,
at this level because in this case we cannot calculate the
address correctly. */
if ((lhs_acc.var_found && rhs_acc.var_found
&& lhs_acc.t_code == INDIRECT_REF)
&& lhs_acc.t_code == MEM_REF)
|| (!rhs_acc.var_found && !lhs_acc.var_found))
{
mark_min_matrix_escape_level (mi, current_indirect_level, use_stmt);
@ -1087,7 +1072,7 @@ analyze_accesses_for_call_stmt (struct matrix_info *mi, tree ssa_var,
{
int l = current_indirect_level + 1;
gcc_assert (lhs_acc.t_code == INDIRECT_REF);
gcc_assert (lhs_acc.t_code == MEM_REF);
mark_min_matrix_escape_level (mi, l, use_stmt);
return current_indirect_level;
}
@ -1213,7 +1198,7 @@ analyze_accesses_for_assign_stmt (struct matrix_info *mi, tree ssa_var,
at this level because in this case we cannot calculate the
address correctly. */
if ((lhs_acc.var_found && rhs_acc.var_found
&& lhs_acc.t_code == INDIRECT_REF)
&& lhs_acc.t_code == MEM_REF)
|| (!rhs_acc.var_found && !lhs_acc.var_found))
{
mark_min_matrix_escape_level (mi, current_indirect_level, use_stmt);
@ -1227,7 +1212,7 @@ analyze_accesses_for_assign_stmt (struct matrix_info *mi, tree ssa_var,
{
int l = current_indirect_level + 1;
gcc_assert (lhs_acc.t_code == INDIRECT_REF);
gcc_assert (lhs_acc.t_code == MEM_REF);
if (!(gimple_assign_copy_p (use_stmt)
|| gimple_assign_cast_p (use_stmt))
@ -1248,7 +1233,7 @@ analyze_accesses_for_assign_stmt (struct matrix_info *mi, tree ssa_var,
is used. */
if (rhs_acc.var_found)
{
if (rhs_acc.t_code != INDIRECT_REF
if (rhs_acc.t_code != MEM_REF
&& rhs_acc.t_code != POINTER_PLUS_EXPR && rhs_acc.t_code != SSA_NAME)
{
mark_min_matrix_escape_level (mi, current_indirect_level, use_stmt);
@ -1256,7 +1241,7 @@ analyze_accesses_for_assign_stmt (struct matrix_info *mi, tree ssa_var,
}
/* If the access in the RHS has an indirection increase the
indirection level. */
if (rhs_acc.t_code == INDIRECT_REF)
if (rhs_acc.t_code == MEM_REF)
{
if (record_accesses)
record_access_alloc_site_info (mi, use_stmt, NULL_TREE,
@ -1309,7 +1294,7 @@ analyze_accesses_for_assign_stmt (struct matrix_info *mi, tree ssa_var,
}
/* If we are storing this level of indirection mark it as
escaping. */
if (lhs_acc.t_code == INDIRECT_REF || TREE_CODE (lhs) != SSA_NAME)
if (lhs_acc.t_code == MEM_REF || TREE_CODE (lhs) != SSA_NAME)
{
int l = current_indirect_level;
@ -1369,8 +1354,8 @@ analyze_matrix_accesses (struct matrix_info *mi, tree ssa_var,
return;
/* Now go over the uses of the SSA_NAME and check how it is used in
each one of them. We are mainly looking for the pattern INDIRECT_REF,
then a POINTER_PLUS_EXPR, then INDIRECT_REF etc. while in between there could
each one of them. We are mainly looking for the pattern MEM_REF,
then a POINTER_PLUS_EXPR, then MEM_REF etc. while in between there could
be any number of copies and casts. */
gcc_assert (TREE_CODE (ssa_var) == SSA_NAME);
@ -1856,7 +1841,7 @@ transform_access_sites (void **slot, void *data ATTRIBUTE_UNUSED)
gimple new_stmt;
gcc_assert (gimple_assign_rhs_code (acc_info->stmt)
== INDIRECT_REF);
== MEM_REF);
/* Emit convert statement to convert to type of use. */
tmp = create_tmp_var (TREE_TYPE (lhs), "new");
add_referenced_var (tmp);
@ -1878,10 +1863,10 @@ transform_access_sites (void **slot, void *data ATTRIBUTE_UNUSED)
continue;
}
code = gimple_assign_rhs_code (acc_info->stmt);
if (code == INDIRECT_REF
if (code == MEM_REF
&& acc_info->level < min_escape_l - 1)
{
/* Replace the INDIRECT_REF with NOP (cast) usually we are casting
/* Replace the MEM_REF with NOP (cast) usually we are casting
from "pointer to type" to "type". */
tree t =
build1 (NOP_EXPR, TREE_TYPE (gimple_assign_rhs1 (acc_info->stmt)),
@ -2206,7 +2191,6 @@ transform_allocation_sites (void **slot, void *data ATTRIBUTE_UNUSED)
for (i = 1; i < mi->min_indirect_level_escape; i++)
{
gimple_stmt_iterator gsi;
gimple use_stmt1 = NULL;
gimple call_stmt = mi->malloc_for_level[i];
gcc_assert (is_gimple_call (call_stmt));
@ -2216,17 +2200,9 @@ transform_allocation_sites (void **slot, void *data ATTRIBUTE_UNUSED)
gsi = gsi_for_stmt (call_stmt);
/* Remove the call stmt. */
gsi_remove (&gsi, true);
/* remove the type cast stmt. */
FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter,
gimple_call_lhs (call_stmt))
{
use_stmt1 = use_stmt;
gsi = gsi_for_stmt (use_stmt);
gsi_remove (&gsi, true);
}
/* Remove the assignment of the allocated area. */
FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter,
gimple_get_lhs (use_stmt1))
gimple_call_lhs (call_stmt))
{
gsi = gsi_for_stmt (use_stmt);
gsi_remove (&gsi, true);

View File

@ -864,10 +864,10 @@ build_receiver_ref (tree var, bool by_ref, omp_context *ctx)
if (x != NULL)
field = x;
x = build_fold_indirect_ref (ctx->receiver_decl);
x = build_simple_mem_ref (ctx->receiver_decl);
x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL);
if (by_ref)
x = build_fold_indirect_ref (x);
x = build_simple_mem_ref (x);
return x;
}
@ -887,7 +887,7 @@ build_outer_var_ref (tree var, omp_context *ctx)
{
x = TREE_OPERAND (DECL_VALUE_EXPR (var), 0);
x = build_outer_var_ref (x, ctx);
x = build_fold_indirect_ref (x);
x = build_simple_mem_ref (x);
}
else if (is_taskreg_ctx (ctx))
{
@ -904,7 +904,7 @@ build_outer_var_ref (tree var, omp_context *ctx)
gcc_unreachable ();
if (is_reference (var))
x = build_fold_indirect_ref (x);
x = build_simple_mem_ref (x);
return x;
}
@ -1916,7 +1916,18 @@ scan_omp_1_op (tree *tp, int *walk_subtrees, void *data)
{
*walk_subtrees = 1;
if (ctx)
TREE_TYPE (t) = remap_type (TREE_TYPE (t), &ctx->cb);
{
tree tem = remap_type (TREE_TYPE (t), &ctx->cb);
if (tem != TREE_TYPE (t))
{
if (TREE_CODE (t) == INTEGER_CST)
*tp = build_int_cst_wide (tem,
TREE_INT_CST_LOW (t),
TREE_INT_CST_HIGH (t));
else
TREE_TYPE (t) = tem;
}
}
}
break;
}
@ -2337,7 +2348,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
gimplify_assign (new_var, x, ilist);
new_var = build_fold_indirect_ref_loc (clause_loc, new_var);
new_var = build_simple_mem_ref_loc (clause_loc, new_var);
}
else if (c_kind == OMP_CLAUSE_REDUCTION
&& OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
@ -2555,7 +2566,7 @@ lower_lastprivate_clauses (tree clauses, tree predicate, gimple_seq *stmt_list,
x = build_outer_var_ref (var, ctx);
if (is_reference (var))
new_var = build_fold_indirect_ref_loc (clause_loc, new_var);
new_var = build_simple_mem_ref_loc (clause_loc, new_var);
x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
gimplify_and_add (x, stmt_list);
}
@ -2622,7 +2633,7 @@ lower_reduction_clauses (tree clauses, gimple_seq *stmt_seqp, omp_context *ctx)
var = OMP_CLAUSE_DECL (c);
new_var = lookup_decl (var, ctx);
if (is_reference (var))
new_var = build_fold_indirect_ref_loc (clause_loc, new_var);
new_var = build_simple_mem_ref_loc (clause_loc, new_var);
ref = build_outer_var_ref (var, ctx);
code = OMP_CLAUSE_REDUCTION_CODE (c);
@ -2714,8 +2725,8 @@ lower_copyprivate_clauses (tree clauses, gimple_seq *slist, gimple_seq *rlist,
if (is_reference (var))
{
ref = fold_convert_loc (clause_loc, TREE_TYPE (new_var), ref);
ref = build_fold_indirect_ref_loc (clause_loc, ref);
new_var = build_fold_indirect_ref_loc (clause_loc, new_var);
ref = build_simple_mem_ref_loc (clause_loc, ref);
new_var = build_simple_mem_ref_loc (clause_loc, new_var);
}
x = lang_hooks.decls.omp_clause_assign_op (c, new_var, ref);
gimplify_and_add (x, rlist);
@ -5067,8 +5078,12 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
loadedi = loaded_val;
}
initial = force_gimple_operand_gsi (&si, build_fold_indirect_ref (iaddr),
true, NULL_TREE, true, GSI_SAME_STMT);
initial
= force_gimple_operand_gsi (&si,
build2 (MEM_REF, TREE_TYPE (TREE_TYPE (iaddr)),
iaddr,
build_int_cst (TREE_TYPE (iaddr), 0)),
true, NULL_TREE, true, GSI_SAME_STMT);
/* Move the value to the LOADEDI temporary. */
if (gimple_in_ssa_p (cfun))
@ -5212,15 +5227,15 @@ expand_omp_atomic_mutex (basic_block load_bb, basic_block store_bb,
t = build_function_call_expr (UNKNOWN_LOCATION, t, 0);
force_gimple_operand_gsi (&si, t, true, NULL_TREE, true, GSI_SAME_STMT);
stmt = gimple_build_assign (loaded_val, build_fold_indirect_ref (addr));
stmt = gimple_build_assign (loaded_val, build_simple_mem_ref (addr));
gsi_insert_before (&si, stmt, GSI_SAME_STMT);
gsi_remove (&si, true);
si = gsi_last_bb (store_bb);
gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ATOMIC_STORE);
stmt = gimple_build_assign (build_fold_indirect_ref (unshare_expr (addr)),
stored_val);
stmt = gimple_build_assign (build_simple_mem_ref (unshare_expr (addr)),
stored_val);
gsi_insert_before (&si, stmt, GSI_SAME_STMT);
t = built_in_decls[BUILT_IN_GOMP_ATOMIC_END];
@ -6269,7 +6284,7 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
n = splay_tree_lookup (ctx->sfield_map, (splay_tree_key) decl);
sf = (tree) n->value;
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_fold_indirect_ref_loc (loc, sarg);
src = build_simple_mem_ref_loc (loc, sarg);
src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
t = build2 (MODIFY_EXPR, TREE_TYPE (*p), *p, src);
append_to_statement_list (t, &list);
@ -6292,9 +6307,9 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
sf = (tree) n->value;
if (tcctx.cb.decl_map)
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_fold_indirect_ref_loc (loc, sarg);
src = build_simple_mem_ref_loc (loc, sarg);
src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
dst = build_fold_indirect_ref_loc (loc, arg);
dst = build_simple_mem_ref_loc (loc, arg);
dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
append_to_statement_list (t, &list);
@ -6315,14 +6330,14 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
sf = (tree) n->value;
if (tcctx.cb.decl_map)
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_fold_indirect_ref_loc (loc, sarg);
src = build_simple_mem_ref_loc (loc, sarg);
src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
if (use_pointer_for_field (decl, NULL) || is_reference (decl))
src = build_fold_indirect_ref_loc (loc, src);
src = build_simple_mem_ref_loc (loc, src);
}
else
src = decl;
dst = build_fold_indirect_ref_loc (loc, arg);
dst = build_simple_mem_ref_loc (loc, arg);
dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
append_to_statement_list (t, &list);
@ -6341,14 +6356,14 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
sf = (tree) n->value;
if (tcctx.cb.decl_map)
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_fold_indirect_ref_loc (loc, sarg);
src = build_simple_mem_ref_loc (loc, sarg);
src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
if (use_pointer_for_field (decl, NULL))
src = build_fold_indirect_ref_loc (loc, src);
src = build_simple_mem_ref_loc (loc, src);
}
else
src = decl;
dst = build_fold_indirect_ref_loc (loc, arg);
dst = build_simple_mem_ref_loc (loc, arg);
dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
append_to_statement_list (t, &list);
@ -6380,10 +6395,10 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
(splay_tree_key) TREE_OPERAND (ind, 0));
sf = (tree) n->value;
sf = *(tree *) pointer_map_contains (tcctx.cb.decl_map, sf);
src = build_fold_indirect_ref_loc (loc, sarg);
src = build_simple_mem_ref_loc (loc, sarg);
src = build3 (COMPONENT_REF, TREE_TYPE (sf), src, sf, NULL);
src = build_fold_indirect_ref_loc (loc, src);
dst = build_fold_indirect_ref_loc (loc, arg);
src = build_simple_mem_ref_loc (loc, src);
dst = build_simple_mem_ref_loc (loc, arg);
dst = build3 (COMPONENT_REF, TREE_TYPE (f), dst, f, NULL);
t = lang_hooks.decls.omp_clause_copy_ctor (c, dst, src);
append_to_statement_list (t, &list);
@ -6391,7 +6406,7 @@ create_task_copyfn (gimple task_stmt, omp_context *ctx)
(splay_tree_key) TREE_OPERAND (ind, 0));
df = (tree) n->value;
df = *(tree *) pointer_map_contains (tcctx.cb.decl_map, df);
ptr = build_fold_indirect_ref_loc (loc, arg);
ptr = build_simple_mem_ref_loc (loc, arg);
ptr = build3 (COMPONENT_REF, TREE_TYPE (df), ptr, df, NULL);
t = build2 (MODIFY_EXPR, TREE_TYPE (ptr), ptr,
build_fold_addr_expr_loc (loc, dst));

View File

@ -1,3 +1,70 @@
2010-07-01 Richard Guenther <rguenther@suse.de>
PR middle-end/42834
PR middle-end/44468
* gcc.c-torture/execute/20100316-1.c: New testcase.
* gcc.c-torture/execute/pr44468.c: Likewise.
* gcc.c-torture/compile/20100609-1.c: Likewise.
* gcc.dg/volatile2.c: Adjust.
* gcc.dg/plugin/selfassign.c: Likewise.
* gcc.dg/pr36902.c: Likewise.
* gcc.dg/tree-ssa/foldaddr-2.c: Remove.
* gcc.dg/tree-ssa/foldaddr-3.c: Likewise.
* gcc.dg/tree-ssa/forwprop-8.c: Adjust.
* gcc.dg/tree-ssa/pr17141-1.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-13.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-14.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-21.c: Likewise.
* gcc.dg/tree-ssa/pta-ptrarith-1.c: Likewise.
* gcc.dg/tree-ssa/20030807-7.c: Likewise.
* gcc.dg/tree-ssa/forwprop-10.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-1.c: Likewise.
* gcc.dg/tree-ssa/pta-ptrarith-2.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.
* gcc.dg/tree-ssa/forwprop-1.c: Likewise.
* gcc.dg/tree-ssa/forwprop-2.c: Likewise.
* gcc.dg/tree-ssa/struct-aliasing-1.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-25.c: Likewise.
* gcc.dg/tree-ssa/ssa-pre-26.c: Likewise.
* gcc.dg/tree-ssa/struct-aliasing-2.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-26.c: Likewise.
* gcc.dg/tree-ssa/ssa-sccvn-4.c: Likewise.
* gcc.dg/tree-ssa/ssa-pre-7.c: Likewise.
* gcc.dg/tree-ssa/forwprop-5.c: Likewise.
* gcc.dg/struct/w_prof_two_strs.c: XFAIL.
* gcc.dg/struct/wo_prof_escape_arg_to_local.c: Likewise.
* gcc.dg/struct/wo_prof_global_var.c: Likewise.
* gcc.dg/struct/wo_prof_malloc_size_var.c: Likewise.
* gcc.dg/struct/w_prof_local_array.c: Likewise.
* gcc.dg/struct/w_prof_single_str_global.c: Likewise.
* gcc.dg/struct/wo_prof_escape_str_init.c: Likewise.
* gcc.dg/struct/wo_prof_array_through_pointer.c: Likewise.
* gcc.dg/struct/w_prof_global_array.c: Likewise.
* gcc.dg/struct/wo_prof_array_field.c: Likewise.
* gcc.dg/struct/wo_prof_single_str_local.c: Likewise.
* gcc.dg/struct/w_prof_local_var.c: Likewise.
* gcc.dg/struct/wo_prof_two_strs.c: Likewise.
* gcc.dg/struct/wo_prof_empty_str.c: Likewise.
* gcc.dg/struct/wo_prof_local_array.c: Likewise.
* gcc.dg/struct/w_prof_global_var.c: Likewise.
* gcc.dg/struct/wo_prof_single_str_global.c: Likewise.
* gcc.dg/struct/wo_prof_escape_substr_value.c: Likewise.
* gcc.dg/struct/wo_prof_global_array.c: Likewise.
* gcc.dg/struct/wo_prof_escape_return.c: Likewise.
* gcc.dg/struct/wo_prof_escape_substr_array.c: Likewise.
* gcc.dg/struct/wo_prof_double_malloc.c: Likewise.
* gcc.dg/struct/w_ratio_cold_str.c: Likewise.
* gcc.dg/struct/wo_prof_escape_substr_pointer.c: Likewise.
* gcc.dg/struct/wo_prof_local_var.c: Likewise.
* gcc.dg/tree-prof/stringop-1.c: Adjust.
* g++.dg/tree-ssa/pr31146.C: Likewise.
* g++.dg/tree-ssa/copyprop-1.C: Likewise.
* g++.dg/tree-ssa/pr33604.C: Likewise.
* g++.dg/plugin/selfassign.c: Likewise.
* gfortran.dg/array_memcpy_3.f90: Likewise.
* gfortran.dg/array_memcpy_4.f90: Likewise.
* c-c++-common/torture/pr42834.c: New testcase.
2010-06-30 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44628

View File

@ -0,0 +1,23 @@
/* { dg-do run } */
void __attribute__((noinline,noclone))
foo(int *p, float *q) { __asm__ volatile ("" : : : "memory"); }
int main()
{
if (sizeof (int) == sizeof (float))
{
int i;
float f;
int *p;
/* Prevent i and f from being rewritten into SSA form. */
foo (&i, &f);
i = 0;
f = 1.0;
p = (int *)&f;
__builtin_memcpy (&i, p, 4);
if (*(float *)&i != 1.0)
__builtin_abort ();
}
return 0;
}

View File

@ -52,9 +52,7 @@ get_real_ref_rhs (tree expr)
/* We are only interested in an assignment with a single
rhs operand because if it is not, the original assignment
will not possibly be a self-assignment. */
if (is_gimple_assign (def_stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt))
== GIMPLE_SINGLE_RHS))
if (gimple_assign_single_p (def_stmt))
return get_real_ref_rhs (gimple_assign_rhs1 (def_stmt));
else
return NULL_TREE;
@ -66,7 +64,7 @@ get_real_ref_rhs (tree expr)
case PARM_DECL:
case FIELD_DECL:
case COMPONENT_REF:
case INDIRECT_REF:
case MEM_REF:
case ARRAY_REF:
return expr;
default:
@ -116,17 +114,18 @@ get_non_ssa_expr (tree expr)
else
return expr;
}
case INDIRECT_REF:
case MEM_REF:
{
tree orig_base = TREE_OPERAND (expr, 0);
tree base = get_non_ssa_expr (orig_base);
if (!base)
return NULL_TREE;
/* If BASE is converted, build a new indirect reference tree. */
if (base != orig_base)
return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (base)), base);
else
return expr;
if (TREE_CODE (orig_base) == SSA_NAME)
{
tree base = get_non_ssa_expr (orig_base);
if (!base)
return NULL_TREE;
return fold_build2 (MEM_REF, TREE_TYPE (expr),
base, TREE_OPERAND (expr, 1));
}
return expr;
}
case ARRAY_REF:
{
@ -153,9 +152,7 @@ get_non_ssa_expr (tree expr)
&& !gimple_nop_p (SSA_NAME_DEF_STMT (expr)))
{
gimple def_stmt = SSA_NAME_DEF_STMT (expr);
if (is_gimple_assign (def_stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt))
== GIMPLE_SINGLE_RHS))
if (gimple_assign_single_p (def_stmt))
vdecl = gimple_assign_rhs1 (def_stmt);
}
return get_non_ssa_expr (vdecl);
@ -201,9 +198,7 @@ warn_self_assign (gimple stmt)
tree rhs, lhs;
/* Check assigment statement. */
if (is_gimple_assign (stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
== GIMPLE_SINGLE_RHS))
if (gimple_assign_single_p (stmt))
{
rhs = get_real_ref_rhs (gimple_assign_rhs1 (stmt));
if (!rhs)

View File

@ -25,5 +25,7 @@ int foo(Object&o)
return o[0];
}
/* { dg-final { scan-tree-dump-not ".* = \[^>;\]*;" "dce2" } } */
/* Remaining should be two loads. */
/* { dg-final { scan-tree-dump-times " = \[^\n\]*;" 2 "dce2" } } */
/* { dg-final { cleanup-tree-dump "dce2" } } */

View File

@ -12,5 +12,5 @@ void foo (int j)
*q = 1;
}
/* { dg-final { scan-tree-dump "i\\\[j.*\\\] =.* 1;" "forwprop1" } } */
/* { dg-final { scan-tree-dump "MEM\\\[.*&i\\\]\\\[j.*\\\] =.* 1;" "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop?" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do run } */
/* { dg-options "-O -fdump-tree-forwprop1" } */
/* { dg-options "-O -fdump-tree-optimized-vops" } */
struct Value
{
@ -35,12 +35,14 @@ int main(int argc, char *argv[])
return 0;
}
/* Check that we forward propagated
/* Check that we propagate
D.2182_13 = (struct Ref *) &D.2137.lhs;
to
D.2182_13->lhs.m ={v} &I;
yielding
D.2137.lhs.m ={v} &I; */
D.2137.lhs.m ={v} &I;
so that SRA can promote all locals to registers and we end up
referencing a single virtual operand at abort () after optimization. */
/* { dg-final { scan-tree-dump-times "D\\\.....\\\..hs\\\.m =" 2 "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */
/* { dg-final { scan-tree-dump-times ".MEM_\[0-9\]*\\\(D\\\)" 1 "optimized" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -0,0 +1,8 @@
extern unsigned long int strtoul (__const char *__restrict __nptr, char **__restrict __endptr, int __base);
int find_reloads (int i, char *p)
{
int c;
while ((c = *p++))
return strtoul (p - 1, &p, 10);
return 0;
}

View File

@ -0,0 +1,24 @@
struct Foo {
int i;
unsigned precision : 10;
unsigned blah : 3;
} f;
int __attribute__((noinline,noclone))
foo (struct Foo *p)
{
struct Foo *q = p;
return (*q).precision;
}
extern void abort (void);
int main()
{
f.i = -1;
f.precision = 0;
f.blah = -1;
if (foo (&f) != 0)
abort ();
return 0;
}

View File

@ -0,0 +1,60 @@
#include <stddef.h>
struct S {
int i;
int j;
};
struct R {
int k;
struct S a;
};
struct Q {
float k;
struct S a;
};
struct Q s;
int __attribute__((noinline,noclone))
test1 (void *q)
{
struct S *b = (struct S *)((char *)q + sizeof (int));
s.a.i = 0;
b->i = 3;
return s.a.i;
}
int __attribute__((noinline,noclone))
test2 (void *q)
{
struct S *b = &((struct R *)q)->a;
s.a.i = 0;
b->i = 3;
return s.a.i;
}
int __attribute__((noinline,noclone))
test3 (void *q)
{
s.a.i = 0;
((struct S *)((char *)q + sizeof (int)))->i = 3;
return s.a.i;
}
extern void abort (void);
int
main()
{
if (sizeof (float) != sizeof (int)
|| offsetof (struct R, a) != sizeof (int)
|| offsetof (struct Q, a) != sizeof (int))
return 0;
s.a.i = 1;
s.a.j = 2;
if (test1 ((void *)&s) != 3)
abort ();
s.a.i = 1;
s.a.j = 2;
if (test2 ((void *)&s) != 3)
abort ();
s.a.i = 1;
s.a.j = 2;
if (test3 ((void *)&s) != 3)
abort ();
return 0;
}

View File

@ -52,9 +52,7 @@ get_real_ref_rhs (tree expr)
/* We are only interested in an assignment with a single
rhs operand because if it is not, the original assignment
will not possibly be a self-assignment. */
if (is_gimple_assign (def_stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt))
== GIMPLE_SINGLE_RHS))
if (gimple_assign_single_p (def_stmt))
return get_real_ref_rhs (gimple_assign_rhs1 (def_stmt));
else
return NULL_TREE;
@ -66,7 +64,7 @@ get_real_ref_rhs (tree expr)
case PARM_DECL:
case FIELD_DECL:
case COMPONENT_REF:
case INDIRECT_REF:
case MEM_REF:
case ARRAY_REF:
return expr;
default:
@ -116,17 +114,18 @@ get_non_ssa_expr (tree expr)
else
return expr;
}
case INDIRECT_REF:
case MEM_REF:
{
tree orig_base = TREE_OPERAND (expr, 0);
tree base = get_non_ssa_expr (orig_base);
if (!base)
return NULL_TREE;
/* If BASE is converted, build a new indirect reference tree. */
if (base != orig_base)
return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (base)), base);
else
return expr;
if (TREE_CODE (orig_base) == SSA_NAME)
{
tree base = get_non_ssa_expr (orig_base);
if (!base)
return NULL_TREE;
return fold_build2 (MEM_REF, TREE_TYPE (expr),
base, TREE_OPERAND (expr, 1));
}
return expr;
}
case ARRAY_REF:
{
@ -153,9 +152,7 @@ get_non_ssa_expr (tree expr)
&& !gimple_nop_p (SSA_NAME_DEF_STMT (expr)))
{
gimple def_stmt = SSA_NAME_DEF_STMT (expr);
if (is_gimple_assign (def_stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (def_stmt))
== GIMPLE_SINGLE_RHS))
if (gimple_assign_single_p (def_stmt))
vdecl = gimple_assign_rhs1 (def_stmt);
}
return get_non_ssa_expr (vdecl);
@ -201,9 +198,7 @@ warn_self_assign (gimple stmt)
tree rhs, lhs;
/* Check assigment statement. */
if (is_gimple_assign (stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
== GIMPLE_SINGLE_RHS))
if (gimple_assign_single_p (stmt))
{
rhs = get_real_ref_rhs (gimple_assign_rhs1 (stmt));
if (!rhs)

View File

@ -44,7 +44,7 @@ foo2(unsigned char * to, const unsigned char * from, int n)
*to = *from;
break;
case 5:
to[4] = from [4]; /* { dg-warning "20:array subscript is above array bounds" } */
to[4] = from [4]; /* { dg-warning "array subscript is above array bounds" } */
break;
}
return to;

View File

@ -26,5 +26,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -39,5 +39,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -34,5 +34,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -37,5 +37,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -28,6 +28,6 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -61,6 +61,6 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 2" "ipa_struct_reorg" } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 2" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -39,5 +39,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" } } */
/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final-use { cleanup-ipa-dump "*" } } */

View File

@ -23,5 +23,5 @@ int main()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -35,5 +35,5 @@ main ()
return 0;
}
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -26,5 +26,5 @@ int main()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -43,5 +43,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "No structures to transform" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "No structures to transform" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -42,5 +42,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "is passed to local function...Excluded." "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "is passed to local function...Excluded." "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -29,5 +29,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "is return type of function...Excluded" "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "is return type of function...Excluded" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -28,6 +28,6 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "is initialized...Excluded" "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "is initialized...Excluded" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -30,5 +30,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -45,5 +45,5 @@ main (void)
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -42,5 +42,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" } } */
/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -29,5 +29,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -42,5 +42,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -37,5 +37,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -40,5 +40,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -44,5 +44,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -31,5 +31,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -31,5 +31,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "No structures to transform" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "No structures to transform" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -64,5 +64,5 @@ main ()
}
/*--------------------------------------------------------------------------*/
/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "ipa_struct_reorg" { xfail { "avr-*-*" } } } } */
/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "ipa_struct_reorg" { xfail *-*-* } } } */
/* { dg-final { cleanup-ipa-dump "*" } } */

View File

@ -16,7 +16,7 @@ main()
/* { dg-final-use { scan-tree-dump "Single value 4 stringop" "tree_profile"} } */
/* Really this ought to simplify into assignment, but we are not there yet. */
/* a[0] = b[0] is what we fold the resulting memcpy into. */
/* { dg-final-use { scan-tree-dump "a.0. = " "optimized"} } */
/* { dg-final-use { scan-tree-dump "= b.0." "optimized"} } */
/* { dg-final-use { scan-tree-dump " = MEM.*&b" "optimized"} } */
/* { dg-final-use { scan-tree-dump "MEM.*&a\\\] = " "optimized"} } */
/* { dg-final-use { cleanup-tree-dump "optimized" } } */
/* { dg-final-use { cleanup-tree-dump "tree_profile" } } */

View File

@ -33,5 +33,5 @@ simplify_condition (cond_p)
}
/* There should be exactly one IF conditional. */
/* { dg-final { scan-tree-dump-times "if " 1 "vrp1" } } */
/* { dg-final { scan-tree-dump-times "if " 1 "vrp1" { xfail *-*-* } } } */
/* { dg-final { cleanup-tree-dump "vrp1" } } */

View File

@ -1,13 +0,0 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized" } */
struct a{
int a;
int b;
} a;
int *
t()
{
return (int *)&a;
}
/* { dg-final { scan-tree-dump "a.a" "optimized"} } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -1,28 +0,0 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-optimized" } */
union a
{
struct s1
{
long long a;
long long b;
} s1;
struct s2
{
int c;
int d;
} s2;
struct s3
{
unsigned long long e;
unsigned long long f;
} s3;
} a;
int *
t ()
{
return (int *) &a;
}
/* { dg-final { scan-tree-dump "a.s2.c" "optimized"} } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -15,5 +15,5 @@ void f(struct a * b, __SIZE_TYPE__ i)
c[i] = 1;
}
/* { dg-final { scan-tree-dump-times "t\\\[i.*\\\] =.* 1;" 1 "forwprop1" } } */
/* { dg-final { scan-tree-dump-times "t\\\[i.*\\\].* = 1;" 1 "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-forwprop1" } */
/* { dg-options "-O -fdump-tree-fre-details" } */
int b;
unsigned a;
@ -15,9 +15,8 @@ void test2(void)
}
/* The indirect load should be replaced by a load from a and a
conversion to int. */
conversion to int. FRE should then be able to replace
the rhs of the store to b by 1. */
/* { dg-final { scan-tree-dump "= a;" "forwprop1" } } */
/* { dg-final { scan-tree-dump "= \\\(int\\\) " "forwprop1" } } */
/* { dg-final { scan-tree-dump-not "= \\\*" "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */
/* { dg-final { scan-tree-dump "Replaced\[^\\n\]*with 1" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -17,5 +17,5 @@ void f(__SIZE_TYPE__ i)
c[i] = 1;
}
/* { dg-final { scan-tree-dump-times "t\\\[i.*\\\] =.* 1;" 1 "forwprop1" } } */
/* { dg-final { scan-tree-dump-times "t\\\[i.*\\\].* = 1;" 1 "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop?" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-forwprop1 -w" } */
/* { dg-options "-O1 -fdump-tree-esra -w" } */
#define vector __attribute__((vector_size(16) ))
struct VecClass
@ -15,7 +15,8 @@ vector float foo( vector float v )
return y.v;
}
/* We should be able to convert the cast to a VCE in forwprop1. */
/* { dg-final { scan-tree-dump-times "VIEW_CONVERT_EXPR" 1 "forwprop1"} } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */
/* We should be able to remove the intermediate struct and directly
return x. As we do not fold VIEW_CONVERT_EXPR<struct VecClass>(x).v
that doesn't happen right now. */
/* { dg-final { scan-tree-dump-times "VIEW_CONVERT_EXPR" 1 "esra"} } */
/* { dg-final { cleanup-tree-dump "esra" } } */

View File

@ -12,5 +12,5 @@ int foo(struct X *q)
/* We should have propragated &q->a into (*pointer). */
/* { dg-final { scan-tree-dump-times "pointer" 0 "forwprop1"} } */
/* { dg-final { scan-tree-dump "->a\\\[0\\\]" "forwprop1" } } */
/* { dg-final { scan-tree-dump "\\\[0\\\]" "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
/* { dg-options "-O2 -fdump-tree-pre-stats -fdump-tree-fre" } */
#include <stddef.h>
union tree_node;
@ -72,7 +72,9 @@ main (void)
remove_useless_vars (&unexpanded_var_list, 0);
return 0;
}
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
/* See PR44656. The last elimination is only done by PRE. */
/* { dg-final { scan-tree-dump-not "= unexpanded_var_list;" "fre" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 2 "pre" } } */
/* { dg-final { scan-tree-dump-times "Insertions: 2" 1 "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-forwprop1" } */
/* { dg-options "-O -fdump-tree-forwprop1" } */
struct A { int i; };
int
@ -11,5 +11,7 @@ foo(struct A *locp, int str)
return locp->i;
}
/* { dg-final { scan-tree-dump "locp.*->i =" "forwprop1" } } */
/* We should have propagated &locp->i into its dereference. */
/* { dg-final { scan-tree-dump "locp_\[^\\n\]* =" "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-alias" } */
/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-ealias" } */
extern void abort (void);
struct X {
@ -22,5 +22,5 @@ foo(int i, int j, int k, int off)
return *q;
}
/* { dg-final { scan-tree-dump "q_., points-to vars: { k }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */
/* { dg-final { scan-tree-dump "q_., points-to vars: { k }" "ealias" } } */
/* { dg-final { cleanup-tree-dump "ealias" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-alias" } */
/* { dg-options "-O2 -fno-tree-ccp -fdump-tree-ealias" } */
extern void abort (void);
struct X {
@ -22,5 +22,5 @@ foo(int i, int j, int k, int off)
return *q;
}
/* { dg-final { scan-tree-dump "q_., points-to vars: { i }" "alias" } } */
/* { dg-final { cleanup-tree-dump "alias" } } */
/* { dg-final { scan-tree-dump "q_., points-to vars: { i }" "ealias" } } */
/* { dg-final { cleanup-tree-dump "ealias" } } */

View File

@ -21,5 +21,9 @@ int bar (void)
return q->i;
}
/* { dg-final { scan-tree-dump-times "a.b.i" 2 "ccp1" } } */
/* The first access is through struct A, so a.b.i is fine,
the second access needs to preserve the original access type struct B. */
/* { dg-final { scan-tree-dump-times "a.b.i" 1 "ccp1" } } */
/* { dg-final { scan-tree-dump-times "MEM\\\[\\\(struct B \\\*\\\)&a\\\].i" 1 "ccp1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */

View File

@ -15,5 +15,5 @@ int foo (void)
return *x;
}
/* { dg-final { scan-tree-dump "a.i\\\[1\\\]" "ccp1" } } */
/* { dg-final { scan-tree-dump "MEM\\\[\\\(int \\\*\\\)&a \\\+ 4B\\\]" "ccp1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */

View File

@ -9,6 +9,6 @@ int foo(int i)
}
/* { dg-final { scan-tree-dump "&a\\\[\[iD\]\\\." "ccp1" } } */
/* { dg-final { scan-tree-dump "= a\\\[\[iD\]\\\." "forwprop1" } } */
/* { dg-final { scan-tree-dump "= .*&a\\\]\\\[\[iD\]\\\." "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */

View File

@ -7,5 +7,5 @@ int foo(int i)
return (a + 1)[i];
}
/* { dg-final { scan-tree-dump "= a\\\[D\\\." "forwprop1" } } */
/* { dg-final { scan-tree-dump "=.*&a\\\]\\\[D\\\." "forwprop1" } } */
/* { dg-final { cleanup-tree-dump "forwprop1" } } */

View File

@ -11,6 +11,5 @@ int f(int *a)
return *c + t;
}
/* { dg-final { scan-tree-dump "Replaced \\\(int \\\*\\\) b_.*with a_" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced \\\*c_.*with t_" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced \\\*a_\[^\n\].*with t_" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -23,6 +23,5 @@ void foo(double (*q)[4], struct Foo *tmp1)
}
}
/* { dg-final { scan-tree-dump "Inserted .* &a" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced tmp1_.\\\(D\\\)->data" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced tmp1_.\\\(D\\\)->data with &a" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -27,6 +27,5 @@ void foo(double (*q)[4])
bar(a);
}
/* { dg-final { scan-tree-dump "Inserted .* &a" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced tmp1.data" "fre" } } */
/* { dg-final { scan-tree-dump "Replaced tmp1.data with &a" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-Os -fdump-tree-pre-details" } */
/* { dg-options "-O -fdump-tree-fre-details" } */
typedef union
{
@ -23,5 +23,5 @@ void foo(SA* pResult, SB* method, SC* self)
pResult->data = pResult->data;
}
/* { dg-final { scan-tree-dump "Deleted redundant store" "pre" } } */
/* { dg-final { cleanup-tree-dump "pre" } } */
/* { dg-final { scan-tree-dump "Deleted redundant store" "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -7,6 +7,6 @@ foo (int *array)
return array[1];
return 0;
}
/* We should eliminate one address calculation, and one load. */
/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "fre"} } */
/* We should eliminate one load. */
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "fre"} } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -23,5 +23,5 @@ int vnum_test8(int *data)
}
/* We should eliminate m - n, n + k, set data[5] = 0, eliminate the
address arithmetic for data[5], and set p = 0.
/* { dg-final { scan-tree-dump-times "Eliminated: 7" 1 "fre"} } */
/* { dg-final { scan-tree-dump-times "Eliminated: 5" 1 "fre"} } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do "compile" } */
/* { dg-options "-O2 -fdump-tree-fre" } */
/* { dg-options "-O2 -fdump-tree-fre-details" } */
struct S { float f; };
int __attribute__((noinline))
@ -11,5 +11,5 @@ foo (float *r, struct S *p)
return i + *q;
}
/* { dg-final { scan-tree-dump-times "\\\*q" 1 "fre" } } */
/* { dg-final { scan-tree-dump "Replaced\[^\n\]*with i_." "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -12,7 +12,8 @@ foo ( struct S *p)
}
/* There should only be one load of p->f because fwprop can change *(int *)&p->f into just (int)p->f. */
/* { dg-final { scan-tree-dump-times "p_.\\\(D\\\)->f" 1 "fre" } } */
/* There should only be one load of p->f because fwprop can change
*(int *)&p->f into just (int)p->f. */
/* { dg-final { scan-tree-dump-times "= \[^\n\]*p_.\\\(D\\\)" 1 "fre" } } */
/* { dg-final { cleanup-tree-dump "fre" } } */

View File

@ -1,5 +1,5 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-gimple -fdump-tree-optimized" } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
struct GTeth_desc
{
@ -12,14 +12,11 @@ struct GTeth_softc
void foo(struct GTeth_softc *sc)
{
/* Verify that we retain the cast to (volatile struct GTeth_desc *)
after gimplification and that we keep the volatileness on the
/* Verify that we retain the volatileness on the
store until after optimization. */
volatile struct GTeth_desc *p = &sc->txq_desc[0];
p->ed_cmdsts = 0;
}
/* { dg-final { scan-tree-dump "\\(volatile struct GTeth_desc \\*\\) D" "gimple" } } */
/* { dg-final { scan-tree-dump "{v}" "optimized" } } */
/* { dg-final { cleanup-tree-dump "gimple" } } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

View File

@ -11,5 +11,5 @@ subroutine bar(x)
x = (/ 3, 1, 4, 1 /)
end subroutine
! { dg-final { scan-tree-dump-times "memcpy|ref-all" 2 "original" } }
! { dg-final { scan-tree-dump-times "memcpy|(ref-all.*ref-all)" 2 "original" } }
! { dg-final { cleanup-tree-dump "original" } }

View File

@ -9,5 +9,5 @@
d = s
end
! { dg-final { scan-tree-dump-times "d = " 1 "original" } }
! { dg-final { scan-tree-dump-times "MEM.*d\\\] = MEM" 1 "original" } }
! { dg-final { cleanup-tree-dump "original" } }

View File

@ -309,6 +309,15 @@ tree_to_aff_combination (tree expr, tree type, aff_tree *comb)
return;
case ADDR_EXPR:
/* Handle &MEM[ptr + CST] which is equivalent to POINTER_PLUS_EXPR. */
if (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF)
{
expr = TREE_OPERAND (expr, 0);
tree_to_aff_combination (TREE_OPERAND (expr, 0), type, comb);
tree_to_aff_combination (TREE_OPERAND (expr, 1), sizetype, &tmp);
aff_combination_add (comb, &tmp);
return;
}
core = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize, &bitpos,
&toffset, &mode, &unsignedp, &volatilep,
false);
@ -331,6 +340,25 @@ tree_to_aff_combination (tree expr, tree type, aff_tree *comb)
}
return;
case MEM_REF:
if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
tree_to_aff_combination (TREE_OPERAND (TREE_OPERAND (expr, 0), 0),
type, comb);
else if (integer_zerop (TREE_OPERAND (expr, 1)))
{
aff_combination_elt (comb, type, expr);
return;
}
else
aff_combination_elt (comb, type,
build2 (MEM_REF, TREE_TYPE (expr),
TREE_OPERAND (expr, 0),
build_int_cst
(TREE_TYPE (TREE_OPERAND (expr, 1)), 0)));
tree_to_aff_combination (TREE_OPERAND (expr, 1), sizetype, &tmp);
aff_combination_add (comb, &tmp);
return;
default:
break;
}

View File

@ -2533,6 +2533,49 @@ gimple_split_edge (edge edge_in)
return new_bb;
}
/* Verify properties of the address expression T with base object BASE. */
static tree
verify_address (tree t, tree base)
{
bool old_constant;
bool old_side_effects;
bool new_constant;
bool new_side_effects;
old_constant = TREE_CONSTANT (t);
old_side_effects = TREE_SIDE_EFFECTS (t);
recompute_tree_invariant_for_addr_expr (t);
new_side_effects = TREE_SIDE_EFFECTS (t);
new_constant = TREE_CONSTANT (t);
if (old_constant != new_constant)
{
error ("constant not recomputed when ADDR_EXPR changed");
return t;
}
if (old_side_effects != new_side_effects)
{
error ("side effects not recomputed when ADDR_EXPR changed");
return t;
}
if (!(TREE_CODE (base) == VAR_DECL
|| TREE_CODE (base) == PARM_DECL
|| TREE_CODE (base) == RESULT_DECL))
return NULL_TREE;
if (DECL_GIMPLE_REG_P (base))
{
error ("DECL_GIMPLE_REG_P set on a variable with address taken");
return base;
}
return NULL_TREE;
}
/* Callback for walk_tree, check that all elements with address taken are
properly noticed as such. The DATA is an int* that is 1 if TP was seen
inside a PHI node. */
@ -2561,12 +2604,26 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
break;
case INDIRECT_REF:
error ("INDIRECT_REF in gimple IL");
return t;
case MEM_REF:
x = TREE_OPERAND (t, 0);
if (!is_gimple_reg (x) && !is_gimple_min_invariant (x))
if (!is_gimple_mem_ref_addr (x))
{
error ("Indirect reference's operand is not a register or a constant.");
error ("Invalid first operand of MEM_REF.");
return x;
}
if (TREE_CODE (TREE_OPERAND (t, 1)) != INTEGER_CST
|| !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1))))
{
error ("Invalid offset operand of MEM_REF.");
return TREE_OPERAND (t, 1);
}
if (TREE_CODE (x) == ADDR_EXPR
&& (x = verify_address (x, TREE_OPERAND (x, 0))))
return x;
*walk_subtrees = 0;
break;
case ASSERT_EXPR:
@ -2584,31 +2641,10 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
case ADDR_EXPR:
{
bool old_constant;
bool old_side_effects;
bool new_constant;
bool new_side_effects;
tree tem;
gcc_assert (is_gimple_address (t));
old_constant = TREE_CONSTANT (t);
old_side_effects = TREE_SIDE_EFFECTS (t);
recompute_tree_invariant_for_addr_expr (t);
new_side_effects = TREE_SIDE_EFFECTS (t);
new_constant = TREE_CONSTANT (t);
if (old_constant != new_constant)
{
error ("constant not recomputed when ADDR_EXPR changed");
return t;
}
if (old_side_effects != new_side_effects)
{
error ("side effects not recomputed when ADDR_EXPR changed");
return t;
}
/* Skip any references (they will be checked when we recurse down the
tree) and ensure that any variable used as a prefix is marked
addressable. */
@ -2617,20 +2653,19 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
x = TREE_OPERAND (x, 0))
;
if ((tem = verify_address (t, x)))
return tem;
if (!(TREE_CODE (x) == VAR_DECL
|| TREE_CODE (x) == PARM_DECL
|| TREE_CODE (x) == RESULT_DECL))
return NULL;
if (!TREE_ADDRESSABLE (x))
{
error ("address taken, but ADDRESSABLE bit not set");
return x;
}
if (DECL_GIMPLE_REG_P (x))
{
error ("DECL_GIMPLE_REG_P set on a variable with address taken");
return x;
}
break;
}
@ -2815,8 +2850,10 @@ verify_types_in_gimple_min_lval (tree expr)
if (is_gimple_id (expr))
return false;
if (!INDIRECT_REF_P (expr)
&& TREE_CODE (expr) != TARGET_MEM_REF)
if (TREE_CODE (expr) != ALIGN_INDIRECT_REF
&& TREE_CODE (expr) != MISALIGNED_INDIRECT_REF
&& TREE_CODE (expr) != TARGET_MEM_REF
&& TREE_CODE (expr) != MEM_REF)
{
error ("invalid expression for min lvalue");
return true;
@ -2833,14 +2870,7 @@ verify_types_in_gimple_min_lval (tree expr)
debug_generic_stmt (op);
return true;
}
if (!useless_type_conversion_p (TREE_TYPE (expr),
TREE_TYPE (TREE_TYPE (op))))
{
error ("type mismatch in indirect reference");
debug_generic_stmt (TREE_TYPE (expr));
debug_generic_stmt (TREE_TYPE (TREE_TYPE (op)));
return true;
}
/* Memory references now generally can involve a value conversion. */
return false;
}
@ -2927,6 +2957,13 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue)
debug_generic_stmt (expr);
return true;
}
else if (TREE_CODE (op) == SSA_NAME
&& TYPE_SIZE (TREE_TYPE (expr)) != TYPE_SIZE (TREE_TYPE (op)))
{
error ("Conversion of register to a different size.");
debug_generic_stmt (expr);
return true;
}
else if (!handled_component_p (op))
return false;
}
@ -2934,6 +2971,23 @@ verify_types_in_gimple_reference (tree expr, bool require_lvalue)
expr = op;
}
if (TREE_CODE (expr) == MEM_REF)
{
if (!is_gimple_mem_ref_addr (TREE_OPERAND (expr, 0)))
{
error ("Invalid address operand in MEM_REF.");
debug_generic_stmt (expr);
return true;
}
if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST
|| !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))))
{
error ("Invalid offset operand in MEM_REF.");
debug_generic_stmt (expr);
return true;
}
}
return ((require_lvalue || !is_gimple_min_invariant (expr))
&& verify_types_in_gimple_min_lval (expr));
}
@ -3642,9 +3696,12 @@ verify_gimple_assign_single (gimple stmt)
}
/* tcc_reference */
case INDIRECT_REF:
error ("INDIRECT_REF in gimple IL");
return true;
case COMPONENT_REF:
case BIT_FIELD_REF:
case INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
case ARRAY_REF:
@ -3653,6 +3710,7 @@ verify_gimple_assign_single (gimple stmt)
case REALPART_EXPR:
case IMAGPART_EXPR:
case TARGET_MEM_REF:
case MEM_REF:
if (!is_gimple_reg (lhs)
&& is_gimple_reg_type (TREE_TYPE (lhs)))
{

View File

@ -596,10 +596,10 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
case VAR_DECL:
case RESULT_DECL:
case PARM_DECL:
case INDIRECT_REF:
case COMPONENT_REF:
case ARRAY_REF:
case VIEW_CONVERT_EXPR:
case MEM_REF:
{
tree inner_type = TREE_TYPE (TREE_TYPE (t));

View File

@ -746,7 +746,22 @@ dr_analyze_innermost (struct data_reference *dr)
return false;
}
base = build_fold_addr_expr (base);
if (TREE_CODE (base) == MEM_REF)
{
if (!integer_zerop (TREE_OPERAND (base, 1)))
{
if (!poffset)
{
double_int moff = mem_ref_offset (base);
poffset = double_int_to_tree (sizetype, moff);
}
else
poffset = size_binop (PLUS_EXPR, poffset, TREE_OPERAND (base, 1));
}
base = TREE_OPERAND (base, 0);
}
else
base = build_fold_addr_expr (base);
if (in_loop)
{
if (!simple_iv (loop, loop_containing_stmt (stmt), base, &base_iv,
@ -844,13 +859,18 @@ dr_analyze_indices (struct data_reference *dr, struct loop *nest)
aref = TREE_OPERAND (aref, 0);
}
if (nest && INDIRECT_REF_P (aref))
if (nest
&& (INDIRECT_REF_P (aref)
|| TREE_CODE (aref) == MEM_REF))
{
op = TREE_OPERAND (aref, 0);
access_fn = analyze_scalar_evolution (loop, op);
access_fn = instantiate_scev (before_loop, loop, access_fn);
base = initial_condition (access_fn);
split_constant_offset (base, &base, &off);
if (TREE_CODE (aref) == MEM_REF)
off = size_binop (PLUS_EXPR, off,
fold_convert (ssizetype, TREE_OPERAND (aref, 1)));
access_fn = chrec_replace_initial_condition (access_fn,
fold_convert (TREE_TYPE (base), off));
@ -858,6 +878,22 @@ dr_analyze_indices (struct data_reference *dr, struct loop *nest)
VEC_safe_push (tree, heap, access_fns, access_fn);
}
if (TREE_CODE (aref) == MEM_REF)
TREE_OPERAND (aref, 1)
= build_int_cst (TREE_TYPE (TREE_OPERAND (aref, 1)), 0);
if (TREE_CODE (ref) == MEM_REF
&& TREE_CODE (TREE_OPERAND (ref, 0)) == ADDR_EXPR
&& integer_zerop (TREE_OPERAND (ref, 1)))
ref = TREE_OPERAND (TREE_OPERAND (ref, 0), 0);
/* For canonicalization purposes we'd like to strip all outermost
zero-offset component-refs.
??? For now simply handle zero-index array-refs. */
while (TREE_CODE (ref) == ARRAY_REF
&& integer_zerop (TREE_OPERAND (ref, 1)))
ref = TREE_OPERAND (ref, 0);
DR_BASE_OBJECT (dr) = ref;
DR_ACCESS_FNS (dr) = access_fns;
}
@ -870,7 +906,8 @@ dr_analyze_alias (struct data_reference *dr)
tree ref = DR_REF (dr);
tree base = get_base_address (ref), addr;
if (INDIRECT_REF_P (base))
if (INDIRECT_REF_P (base)
|| TREE_CODE (base) == MEM_REF)
{
addr = TREE_OPERAND (base, 0);
if (TREE_CODE (addr) == SSA_NAME)
@ -1188,7 +1225,8 @@ object_address_invariant_in_loop_p (const struct loop *loop, const_tree obj)
obj = TREE_OPERAND (obj, 0);
}
if (!INDIRECT_REF_P (obj))
if (!INDIRECT_REF_P (obj)
&& TREE_CODE (obj) != MEM_REF)
return true;
return !chrec_contains_symbols_defined_in_loop (TREE_OPERAND (obj, 0),

View File

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "toplev.h"
#include "hashtab.h"
#include "pointer-set.h"
#include "tree.h"
@ -855,6 +856,29 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
case VIEW_CONVERT_EXPR:
break;
case MEM_REF:
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
{
if (integer_zerop (TREE_OPERAND (exp, 1)))
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
else
{
double_int off = mem_ref_offset (exp);
off = double_int_lshift (off,
BITS_PER_UNIT == 8
? 3 : exact_log2 (BITS_PER_UNIT),
HOST_BITS_PER_DOUBLE_INT, true);
off = double_int_add (off, shwi_to_double_int (bit_offset));
if (double_int_fits_in_shwi_p (off))
{
bit_offset = double_int_to_shwi (off);
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
}
}
}
goto done;
default:
goto done;
}
@ -901,6 +925,104 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
return exp;
}
/* Returns the base object and a constant BITS_PER_UNIT offset in *POFFSET that
denotes the starting address of the memory access EXP.
Returns NULL_TREE if the offset is not constant or any component
is not BITS_PER_UNIT-aligned. */
tree
get_addr_base_and_unit_offset (tree exp, HOST_WIDE_INT *poffset)
{
HOST_WIDE_INT byte_offset = 0;
/* Compute cumulative byte-offset for nested component-refs and array-refs,
and find the ultimate containing object. */
while (1)
{
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
return NULL_TREE;
case COMPONENT_REF:
{
tree field = TREE_OPERAND (exp, 1);
tree this_offset = component_ref_field_offset (exp);
HOST_WIDE_INT hthis_offset;
if (!this_offset
|| TREE_CODE (this_offset) != INTEGER_CST
|| (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
% BITS_PER_UNIT))
return NULL_TREE;
hthis_offset = TREE_INT_CST_LOW (this_offset);
hthis_offset += (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field))
/ BITS_PER_UNIT);
byte_offset += hthis_offset;
}
break;
case ARRAY_REF:
case ARRAY_RANGE_REF:
{
tree index = TREE_OPERAND (exp, 1);
tree low_bound, unit_size;
/* If the resulting bit-offset is constant, track it. */
if (TREE_CODE (index) == INTEGER_CST
&& (low_bound = array_ref_low_bound (exp),
TREE_CODE (low_bound) == INTEGER_CST)
&& (unit_size = array_ref_element_size (exp),
TREE_CODE (unit_size) == INTEGER_CST))
{
HOST_WIDE_INT hindex = TREE_INT_CST_LOW (index);
hindex -= TREE_INT_CST_LOW (low_bound);
hindex *= TREE_INT_CST_LOW (unit_size);
byte_offset += hindex;
}
else
return NULL_TREE;
}
break;
case REALPART_EXPR:
break;
case IMAGPART_EXPR:
byte_offset += TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (exp)));
break;
case VIEW_CONVERT_EXPR:
break;
case MEM_REF:
/* Hand back the decl for MEM[&decl, off]. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR)
{
if (!integer_zerop (TREE_OPERAND (exp, 1)))
{
double_int off = mem_ref_offset (exp);
gcc_assert (off.high == -1 || off.high == 0);
byte_offset += double_int_to_shwi (off);
}
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
}
goto done;
default:
goto done;
}
exp = TREE_OPERAND (exp, 0);
}
done:
*poffset = byte_offset;
return exp;
}
/* Returns true if STMT references an SSA_NAME that has
SSA_NAME_OCCURS_IN_ABNORMAL_PHI set, otherwise false. */

View File

@ -2437,6 +2437,10 @@ tree_could_trap_p (tree expr)
return false;
return !in_array_bounds_p (expr);
case MEM_REF:
if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
return false;
/* Fallthru. */
case INDIRECT_REF:
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:

Some files were not shown because too many files have changed in this diff Show More