[PR 78687] Set SRA grp_write lazily
2017-05-02 Martin Jambor <mjambor@suse.cz> PR tree-optimization/78687 * tree-sra.c (access): New field parent. (process_subtree_disqualification): New function. (disqualify_candidate): Call it. (build_accesses_from_assign): Reset write flag if creating an assighnment link. (build_access_subtree): Fill in parent field and also prpagate down grp_write flag. (create_artificial_child_access): New parameter set_grp_write, set grp_write to its value. (propagate_subaccesses_across_link): Also propagate grp_write flag values. (propagate_all_subaccesses): Push the closest parent back to work queue if add_access_to_work_queue returned true. testsuite/ * g++.dg/tree-ssa/pr78687.C: New test. From-SVN: r247497
This commit is contained in:
parent
2bf54d93f1
commit
2bba75411e
@ -1,3 +1,20 @@
|
||||
2017-05-02 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
PR tree-optimization/78687
|
||||
* tree-sra.c (access): New field parent.
|
||||
(process_subtree_disqualification): New function.
|
||||
(disqualify_candidate): Call it.
|
||||
(build_accesses_from_assign): Reset write flag if creating an
|
||||
assighnment link.
|
||||
(build_access_subtree): Fill in parent field and also prpagate
|
||||
down grp_write flag.
|
||||
(create_artificial_child_access): New parameter set_grp_write, set
|
||||
grp_write to its value.
|
||||
(propagate_subaccesses_across_link): Also propagate grp_write flag
|
||||
values.
|
||||
(propagate_all_subaccesses): Push the closest parent back to work
|
||||
queue if add_access_to_work_queue returned true.
|
||||
|
||||
2017-05-02 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* common.opt (fstrict-overflow): Alias negative to fwrapv.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2017-05-02 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
PR tree-optimization/78687
|
||||
* g++.dg/tree-ssa/pr78687.C: New test.
|
||||
|
||||
2017-05-02 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* c-c++-common/Wlogical-op-1.c: Add -fwrapv to restore previous
|
||||
|
483
gcc/testsuite/g++.dg/tree-ssa/pr78687.C
Normal file
483
gcc/testsuite/g++.dg/tree-ssa/pr78687.C
Normal file
@ -0,0 +1,483 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -std=gnu++14 -fdump-tree-sra" } */
|
||||
|
||||
#include <utility>
|
||||
|
||||
#define EGGS_CXX11_CONSTEXPR constexpr
|
||||
#define EGGS_CXX11_STATIC_CONSTEXPR static constexpr
|
||||
#define EGGS_CXX14_CONSTEXPR constexpr
|
||||
#define EGGS_CXX11_NOEXCEPT noexcept
|
||||
|
||||
namespace eggs { namespace variants { namespace detail
|
||||
{
|
||||
struct empty
|
||||
{
|
||||
EGGS_CXX11_CONSTEXPR bool operator==(empty) const { return true; }
|
||||
EGGS_CXX11_CONSTEXPR bool operator<(empty) const { return false; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct identity
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
struct index
|
||||
{
|
||||
EGGS_CXX11_STATIC_CONSTEXPR std::size_t value = I;
|
||||
};
|
||||
|
||||
template <typename ...Ts>
|
||||
struct pack
|
||||
{
|
||||
using type = pack;
|
||||
EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = sizeof...(Ts);
|
||||
};
|
||||
|
||||
template <typename T, T ...Vs>
|
||||
struct pack_c
|
||||
{
|
||||
using type = pack_c;
|
||||
EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = sizeof...(Vs);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Is, bool Odd>
|
||||
struct _make_index_pack_twice;
|
||||
|
||||
template <std::size_t ...Is>
|
||||
struct _make_index_pack_twice<
|
||||
pack_c<std::size_t, Is...>
|
||||
, false
|
||||
> : pack_c<std::size_t, Is..., (sizeof...(Is) + Is)...>
|
||||
{};
|
||||
|
||||
template <std::size_t ...Is>
|
||||
struct _make_index_pack_twice<
|
||||
pack_c<std::size_t, Is...>
|
||||
, true
|
||||
> : pack_c<std::size_t, Is..., (sizeof...(Is) + Is)..., sizeof...(Is) * 2>
|
||||
{};
|
||||
|
||||
template <std::size_t N>
|
||||
struct _make_index_pack
|
||||
: _make_index_pack_twice<
|
||||
typename _make_index_pack<N / 2>::type
|
||||
, N % 2 != 0
|
||||
>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct _make_index_pack<1>
|
||||
: pack_c<std::size_t, 0>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct _make_index_pack<0>
|
||||
: pack_c<std::size_t>
|
||||
{};
|
||||
|
||||
template <std::size_t N>
|
||||
using make_index_pack = typename _make_index_pack<N>::type;
|
||||
|
||||
template <typename Ts>
|
||||
struct _index_pack;
|
||||
|
||||
template <typename ...Ts>
|
||||
struct _index_pack<pack<Ts...>>
|
||||
: _make_index_pack<sizeof...(Ts)>
|
||||
{};
|
||||
|
||||
template <typename Ts>
|
||||
using index_pack = typename _index_pack<Ts>::type;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Vs>
|
||||
struct all_of;
|
||||
|
||||
template <bool ...Vs>
|
||||
struct all_of<pack_c<bool, Vs...>>
|
||||
: std::integral_constant<
|
||||
bool
|
||||
, std::is_same<
|
||||
pack_c<bool, Vs...>
|
||||
, pack_c<bool, (Vs || true)...> // true...
|
||||
>::value
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename ...Ts>
|
||||
struct all_of<pack<Ts...>>
|
||||
: all_of<pack_c<bool, (Ts::value)...>>
|
||||
{};
|
||||
|
||||
template <typename ...Vs>
|
||||
struct any_of;
|
||||
|
||||
template <bool ...Vs>
|
||||
struct any_of<pack_c<bool, Vs...>>
|
||||
: std::integral_constant<
|
||||
bool
|
||||
, !all_of<pack_c<bool, !Vs...>>::value
|
||||
>
|
||||
{};
|
||||
|
||||
template <typename ...Ts>
|
||||
struct any_of<pack<Ts...>>
|
||||
: any_of<pack_c<bool, (Ts::value)...>>
|
||||
{};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <std::size_t I, typename T>
|
||||
struct _indexed {};
|
||||
|
||||
template <typename Ts, typename Is = index_pack<Ts>>
|
||||
struct _indexer;
|
||||
|
||||
template <typename ...Ts, std::size_t ...Is>
|
||||
struct _indexer<pack<Ts...>, pack_c<std::size_t, Is...>>
|
||||
: _indexed<Is, Ts>...
|
||||
{};
|
||||
|
||||
empty _at_index(...);
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
identity<T> _at_index(_indexed<I, T> const&);
|
||||
|
||||
template <std::size_t I, typename Ts>
|
||||
struct at_index
|
||||
: decltype(_at_index<I>(_indexer<Ts>{}))
|
||||
{};
|
||||
|
||||
empty _index_of(...);
|
||||
|
||||
template <typename T, std::size_t I>
|
||||
index<I> _index_of(_indexed<I, T> const&);
|
||||
|
||||
template <typename T, typename Ts>
|
||||
struct index_of
|
||||
: decltype(_index_of<T>(_indexer<Ts>{}))
|
||||
{};
|
||||
}}}
|
||||
|
||||
namespace eggs { namespace variants { namespace detail
|
||||
{
|
||||
template <typename Ts, bool IsTriviallyDestructible>
|
||||
struct _union;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <bool IsTriviallyDestructible>
|
||||
struct _union<pack<>, IsTriviallyDestructible>
|
||||
{};
|
||||
|
||||
template <typename T, typename ...Ts>
|
||||
struct _union<pack<T, Ts...>, true>
|
||||
{
|
||||
EGGS_CXX11_STATIC_CONSTEXPR std::size_t size = 1 + sizeof...(Ts);
|
||||
|
||||
template <typename ...Args>
|
||||
EGGS_CXX11_CONSTEXPR _union(index<0>, Args&&... args)
|
||||
: _head(std::forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
template <std::size_t I, typename ...Args>
|
||||
EGGS_CXX11_CONSTEXPR _union(index<I>, Args&&... args)
|
||||
: _tail(index<I - 1>{}, std::forward<Args>(args)...)
|
||||
{}
|
||||
|
||||
EGGS_CXX14_CONSTEXPR void* target() EGGS_CXX11_NOEXCEPT
|
||||
{
|
||||
return &_target;
|
||||
}
|
||||
|
||||
EGGS_CXX11_CONSTEXPR void const* target() const EGGS_CXX11_NOEXCEPT
|
||||
{
|
||||
return &_target;
|
||||
}
|
||||
|
||||
EGGS_CXX14_CONSTEXPR T& get(index<0>) EGGS_CXX11_NOEXCEPT
|
||||
{
|
||||
return this->_head;
|
||||
}
|
||||
|
||||
EGGS_CXX11_CONSTEXPR T const& get(index<0>) const EGGS_CXX11_NOEXCEPT
|
||||
{
|
||||
return this->_head;
|
||||
}
|
||||
|
||||
template <
|
||||
std::size_t I
|
||||
, typename U = typename at_index<I, pack<T, Ts...>>::type
|
||||
>
|
||||
EGGS_CXX14_CONSTEXPR U& get(index<I>) EGGS_CXX11_NOEXCEPT
|
||||
{
|
||||
return this->_tail.get(index<I - 1>{});
|
||||
}
|
||||
|
||||
template <
|
||||
std::size_t I
|
||||
, typename U = typename at_index<I, pack<T, Ts...>>::type
|
||||
>
|
||||
EGGS_CXX11_CONSTEXPR U const& get(index<I>) const EGGS_CXX11_NOEXCEPT
|
||||
{
|
||||
return this->_tail.get(index<I - 1>{});
|
||||
}
|
||||
|
||||
private:
|
||||
union
|
||||
{
|
||||
char _target;
|
||||
T _head;
|
||||
_union<pack<Ts...>, true> _tail;
|
||||
};
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename Ts, bool TriviallyCopyable, bool TriviallyDestructible>
|
||||
struct _storage;
|
||||
|
||||
template <typename ...Ts>
|
||||
struct _storage<pack<Ts...>, true, true>
|
||||
: _union<
|
||||
pack<Ts...>
|
||||
, all_of<pack<std::is_trivially_destructible<Ts>...>>::value
|
||||
>
|
||||
{
|
||||
using base_type = _union<
|
||||
pack<Ts...>
|
||||
, all_of<pack<std::is_trivially_destructible<Ts>...>>::value
|
||||
>;
|
||||
|
||||
EGGS_CXX11_CONSTEXPR _storage() EGGS_CXX11_NOEXCEPT
|
||||
: base_type{index<0>{}}
|
||||
, _which{0}
|
||||
{}
|
||||
|
||||
_storage(_storage const& rhs) = default;
|
||||
_storage(_storage&& rhs) = default;
|
||||
|
||||
template <std::size_t I, typename ...Args>
|
||||
EGGS_CXX11_CONSTEXPR _storage(index<I> which, Args&&... args)
|
||||
: base_type{which, std::forward<Args>(args)...}
|
||||
, _which{I}
|
||||
{}
|
||||
|
||||
_storage& operator=(_storage const& rhs) = default;
|
||||
_storage& operator=(_storage&& rhs) = default;
|
||||
|
||||
EGGS_CXX11_CONSTEXPR std::size_t which() const
|
||||
{
|
||||
return _which;
|
||||
}
|
||||
|
||||
using base_type::target;
|
||||
using base_type::get;
|
||||
|
||||
protected:
|
||||
std::size_t _which;
|
||||
};
|
||||
|
||||
template <typename ...Ts>
|
||||
using storage = _storage<
|
||||
pack<empty, Ts...>
|
||||
, all_of<pack<std::is_trivially_copyable<Ts>...>>::value
|
||||
, all_of<pack<std::is_trivially_destructible<Ts>...>>::value
|
||||
>;
|
||||
}}}
|
||||
|
||||
namespace eggs { namespace variants
|
||||
{
|
||||
template <typename ...Ts>
|
||||
class variant;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
namespace _best_match
|
||||
{
|
||||
template <typename Ts, std::size_t I = 0>
|
||||
struct overloads
|
||||
{};
|
||||
|
||||
template <typename T, typename ...Ts, std::size_t I>
|
||||
struct overloads<pack<T, Ts...>, I>
|
||||
: overloads<pack<Ts...>, I + 1>
|
||||
{
|
||||
using fun_ptr = index<I>(*)(T);
|
||||
operator fun_ptr();
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
auto _invoke(F&&, T&&)
|
||||
-> decltype(std::declval<F>()(std::declval<T>()));
|
||||
|
||||
struct _fallback {};
|
||||
|
||||
_fallback _invoke(...);
|
||||
|
||||
template <
|
||||
typename T, typename U
|
||||
, typename R = decltype(_best_match::_invoke(
|
||||
std::declval<T>(), std::declval<U>()))
|
||||
>
|
||||
struct result_of : R
|
||||
{};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct result_of<T, U, _fallback>
|
||||
{};
|
||||
}
|
||||
|
||||
template <typename U, typename ...Ts>
|
||||
struct index_of_best_match
|
||||
: _best_match::result_of<_best_match::overloads<Ts...>, U>
|
||||
{};
|
||||
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
class variant
|
||||
{
|
||||
|
||||
public:
|
||||
EGGS_CXX11_CONSTEXPR variant() EGGS_CXX11_NOEXCEPT = delete;
|
||||
|
||||
variant(variant const& rhs) = default;
|
||||
|
||||
variant(variant&& rhs) = default;
|
||||
|
||||
template <
|
||||
typename U
|
||||
, typename Enable = typename std::enable_if<!std::is_same<
|
||||
typename std::decay<U>::type, variant
|
||||
>::value>::type
|
||||
, std::size_t I = detail::index_of_best_match<
|
||||
U&&, detail::pack<Ts...>>::value
|
||||
, typename T = typename detail::at_index<
|
||||
I, detail::pack<Ts...>>::type
|
||||
>
|
||||
EGGS_CXX11_CONSTEXPR variant(U&& v)
|
||||
noexcept(
|
||||
std::is_nothrow_constructible<T, U&&>::value)
|
||||
: _storage{detail::index<I + 1>{}, std::forward<U>(v)}
|
||||
{}
|
||||
|
||||
~variant() = default;
|
||||
variant& operator=(variant const& rhs) = delete;
|
||||
|
||||
private:
|
||||
detail::storage<Ts...> _storage;
|
||||
};
|
||||
}}
|
||||
|
||||
template <class T, class Base>
|
||||
struct ref_proxy : Base
|
||||
{
|
||||
using Base::Base;
|
||||
|
||||
ref_proxy()
|
||||
: Base()
|
||||
{
|
||||
}
|
||||
|
||||
ref_proxy(Base ptr)
|
||||
: Base(std::move(ptr))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct inplace_ref
|
||||
{
|
||||
explicit inplace_ref(T inner)
|
||||
: inner_(inner)
|
||||
{
|
||||
}
|
||||
|
||||
T inner_;
|
||||
};
|
||||
|
||||
template <class ...Variants>
|
||||
struct variant_ref
|
||||
{
|
||||
variant_ref() = delete;
|
||||
|
||||
explicit variant_ref(eggs::variants::variant<Variants...> t)
|
||||
: inner_storage_(t)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
variant_ref(ref_proxy<Source, variant_ref> ptr)
|
||||
: inner_storage_(ptr.inner_storage_)
|
||||
{}
|
||||
|
||||
private:
|
||||
eggs::variants::variant<Variants...> inner_storage_;
|
||||
};
|
||||
|
||||
struct option_1
|
||||
{
|
||||
void *a, *b, *c, *d, *e;
|
||||
};
|
||||
|
||||
struct option_2
|
||||
{
|
||||
};
|
||||
|
||||
using option_ref = variant_ref<option_1, option_2>;
|
||||
|
||||
|
||||
struct qual_option
|
||||
{
|
||||
qual_option(ref_proxy<void, option_ref > type, int quals)
|
||||
: type_(type)
|
||||
, quals_(quals)
|
||||
{
|
||||
}
|
||||
|
||||
explicit qual_option(ref_proxy<void, option_ref > type)
|
||||
: qual_option(type, 0)
|
||||
{
|
||||
}
|
||||
|
||||
ref_proxy<void, option_ref > type_;
|
||||
int quals_;
|
||||
};
|
||||
|
||||
inline ref_proxy<option_2, option_ref > make_object_1()
|
||||
{
|
||||
return ref_proxy<option_2, option_ref >(option_2());
|
||||
}
|
||||
|
||||
inline ref_proxy<option_2, option_ref > make_object_2()
|
||||
{
|
||||
return make_object_1();
|
||||
}
|
||||
|
||||
inline inplace_ref<qual_option> make_object_3(ref_proxy<option_2, option_ref>&& a0)
|
||||
{
|
||||
return inplace_ref<qual_option>(qual_option(a0));
|
||||
}
|
||||
|
||||
inline ref_proxy<qual_option, inplace_ref<qual_option> > make_object_4(ref_proxy<option_2, option_ref>&& a0)
|
||||
{
|
||||
return make_object_3(std::move(a0));
|
||||
}
|
||||
|
||||
|
||||
ref_proxy<qual_option, inplace_ref<qual_option> > f() __attribute__((noinline));
|
||||
|
||||
ref_proxy<qual_option, inplace_ref<qual_option> > f()
|
||||
{
|
||||
return make_object_4(make_object_2());
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
for (;;)
|
||||
f();
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "Removing load:.*ptr;" "sra" } } */
|
@ -158,6 +158,10 @@ struct access
|
||||
the representative. */
|
||||
struct access *group_representative;
|
||||
|
||||
/* After access tree has been constructed, this points to the parent of the
|
||||
current access, if there is one. NULL for roots. */
|
||||
struct access *parent;
|
||||
|
||||
/* If this access has any children (in terms of the definition above), this
|
||||
points to the first one. */
|
||||
struct access *first_child;
|
||||
@ -690,6 +694,19 @@ static bool constant_decl_p (tree decl)
|
||||
return VAR_P (decl) && DECL_IN_CONSTANT_POOL (decl);
|
||||
}
|
||||
|
||||
|
||||
/* Mark LHS of assign links out of ACCESS and its children as written to. */
|
||||
|
||||
static void
|
||||
process_subtree_disqualification (struct access *access)
|
||||
{
|
||||
struct access *child;
|
||||
for (struct assign_link *link = access->first_link; link; link = link->next)
|
||||
link->lacc->grp_write = true;
|
||||
for (child = access->first_child; child; child = child->next_sibling)
|
||||
process_subtree_disqualification (child);
|
||||
}
|
||||
|
||||
/* Remove DECL from candidates for SRA and write REASON to the dump file if
|
||||
there is one. */
|
||||
static void
|
||||
@ -706,6 +723,13 @@ disqualify_candidate (tree decl, const char *reason)
|
||||
print_generic_expr (dump_file, decl, 0);
|
||||
fprintf (dump_file, " - %s\n", reason);
|
||||
}
|
||||
|
||||
struct access *access = get_first_repr_for_decl (decl);
|
||||
while (access)
|
||||
{
|
||||
process_subtree_disqualification (access);
|
||||
access = access->next_grp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true iff the type contains a field or an element which does not allow
|
||||
@ -1338,8 +1362,10 @@ build_accesses_from_assign (gimple *stmt)
|
||||
|
||||
link->lacc = lacc;
|
||||
link->racc = racc;
|
||||
|
||||
add_link_to_rhs (racc, link);
|
||||
/* Let's delay marking the areas as written until propagation of accesses
|
||||
across link. */
|
||||
lacc->write = false;
|
||||
}
|
||||
|
||||
return lacc || racc;
|
||||
@ -2252,6 +2278,8 @@ build_access_subtree (struct access **access)
|
||||
else
|
||||
last_child->next_sibling = *access;
|
||||
last_child = *access;
|
||||
(*access)->parent = root;
|
||||
(*access)->grp_write |= root->grp_write;
|
||||
|
||||
if (!build_access_subtree (access))
|
||||
return false;
|
||||
@ -2495,13 +2523,15 @@ child_would_conflict_in_lacc (struct access *lacc, HOST_WIDE_INT norm_offset,
|
||||
|
||||
/* Create a new child access of PARENT, with all properties just like MODEL
|
||||
except for its offset and with its grp_write false and grp_read true.
|
||||
Return the new access or NULL if it cannot be created. Note that this access
|
||||
is created long after all splicing and sorting, it's not located in any
|
||||
access vector and is automatically a representative of its group. */
|
||||
Return the new access or NULL if it cannot be created. Note that this
|
||||
access is created long after all splicing and sorting, it's not located in
|
||||
any access vector and is automatically a representative of its group. Set
|
||||
the gpr_write flag of the new accesss if SET_GRP_WRITE is true. */
|
||||
|
||||
static struct access *
|
||||
create_artificial_child_access (struct access *parent, struct access *model,
|
||||
HOST_WIDE_INT new_offset)
|
||||
HOST_WIDE_INT new_offset,
|
||||
bool set_grp_write)
|
||||
{
|
||||
struct access **child;
|
||||
tree expr = parent->base;
|
||||
@ -2523,7 +2553,7 @@ create_artificial_child_access (struct access *parent, struct access *model,
|
||||
access->offset = new_offset;
|
||||
access->size = model->size;
|
||||
access->type = model->type;
|
||||
access->grp_write = true;
|
||||
access->grp_write = set_grp_write;
|
||||
access->grp_read = false;
|
||||
access->reverse = model->reverse;
|
||||
|
||||
@ -2549,10 +2579,23 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
|
||||
HOST_WIDE_INT norm_delta = lacc->offset - racc->offset;
|
||||
bool ret = false;
|
||||
|
||||
/* IF the LHS is still not marked as being written to, we only need to do so
|
||||
if the RHS at this level actually was. */
|
||||
if (!lacc->grp_write &&
|
||||
(racc->grp_write || TREE_CODE (racc->base) == PARM_DECL))
|
||||
{
|
||||
lacc->grp_write = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (is_gimple_reg_type (lacc->type)
|
||||
|| lacc->grp_unscalarizable_region
|
||||
|| racc->grp_unscalarizable_region)
|
||||
return false;
|
||||
{
|
||||
ret |= !lacc->grp_write;
|
||||
lacc->grp_write = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_gimple_reg_type (racc->type))
|
||||
{
|
||||
@ -2572,7 +2615,7 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
|
||||
lacc->grp_no_warning = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (rchild = racc->first_child; rchild; rchild = rchild->next_sibling)
|
||||
@ -2581,23 +2624,37 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
|
||||
HOST_WIDE_INT norm_offset = rchild->offset + norm_delta;
|
||||
|
||||
if (rchild->grp_unscalarizable_region)
|
||||
continue;
|
||||
{
|
||||
lacc->grp_write = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child_would_conflict_in_lacc (lacc, norm_offset, rchild->size,
|
||||
&new_acc))
|
||||
{
|
||||
if (new_acc)
|
||||
{
|
||||
if (!new_acc->grp_write
|
||||
&& (lacc->grp_write || rchild->grp_write))
|
||||
{
|
||||
new_acc ->grp_write = true;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
rchild->grp_hint = 1;
|
||||
new_acc->grp_hint |= new_acc->grp_read;
|
||||
if (rchild->first_child)
|
||||
ret |= propagate_subaccesses_across_link (new_acc, rchild);
|
||||
}
|
||||
else
|
||||
lacc->grp_write = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
rchild->grp_hint = 1;
|
||||
new_acc = create_artificial_child_access (lacc, rchild, norm_offset);
|
||||
new_acc = create_artificial_child_access (lacc, rchild, norm_offset,
|
||||
lacc->grp_write
|
||||
|| rchild->grp_write);
|
||||
if (new_acc)
|
||||
{
|
||||
ret = true;
|
||||
@ -2628,9 +2685,17 @@ propagate_all_subaccesses (void)
|
||||
if (!bitmap_bit_p (candidate_bitmap, DECL_UID (lacc->base)))
|
||||
continue;
|
||||
lacc = lacc->group_representative;
|
||||
if (propagate_subaccesses_across_link (lacc, racc)
|
||||
&& lacc->first_link)
|
||||
add_access_to_work_queue (lacc);
|
||||
if (propagate_subaccesses_across_link (lacc, racc))
|
||||
do
|
||||
{
|
||||
if (lacc->first_link)
|
||||
{
|
||||
add_access_to_work_queue (lacc);
|
||||
break;
|
||||
}
|
||||
lacc = lacc->parent;
|
||||
}
|
||||
while (lacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user