[vm/compiler] Ensure aliasing between *[C|S] and X[C'|S'] for S < S'.

Previously when computing aliasing during load propagation we only
propagated aliasing from X[C'|S'] to *[C''|S''] for S' < S''.

The code incorrectly assumed that this propagation is symmetric (which
it is not) and expected that *[C|S] would be cross aliased with X[C'|S']
when *[C|S] is visited.

Now we split symmetric and non-symmetric parts of the aliasing

computation: X[C'|S'] propagates aliasing to X[C''|S''] for S' < S'' -
which is symmetric. Separately if X is an aliased instance we propagate
aliasing from X[C'|S'] to *[C|S] for all sizes S.
Change-Id: Iccd4c73a18ffd3f60fd179df43a6b117e0844b64
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101281
Commit-Queue: Vyacheslav Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Vyacheslav Egorov
2019-05-03 14:18:28 +00:00
committed by commit-bot@chromium.org
parent fb7137ba6f
commit 836c04f3d2
@@ -310,6 +310,23 @@ class Place : public ValueObject {
RoundByteOffset(to, index_constant_));
}
// Given alias X[ByteOffs|S], smaller element size S' and index from 0 to
// S/S' - 1 return alias X[ByteOffs + S'*index|S'] - this is the byte offset
// of a smaller typed array element which is contained within this typed
// array element.
// For example X[8|kInt32] contains inside X[8|kInt16] (index is 0) and
// X[10|kInt16] (index is 1).
Place ToSmallerElement(ElementSize to, intptr_t index) const {
ASSERT(kind() == kConstantIndexed);
ASSERT(element_size() != kNoSize);
ASSERT(element_size() > to);
ASSERT(index >= 0);
ASSERT(index <
ElementSizeMultiplier(element_size()) / ElementSizeMultiplier(to));
return Place(ElementSizeBits::update(to, flags_), instance_,
ByteOffsetToSmallerElement(to, index, index_constant_));
}
intptr_t id() const { return id_; }
Kind kind() const { return KindBits::decode(flags_); }
@@ -548,6 +565,12 @@ class Place : public ValueObject {
return offset & ~(ElementSizeMultiplier(size) - 1);
}
static intptr_t ByteOffsetToSmallerElement(ElementSize size,
intptr_t index,
intptr_t base_offset) {
return base_offset + index * ElementSizeMultiplier(size);
}
class KindBits : public BitField<uword, Kind, 0, 3> {};
class RepresentationBits
: public BitField<uword, Representation, KindBits::kNextBit, 11> {};
@@ -890,13 +913,42 @@ class AliasedSet : public ZoneAllocated {
// X[C|S] aliases with X[RoundDown(C, S')|S'] and likewise
// *[C|S] aliases with *[RoundDown(C, S')|S'].
const Place larger_alias =
alias->ToLargerElement(static_cast<Place::ElementSize>(i));
CrossAlias(alias, larger_alias);
if (has_aliased_instance) {
// If X is an aliased instance then X[C|S] aliases
// with *[RoundDown(C, S')|S'].
CrossAlias(alias, larger_alias.CopyWithoutInstance());
CrossAlias(alias, alias->ToLargerElement(
static_cast<Place::ElementSize>(i)));
}
if (has_aliased_instance) {
// If X is an aliased instance then X[C|S] aliases *[C'|S'] for all
// related combinations of C' and S'.
// Caveat: this propagation is not symmetric (we would not know
// to propagate aliasing from *[C'|S'] to X[C|S] when visiting
// *[C'|S']) and thus we need to handle both element sizes smaller
// and larger than S.
const Place no_instance_alias = alias->CopyWithoutInstance();
for (intptr_t i = Place::kInt8; i <= Place::kLargestElementSize;
i++) {
// Skip element sizes that a guaranteed to have no
// representatives.
if (!typed_data_access_sizes_.Contains(alias->element_size())) {
continue;
}
const auto other_size = static_cast<Place::ElementSize>(i);
if (other_size > alias->element_size()) {
// X[C|S] aliases all larger elements which cover it:
// *[RoundDown(C, S')|S'] for S' > S.
CrossAlias(alias,
no_instance_alias.ToLargerElement(other_size));
} else if (other_size < alias->element_size()) {
// X[C|S] aliases all sub-elements of smaller size:
// *[C+j*S'|S'] for S' < S and j from 0 to S/S' - 1.
const auto num_smaller_elements =
1 << (alias->element_size() - other_size);
for (intptr_t j = 0; j < num_smaller_elements; j++) {
CrossAlias(alias,
no_instance_alias.ToSmallerElement(other_size, j));
}
}
}
}
}