Commit d242d063 by Martin Jambor Committed by Martin Jambor

re PR tree-optimization/44972 (ICE: in load_assign_lhs_subreplacements, at tree-sra.c:2475)

2010-09-10  Martin Jambor  <mjambor@suse.cz>

	PR tree-optimization/44972
	* tree-sra.c: Include toplev.h.
	(build_ref_for_offset): Entirely reimplemented.
	(build_ref_for_model): New function.
	(build_user_friendly_ref_for_offset): New function.
	(analyze_access_subtree): Removed build_ref_for_offset check.
	(propagate_subaccesses_across_link): Likewise.
	(create_artificial_child_access): Use
	build_user_friendly_ref_for_offset.
	(propagate_subaccesses_across_link): Likewise.
	(ref_expr_for_all_replacements_p): Removed.
	(generate_subtree_copies): Updated comment.  Use build_ref_for_model.
	(sra_modify_expr): Use build_ref_for_model.
	(load_assign_lhs_subreplacements): Likewise.
	(sra_modify_assign): Removed ref_expr_for_all_replacements_p checks,
	checks for return values of build_ref_for_offset.
	* ipa-cp.c (ipcp_lattice_from_jfunc): No need to check return value of
	build_ref_for_offset.
	* ipa-prop.h: Include gimple.h
	* ipa-prop.c (ipa_compute_jump_functions): Update to look for MEM_REFs.
	(ipa_analyze_indirect_call_uses): Update comment.
	* Makefile.in (tree-sra.o): Add $(GIMPLE_H) to dependencies.
	(IPA_PROP_H): Likewise.

	* testsuite/gcc.dg/ipa/ipa-sra-1.c: Adjust scanning expressions.
	* testsuite/gcc.dg/tree-ssa/pr45144.c: Likewise.
	* testsuite/gcc.dg/tree-ssa/forwprop-5.c: Likewise and scan optimzed
	dump instead.
        * testsuite/g++.dg/torture/pr44972.C: New test.

From-SVN: r164136
parent fffe1e40
2010-09-10 Martin Jambor <mjambor@suse.cz> 2010-09-10 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/44972 PR tree-optimization/44972
* tree-sra.c: Include toplev.h.
(build_ref_for_offset): Entirely reimplemented.
(build_ref_for_model): New function.
(build_user_friendly_ref_for_offset): New function.
(analyze_access_subtree): Removed build_ref_for_offset check.
(propagate_subaccesses_across_link): Likewise.
(create_artificial_child_access): Use
build_user_friendly_ref_for_offset.
(propagate_subaccesses_across_link): Likewise.
(ref_expr_for_all_replacements_p): Removed.
(generate_subtree_copies): Updated comment. Use build_ref_for_model.
(sra_modify_expr): Use build_ref_for_model.
(load_assign_lhs_subreplacements): Likewise.
(sra_modify_assign): Removed ref_expr_for_all_replacements_p checks,
checks for return values of build_ref_for_offset.
* ipa-cp.c (ipcp_lattice_from_jfunc): No need to check return value of
build_ref_for_offset.
* ipa-prop.h: Include gimple.h
* ipa-prop.c (ipa_compute_jump_functions): Update to look for MEM_REFs.
(ipa_analyze_indirect_call_uses): Update comment.
* Makefile.in (tree-sra.o): Add $(GIMPLE_H) to dependencies.
(IPA_PROP_H): Likewise.
2010-09-10 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/44972
* ipa-prop.c (ipa_modify_call_arguments): Build MEM_REF instead of * ipa-prop.c (ipa_modify_call_arguments): Build MEM_REF instead of
calling build_ref_for_offset. calling build_ref_for_offset.
......
...@@ -968,7 +968,7 @@ EBITMAP_H = ebitmap.h sbitmap.h ...@@ -968,7 +968,7 @@ EBITMAP_H = ebitmap.h sbitmap.h
LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \ LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
$(CGRAPH_H) $(VEC_H) vecprim.h $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(VEC_H) vecprim.h $(TREE_H) $(GIMPLE_H)
TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H) TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
IPA_PROP_H = ipa-prop.h $(TREE_H) $(VEC_H) $(CGRAPH_H) IPA_PROP_H = ipa-prop.h $(TREE_H) $(VEC_H) $(CGRAPH_H) $(GIMPLE_H)
GSTAB_H = gstab.h stab.def GSTAB_H = gstab.h stab.def
BITMAP_H = bitmap.h $(HASHTAB_H) statistics.h BITMAP_H = bitmap.h $(HASHTAB_H) statistics.h
GCC_PLUGIN_H = gcc-plugin.h highlev-plugin-common.h $(CONFIG_H) $(SYSTEM_H) \ GCC_PLUGIN_H = gcc-plugin.h highlev-plugin-common.h $(CONFIG_H) $(SYSTEM_H) \
...@@ -3143,10 +3143,10 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \ ...@@ -3143,10 +3143,10 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \
tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) \ tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) \
$(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h $(DBGCNT_H) tree-pretty-print.h gimple-pretty-print.h
tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \ tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \
$(TM_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) $(IPA_PROP_H) \ $(TM_H) $(TOPLEV_H) $(TREE_H) $(GIMPLE_H) $(CGRAPH_H) $(TREE_FLOW_H) \
$(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) $(PARAMS_H) \ $(IPA_PROP_H) $(DIAGNOSTIC_H) statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) \
$(TARGET_H) $(FLAGS_H) $(EXPR_H) tree-pretty-print.h $(DBGCNT_H) \ $(PARAMS_H) $(TARGET_H) $(FLAGS_H) $(EXPR_H) tree-pretty-print.h \
$(TREE_INLINE_H) gimple-pretty-print.h $(DBGCNT_H) $(TREE_INLINE_H) gimple-pretty-print.h
tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \ tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \
$(TREE_H) $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \ $(TREE_H) $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \
$(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(GIMPLE_H) \ $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(GIMPLE_H) \
......
...@@ -327,7 +327,6 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat, ...@@ -327,7 +327,6 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
{ {
struct ipcp_lattice *caller_lat; struct ipcp_lattice *caller_lat;
tree t; tree t;
bool ok;
caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id); caller_lat = ipcp_get_lattice (info, jfunc->value.ancestor.formal_id);
lat->type = caller_lat->type; lat->type = caller_lat->type;
...@@ -340,16 +339,9 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat, ...@@ -340,16 +339,9 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat,
return; return;
} }
t = TREE_OPERAND (caller_lat->constant, 0); t = TREE_OPERAND (caller_lat->constant, 0);
ok = build_ref_for_offset (&t, TREE_TYPE (t), t = build_ref_for_offset (t, jfunc->value.ancestor.offset,
jfunc->value.ancestor.offset, jfunc->value.ancestor.type, NULL, false);
jfunc->value.ancestor.type, false); lat->constant = build_fold_addr_expr (t);
if (!ok)
{
lat->type = IPA_BOTTOM;
lat->constant = NULL_TREE;
}
else
lat->constant = build_fold_addr_expr (t);
} }
else else
lat->type = IPA_BOTTOM; lat->type = IPA_BOTTOM;
......
...@@ -916,23 +916,27 @@ ipa_compute_jump_functions (struct cgraph_node *node, ...@@ -916,23 +916,27 @@ ipa_compute_jump_functions (struct cgraph_node *node,
static tree static tree
ipa_get_member_ptr_load_param (tree rhs, bool use_delta) ipa_get_member_ptr_load_param (tree rhs, bool use_delta)
{ {
tree rec, fld; tree rec, ref_offset, fld_offset;
tree ptr_field; tree ptr_field;
tree delta_field; tree delta_field;
if (TREE_CODE (rhs) != COMPONENT_REF) if (TREE_CODE (rhs) != MEM_REF)
return NULL_TREE; return NULL_TREE;
rec = TREE_OPERAND (rhs, 0); rec = TREE_OPERAND (rhs, 0);
if (TREE_CODE (rec) != ADDR_EXPR)
return NULL_TREE;
rec = TREE_OPERAND (rec, 0);
if (TREE_CODE (rec) != PARM_DECL if (TREE_CODE (rec) != PARM_DECL
|| !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, &delta_field)) || !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, &delta_field))
return NULL_TREE; return NULL_TREE;
fld = TREE_OPERAND (rhs, 1); ref_offset = TREE_OPERAND (rhs, 1);
if (use_delta ? (fld == delta_field) : (fld == ptr_field)) if (use_delta)
return rec; fld_offset = byte_position (delta_field);
else else
return NULL_TREE; fld_offset = byte_position (ptr_field);
return tree_int_cst_equal (ref_offset, fld_offset) ? rec : NULL_TREE;
} }
/* If STMT looks like a statement loading a value from a member pointer formal /* If STMT looks like a statement loading a value from a member pointer formal
...@@ -999,8 +1003,8 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt, ...@@ -999,8 +1003,8 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt,
below, the call is on the last line: below, the call is on the last line:
<bb 2>: <bb 2>:
f$__delta_5 = f.__delta; f$__delta_5 = MEM[(struct *)&f];
f$__pfn_24 = f.__pfn; f$__pfn_24 = MEM[(struct *)&f + 4B];
... ...
......
...@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h" #include "tree.h"
#include "vec.h" #include "vec.h"
#include "cgraph.h" #include "cgraph.h"
#include "gimple.h"
/* The following definitions and interfaces are used by /* The following definitions and interfaces are used by
interprocedural analyses or parameters. */ interprocedural analyses or parameters. */
...@@ -511,6 +512,7 @@ void ipa_prop_read_jump_functions (void); ...@@ -511,6 +512,7 @@ void ipa_prop_read_jump_functions (void);
void ipa_update_after_lto_read (void); void ipa_update_after_lto_read (void);
/* From tree-sra.c: */ /* From tree-sra.c: */
bool build_ref_for_offset (tree *, tree, HOST_WIDE_INT, tree, bool); tree build_ref_for_offset (tree, HOST_WIDE_INT, tree, gimple_stmt_iterator *,
bool);
#endif /* IPA_PROP_H */ #endif /* IPA_PROP_H */
2010-09-10 Martin Jambor <mjambor@suse.cz> 2010-09-10 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/44972 PR tree-optimization/44972
* gcc.dg/ipa/ipa-sra-1.c: Adjust scanning expressions.
* gcc.dg/tree-ssa/pr45144.c: Likewise.
* gcc.dg/tree-ssa/forwprop-5.c: Likewise and scan optimzed dump
instead.
* g++.dg/torture/pr44972.C: New test.
2010-09-10 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/44972
* g++.dg/torture/pr34850.C: Remove expected warning. * g++.dg/torture/pr34850.C: Remove expected warning.
2010-09-09 Steven G. Kargl <kargl@gcc.gnu.org> 2010-09-09 Steven G. Kargl <kargl@gcc.gnu.org>
......
/* { dg-do compile } */
#include<cassert>
#include<new>
#include<utility>
namespace boost {
template<class T>
class optional;
class aligned_storage
{
char data[ 1000 ];
public:
void const* address() const { return &data[0]; }
void * address() { return &data[0]; }
} ;
template<class T>
class optional_base
{
protected :
optional_base(){}
optional_base ( T const& val )
{
construct(val);
}
template<class U>
void assign ( optional<U> const& rhs )
{
if (!is_initialized())
if ( rhs.is_initialized() )
construct(T());
}
public :
bool is_initialized() const { return m_initialized ; }
protected :
void construct ( T const& val )
{
new (m_storage.address()) T(val) ;
}
T const* get_ptr_impl() const
{ return static_cast<T const*>(m_storage.address()); }
private :
bool m_initialized ;
aligned_storage m_storage ;
} ;
template<class T>
class optional : public optional_base<T>
{
typedef optional_base<T> base ;
public :
optional() : base() {}
optional ( T const& val ) : base(val) {}
optional& operator= ( optional const& rhs )
{
this->assign( rhs ) ;
return *this ;
}
T const& get() const ;
T const* operator->() const { ((this->is_initialized()) ? static_cast<void> (0) : __assert_fail ("this->is_initialized()", "pr44972.C", 78, __PRETTY_FUNCTION__)) ; return this->get_ptr_impl() ; }
} ;
} // namespace boost
namespace std
{
template<typename _Tp, std::size_t _Nm>
struct array
{
typedef _Tp value_type;
typedef const value_type* const_iterator;
value_type _M_instance[_Nm];
};
}
class NT
{
double _inf, _sup;
};
template < typename T > inline
std::array<T, 1>
make_array(const T& b1)
{
std::array<T, 1> a = { { b1 } };
return a;
}
class V
{
typedef std::array<NT, 1> Base;
Base base;
public:
V() {}
V(const NT &x)
: base(make_array(x)) {}
};
using boost::optional ;
optional< std::pair< NT, NT > >
linsolve_pointC2() ;
optional< V > construct_normal_offset_lines_isecC2 ( )
{
optional< std::pair<NT,NT> > ip;
ip = linsolve_pointC2();
V a(ip->first) ;
return a;
}
...@@ -36,6 +36,5 @@ main (int argc, char *argv[]) ...@@ -36,6 +36,5 @@ main (int argc, char *argv[])
return 0; return 0;
} }
/* { dg-final { scan-tree-dump "About to replace expr cow.green with ISRA" "eipa_sra" } } */ /* { dg-final { scan-tree-dump-times "About to replace expr" 2 "eipa_sra" } } */
/* { dg-final { scan-tree-dump "About to replace expr cow.blue with ISRA" "eipa_sra" } } */
/* { dg-final { cleanup-tree-dump "eipa_sra" } } */ /* { dg-final { cleanup-tree-dump "eipa_sra" } } */
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-esra -w" } */ /* { dg-options "-O1 -fdump-tree-optimized -w" } */
#define vector __attribute__((vector_size(16) )) #define vector __attribute__((vector_size(16) ))
struct VecClass struct VecClass
...@@ -11,12 +11,9 @@ vector float foo( vector float v ) ...@@ -11,12 +11,9 @@ vector float foo( vector float v )
{ {
vector float x = v; vector float x = v;
x = x + x; x = x + x;
struct VecClass y = *(struct VecClass*)&x; struct VecClass disappear = *(struct VecClass*)&x;
return y.v; return disappear.v;
} }
/* We should be able to remove the intermediate struct and directly /* { dg-final { scan-tree-dump-times "disappear" 0 "optimized"} } */
return x. As we do not fold VIEW_CONVERT_EXPR<struct VecClass>(x).v /* { dg-final { cleanup-tree-dump "optimized" } } */
that doesn't happen right now. */
/* { dg-final { scan-tree-dump-times "VIEW_CONVERT_EXPR" 1 "esra"} } */
/* { dg-final { cleanup-tree-dump "esra" } } */
...@@ -42,5 +42,5 @@ bar (unsigned orig, unsigned *new) ...@@ -42,5 +42,5 @@ bar (unsigned orig, unsigned *new)
*new = foo (&a); *new = foo (&a);
} }
/* { dg-final { scan-tree-dump "x = a;" "optimized"} } */ /* { dg-final { scan-tree-dump " = VIEW_CONVERT_EXPR<unsigned int>\\(a\\);" "optimized"} } */
/* { dg-final { cleanup-tree-dump "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */
...@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -76,6 +76,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h" #include "coretypes.h"
#include "alloc-pool.h" #include "alloc-pool.h"
#include "tm.h" #include "tm.h"
#include "toplev.h"
#include "tree.h" #include "tree.h"
#include "gimple.h" #include "gimple.h"
#include "cgraph.h" #include "cgraph.h"
...@@ -1320,15 +1321,106 @@ make_fancy_name (tree expr) ...@@ -1320,15 +1321,106 @@ make_fancy_name (tree expr)
return XOBFINISH (&name_obstack, char *); return XOBFINISH (&name_obstack, char *);
} }
/* Helper function for build_ref_for_offset. /* Construct a MEM_REF that would reference a part of aggregate BASE of type
EXP_TYPE at the given OFFSET. If BASE is something for which
get_addr_base_and_unit_offset returns NULL, gsi must be non-NULL and is used
to insert new statements either before or below the current one as specified
by INSERT_AFTER. This function is not capable of handling bitfields. */
FIXME: Eventually this should be rewritten to either re-use the tree
original access expression unshared (which is good for alias build_ref_for_offset (tree base, HOST_WIDE_INT offset,
analysis) or to build a MEM_REF expression. */ tree exp_type, gimple_stmt_iterator *gsi,
bool insert_after)
{
tree prev_base = base;
tree off;
location_t loc = EXPR_LOCATION (base);
HOST_WIDE_INT base_offset;
gcc_checking_assert (offset % BITS_PER_UNIT == 0);
base = get_addr_base_and_unit_offset (base, &base_offset);
/* get_addr_base_and_unit_offset returns NULL for references with a variable
offset such as array[var_index]. */
if (!base)
{
gimple stmt;
tree tmp, addr;
gcc_checking_assert (gsi);
tmp = create_tmp_reg (build_pointer_type (TREE_TYPE (prev_base)), NULL);
add_referenced_var (tmp);
tmp = make_ssa_name (tmp, NULL);
addr = build_fold_addr_expr (unshare_expr (prev_base));
stmt = gimple_build_assign (tmp, addr);
SSA_NAME_DEF_STMT (tmp) = stmt;
if (insert_after)
gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
else
gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
update_stmt (stmt);
off = build_int_cst (reference_alias_ptr_type (prev_base),
offset / BITS_PER_UNIT);
base = tmp;
}
else if (TREE_CODE (base) == MEM_REF)
{
off = build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)),
base_offset + offset / BITS_PER_UNIT);
off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1), off, 0);
base = unshare_expr (TREE_OPERAND (base, 0));
}
else
{
off = build_int_cst (reference_alias_ptr_type (base),
base_offset + offset / BITS_PER_UNIT);
base = build_fold_addr_expr (unshare_expr (base));
}
return fold_build2_loc (loc, MEM_REF, exp_type, base, off);
}
/* Construct a memory reference to a part of an aggregate BASE at the given
OFFSET and of the same type as MODEL. In case this is a reference to a
bit-field, the function will replicate the last component_ref of model's
expr to access it. GSI and INSERT_AFTER have the same meaning as in
build_ref_for_offset. */
static tree
build_ref_for_model (tree base, HOST_WIDE_INT offset,
struct access *model, gimple_stmt_iterator *gsi,
bool insert_after)
{
if (TREE_CODE (model->expr) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (model->expr, 1)))
{
/* This access represents a bit-field. */
tree t, exp_type;
offset -= int_bit_position (TREE_OPERAND (model->expr, 1));
exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
t = build_ref_for_offset (base, offset, exp_type, gsi, insert_after);
return fold_build3_loc (EXPR_LOCATION (base), COMPONENT_REF,
model->type, t, TREE_OPERAND (model->expr, 1),
NULL_TREE);
}
else
return build_ref_for_offset (base, offset, model->type, gsi, insert_after);
}
/* Construct a memory reference consisting of component_refs and array_refs to
a part of an aggregate *RES (which is of type TYPE). The requested part
should have type EXP_TYPE at be the given OFFSET. This function might not
succeed, it returns true when it does and only then *RES points to something
meaningful. This function should be used only to build expressions that we
might need to present to user (e.g. in warnings). In all other situations,
build_ref_for_model or build_ref_for_offset should be used instead. */
static bool static bool
build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, build_user_friendly_ref_for_offset (tree *res, tree type, HOST_WIDE_INT offset,
tree exp_type) tree exp_type)
{ {
while (1) while (1)
{ {
...@@ -1367,19 +1459,13 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, ...@@ -1367,19 +1459,13 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
else if (pos > offset || (pos + size) <= offset) else if (pos > offset || (pos + size) <= offset)
continue; continue;
if (res) expr = build3 (COMPONENT_REF, TREE_TYPE (fld), *res, fld,
NULL_TREE);
expr_ptr = &expr;
if (build_user_friendly_ref_for_offset (expr_ptr, TREE_TYPE (fld),
offset - pos, exp_type))
{ {
expr = build3 (COMPONENT_REF, TREE_TYPE (fld), *res, fld, *res = expr;
NULL_TREE);
expr_ptr = &expr;
}
else
expr_ptr = NULL;
if (build_ref_for_offset_1 (expr_ptr, TREE_TYPE (fld),
offset - pos, exp_type))
{
if (res)
*res = expr;
return true; return true;
} }
} }
...@@ -1394,14 +1480,11 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, ...@@ -1394,14 +1480,11 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
if (TREE_CODE (minidx) != INTEGER_CST || el_size == 0) if (TREE_CODE (minidx) != INTEGER_CST || el_size == 0)
return false; return false;
if (res) index = build_int_cst (TYPE_DOMAIN (type), offset / el_size);
{ if (!integer_zerop (minidx))
index = build_int_cst (TYPE_DOMAIN (type), offset / el_size); index = int_const_binop (PLUS_EXPR, index, minidx, 0);
if (!integer_zerop (minidx)) *res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index,
index = int_const_binop (PLUS_EXPR, index, minidx, 0); NULL_TREE, NULL_TREE);
*res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index,
NULL_TREE, NULL_TREE);
}
offset = offset % el_size; offset = offset % el_size;
type = TREE_TYPE (type); type = TREE_TYPE (type);
break; break;
...@@ -1418,31 +1501,6 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, ...@@ -1418,31 +1501,6 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset,
} }
} }
/* Construct an expression that would reference a part of aggregate *EXPR of
type TYPE at the given OFFSET of the type EXP_TYPE. If EXPR is NULL, the
function only determines whether it can build such a reference without
actually doing it, otherwise, the tree it points to is unshared first and
then used as a base for furhter sub-references. */
bool
build_ref_for_offset (tree *expr, tree type, HOST_WIDE_INT offset,
tree exp_type, bool allow_ptr)
{
location_t loc = expr ? EXPR_LOCATION (*expr) : UNKNOWN_LOCATION;
if (expr)
*expr = unshare_expr (*expr);
if (allow_ptr && POINTER_TYPE_P (type))
{
type = TREE_TYPE (type);
if (expr)
*expr = build_simple_mem_ref_loc (loc, *expr);
}
return build_ref_for_offset_1 (expr, type, offset, exp_type);
}
/* Return true iff TYPE is stdarg va_list type. */ /* Return true iff TYPE is stdarg va_list type. */
static inline bool static inline bool
...@@ -1823,13 +1881,7 @@ analyze_access_subtree (struct access *root, bool allow_replacements, ...@@ -1823,13 +1881,7 @@ analyze_access_subtree (struct access *root, bool allow_replacements,
if (allow_replacements && scalar && !root->first_child if (allow_replacements && scalar && !root->first_child
&& (root->grp_hint && (root->grp_hint
|| (root->grp_write && (direct_read || root->grp_assignment_read))) || (root->grp_write && (direct_read || root->grp_assignment_read))))
/* We must not ICE later on when trying to build an access to the
original data within the aggregate even when it is impossible to do in
a defined way like in the PR 42703 testcase. Therefore we check
pre-emptively here that we will be able to do that. */
&& build_ref_for_offset (NULL, TREE_TYPE (root->base), root->offset,
root->type, false))
{ {
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
...@@ -1914,12 +1966,11 @@ create_artificial_child_access (struct access *parent, struct access *model, ...@@ -1914,12 +1966,11 @@ create_artificial_child_access (struct access *parent, struct access *model,
{ {
struct access *access; struct access *access;
struct access **child; struct access **child;
tree expr = parent->base;; tree expr = parent->base;
gcc_assert (!model->grp_unscalarizable_region); gcc_assert (!model->grp_unscalarizable_region);
if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
if (!build_ref_for_offset (&expr, TREE_TYPE (expr), new_offset, model->type))
model->type, false))
return NULL; return NULL;
access = (struct access *) pool_alloc (access_pool); access = (struct access *) pool_alloc (access_pool);
...@@ -1964,8 +2015,8 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc) ...@@ -1964,8 +2015,8 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
{ {
tree t = lacc->base; tree t = lacc->base;
if (build_ref_for_offset (&t, TREE_TYPE (t), lacc->offset, racc->type, if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t), lacc->offset,
false)) racc->type))
{ {
lacc->expr = t; lacc->expr = t;
lacc->type = racc->type; lacc->type = racc->type;
...@@ -1994,13 +2045,6 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc) ...@@ -1994,13 +2045,6 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
continue; continue;
} }
/* If a (part of) a union field is on the RHS of an assignment, it can
have sub-accesses which do not make sense on the LHS (PR 40351).
Check that this is not the case. */
if (!build_ref_for_offset (NULL, TREE_TYPE (lacc->base), norm_offset,
rchild->type, false))
continue;
rchild->grp_hint = 1; rchild->grp_hint = 1;
new_acc = create_artificial_child_access (lacc, rchild, norm_offset); new_acc = create_artificial_child_access (lacc, rchild, norm_offset);
if (new_acc) if (new_acc)
...@@ -2124,48 +2168,19 @@ analyze_all_variable_accesses (void) ...@@ -2124,48 +2168,19 @@ analyze_all_variable_accesses (void)
return false; return false;
} }
/* Return true iff a reference statement into aggregate AGG can be built for
every single to-be-replaced accesses that is a child of ACCESS, its sibling
or a child of its sibling. TOP_OFFSET is the offset from the processed
access subtree that has to be subtracted from offset of each access. */
static bool
ref_expr_for_all_replacements_p (struct access *access, tree agg,
HOST_WIDE_INT top_offset)
{
do
{
if (access->grp_to_be_replaced
&& !build_ref_for_offset (NULL, TREE_TYPE (agg),
access->offset - top_offset,
access->type, false))
return false;
if (access->first_child
&& !ref_expr_for_all_replacements_p (access->first_child, agg,
top_offset))
return false;
access = access->next_sibling;
}
while (access);
return true;
}
/* Generate statements copying scalar replacements of accesses within a subtree /* Generate statements copying scalar replacements of accesses within a subtree
into or out of AGG. ACCESS is the first child of the root of the subtree to into or out of AGG. ACCESS is the first child of the root of the subtree to
be processed. AGG is an aggregate type expression (can be a declaration but be processed. AGG is an aggregate type expression (can be a declaration but
does not have to be, it can for example also be an indirect_ref). does not have to be, it can for example also be a mem_ref or a series of
TOP_OFFSET is the offset of the processed subtree which has to be subtracted handled components). TOP_OFFSET is the offset of the processed subtree
from offsets of individual accesses to get corresponding offsets for AGG. which has to be subtracted from offsets of individual accesses to get
If CHUNK_SIZE is non-null, copy only replacements in the interval corresponding offsets for AGG. If CHUNK_SIZE is non-null, copy only
<start_offset, start_offset + chunk_size>, otherwise copy all. GSI is a replacements in the interval <start_offset, start_offset + chunk_size>,
statement iterator used to place the new statements. WRITE should be true otherwise copy all. GSI is a statement iterator used to place the new
when the statements should write from AGG to the replacement and false if statements. WRITE should be true when the statements should write from AGG
vice versa. if INSERT_AFTER is true, new statements will be added after the to the replacement and false if vice versa. if INSERT_AFTER is true, new
current statement in GSI, they will be added before the statement statements will be added after the current statement in GSI, they will be
otherwise. */ added before the statement otherwise. */
static void static void
generate_subtree_copies (struct access *access, tree agg, generate_subtree_copies (struct access *access, tree agg,
...@@ -2176,8 +2191,6 @@ generate_subtree_copies (struct access *access, tree agg, ...@@ -2176,8 +2191,6 @@ generate_subtree_copies (struct access *access, tree agg,
{ {
do do
{ {
tree expr = agg;
if (chunk_size && access->offset >= start_offset + chunk_size) if (chunk_size && access->offset >= start_offset + chunk_size)
return; return;
...@@ -2185,14 +2198,11 @@ generate_subtree_copies (struct access *access, tree agg, ...@@ -2185,14 +2198,11 @@ generate_subtree_copies (struct access *access, tree agg,
&& (chunk_size == 0 && (chunk_size == 0
|| access->offset + access->size > start_offset)) || access->offset + access->size > start_offset))
{ {
tree repl = get_access_replacement (access); tree expr, repl = get_access_replacement (access);
bool ref_found;
gimple stmt; gimple stmt;
ref_found = build_ref_for_offset (&expr, TREE_TYPE (agg), expr = build_ref_for_model (agg, access->offset - top_offset,
access->offset - top_offset, access, gsi, insert_after);
access->type, false);
gcc_assert (ref_found);
if (write) if (write)
{ {
...@@ -2329,12 +2339,10 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write) ...@@ -2329,12 +2339,10 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
in assembler statements (see PR42398). */ in assembler statements (see PR42398). */
if (!useless_type_conversion_p (type, access->type)) if (!useless_type_conversion_p (type, access->type))
{ {
tree ref = access->base; tree ref;
bool ok;
ok = build_ref_for_offset (&ref, TREE_TYPE (ref), ref = build_ref_for_model (access->base, access->offset, access,
access->offset, access->type, false); NULL, false);
gcc_assert (ok);
if (write) if (write)
{ {
...@@ -2458,25 +2466,11 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc, ...@@ -2458,25 +2466,11 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
lhs, old_gsi); lhs, old_gsi);
if (*refreshed == SRA_UDH_LEFT) if (*refreshed == SRA_UDH_LEFT)
{ rhs = build_ref_for_model (lacc->base, lacc->offset, lacc,
bool repl_found; new_gsi, true);
rhs = lacc->base;
repl_found = build_ref_for_offset (&rhs, TREE_TYPE (rhs),
lacc->offset, lacc->type,
false);
gcc_assert (repl_found);
}
else else
{ rhs = build_ref_for_model (top_racc->base, offset, lacc,
bool repl_found; new_gsi, true);
rhs = top_racc->base;
repl_found = build_ref_for_offset (&rhs,
TREE_TYPE (top_racc->base),
offset, lacc->type, false);
gcc_assert (repl_found);
}
} }
stmt = gimple_build_assign (get_access_replacement (lacc), rhs); stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
...@@ -2633,25 +2627,18 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) ...@@ -2633,25 +2627,18 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
if (AGGREGATE_TYPE_P (TREE_TYPE (lhs)) if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))
&& !access_has_children_p (lacc)) && !access_has_children_p (lacc))
{ {
tree expr = lhs; lhs = build_ref_for_offset (lhs, 0, TREE_TYPE (rhs), gsi, false);
if (build_ref_for_offset (&expr, TREE_TYPE (lhs), 0, gimple_assign_set_lhs (*stmt, lhs);
TREE_TYPE (rhs), false))
{
lhs = expr;
gimple_assign_set_lhs (*stmt, expr);
}
} }
else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs)) else if (AGGREGATE_TYPE_P (TREE_TYPE (rhs))
&& !contains_view_convert_expr_p (rhs)
&& !access_has_children_p (racc)) && !access_has_children_p (racc))
{ rhs = build_ref_for_offset (rhs, 0, TREE_TYPE (lhs), gsi, false);
tree expr = rhs;
if (build_ref_for_offset (&expr, TREE_TYPE (rhs), 0,
TREE_TYPE (lhs), false))
rhs = expr;
}
if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
{ {
rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (lhs), rhs); rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (lhs),
rhs);
if (is_gimple_reg_type (TREE_TYPE (lhs)) if (is_gimple_reg_type (TREE_TYPE (lhs))
&& TREE_CODE (lhs) != SSA_NAME) && TREE_CODE (lhs) != SSA_NAME)
force_gimple_rhs = true; force_gimple_rhs = true;
...@@ -2694,11 +2681,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi) ...@@ -2694,11 +2681,7 @@ sra_modify_assign (gimple *stmt, gimple_stmt_iterator *gsi)
if (gimple_has_volatile_ops (*stmt) if (gimple_has_volatile_ops (*stmt)
|| contains_view_convert_expr_p (rhs) || contains_view_convert_expr_p (rhs)
|| contains_view_convert_expr_p (lhs) || contains_view_convert_expr_p (lhs))
|| (access_has_children_p (racc)
&& !ref_expr_for_all_replacements_p (racc, lhs, racc->offset))
|| (access_has_children_p (lacc)
&& !ref_expr_for_all_replacements_p (lacc, rhs, lacc->offset)))
{ {
if (access_has_children_p (racc)) if (access_has_children_p (racc))
generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0, generate_subtree_copies (racc->first_child, racc->base, 0, 0, 0,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment