Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 46 additions & 16 deletions src/ir/constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,19 @@ void LocalConstraint::flip() {
}

void BasicBlockConstraintMap::set(Index index, const Constraint& c) {
// We should not set values in unreachable code.
assert(!unreachable);
eraseStaleRefs(index);
map[index].set(c);
noteRefs(index, c);

// If the constraint refers to another local, add it there too.
if (std::holds_alternative<Index>(c.term)) {
approximateAndInternal(index, c, true);
}
// Clear the old state.
eraseStaleRefs(index);
map[index].setProvesNothing();
// Note that this last line puts us in a temporarily invalid state: we do not
// normally store a constraint of proves-nothing in the map. Doing it this
// way, until approximateAnd adds the constraint, is more efficient than
// erasing and re-adding.

// Apply the constraint.
approximateAnd(index, c);
}

void BasicBlockConstraintMap::setProvesNothing(Index index) {
Expand Down Expand Up @@ -319,7 +323,8 @@ void BasicBlockConstraintMap::approximateOr(

void BasicBlockConstraintMap::approximateAndInternal(Index index,
const Constraint& c,
bool flip) {
bool flip,
bool isCopy) {
Constraint actual = c;
if (flip) {
LocalConstraint flipped{index, c};
Expand All @@ -328,10 +333,26 @@ void BasicBlockConstraintMap::approximateAndInternal(Index index,
actual = flipped.constraint;
}

auto combined = get(index);
combined.approximateAnd(actual);
// Never add constraints to ourselves (x == x, etc., which can happen due to
// copying/flipping).
if (auto* other = std::get_if<Index>(&actual.term)) {
if (*other == index) {
return;
}
}

// Refer to the constraints for this index. If this is the first access of
// the local, then we insert a new item into the map, which has a default of
// proxesEverything, which we need to flip (provesEverything cannot otherwise
// be found in the map, as we never store it).
auto [iter, _] = map.insert({index, AndedConstraintSet::makeProvesNothing()});
auto& indexConstraints = iter->second;
// As in ::set(), this makes the map temporarily invalid until the
// approximateAnd, as we don't store proves-nothing in the map, normally.

indexConstraints.approximateAnd(actual);

if (combined.provesEverything()) {
if (indexConstraints.provesEverything()) {
// We just proved we are in unreachable code.
unreachable = true;
map.clear();
Expand All @@ -340,10 +361,7 @@ void BasicBlockConstraintMap::approximateAndInternal(Index index,

// We just added a constraint, so we can prove something (we may lose some
// information as this is an approximate AND, but we cannot lose it all).
assert(!combined.provesNothing());

// Otherwise, this is an interesting state; set it.
map[index] = std::move(combined);
assert(!indexConstraints.provesNothing());

// Add a ref of what we are adding. Note that the approximation above may end
// up not actually adding this, or adding only part of this, but it is safe to
Expand All @@ -353,7 +371,19 @@ void BasicBlockConstraintMap::approximateAndInternal(Index index,
// If this is not the flipped version, and it refers to a local, add the
// flipped one too.
if (!flip && std::holds_alternative<Index>(actual.term)) {
approximateAndInternal(index, actual, true);
approximateAndInternal(index, actual, true, isCopy);
}

// If this constraint is simply "== x", then we are equal to that other local
// x, and can copy its constraints (if we are not already such a copy).
if (!isCopy) {
if (auto* other = std::get_if<Index>(&actual.term)) {
if (actual.op == Abstract::Eq) {
for (auto& otherC : get(*other)) {
approximateAndInternal(index, otherC, false, true);
}
}
}
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/ir/constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,9 +287,12 @@ struct BasicBlockConstraintMap {
// Internal version, with a flag to flip the constraint. Whenever we apply
// e.g. x == y, we also apply y == x to y, to maintain the invariant described
// above. When flip is true, we flip the constraint and apply it to the other
// index (y == x, in this example).
void
approximateAndInternal(Index index, const Constraint& c, bool flip = false);
// index (y == x, in this example). When isCopy is true, we are a copied
// constraint from another local, and we do not need to add new copies of it.
void approximateAndInternal(Index index,
const Constraint& c,
bool flip = false,
bool isCopy = false);
};

std::ostream& operator<<(std::ostream& o, const Constraint& c);
Expand Down
5 changes: 5 additions & 0 deletions src/passes/ConstraintAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ struct Info {
// For each local index, we track the constraints we know about it. We only do
// so at the start of each block, which is enough for the analysis below.
BasicBlockConstraintMap startConstraints;

void dump(Function* func) {
std::cout << "Info{" << actions.size() << ", " << brancher << ", "
<< startConstraints << "}\n";
}
};

struct ConstraintAnalysis
Expand Down
Loading
Loading