summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/CoalesceLocals.cpp25
1 files changed, 22 insertions, 3 deletions
diff --git a/src/passes/CoalesceLocals.cpp b/src/passes/CoalesceLocals.cpp
index 558be07ff..062449e95 100644
--- a/src/passes/CoalesceLocals.cpp
+++ b/src/passes/CoalesceLocals.cpp
@@ -523,7 +523,10 @@ void CoalesceLocals::applyIndices(std::vector<Index>& indices,
}
}
if (auto* subSet = set->value->dynCast<LocalSet>()) {
- if (subSet->index == set->index) {
+ // Only do so if not only the index matches but also the type. If the
+ // inner type is more refined, leave that for other passes.
+ if (subSet->index == set->index &&
+ subSet->value->type == subSet->type) {
set->value = subSet->value;
continue;
}
@@ -550,12 +553,28 @@ void CoalesceLocals::applyIndices(std::vector<Index>& indices,
if (!action.effective) {
// value may have no side effects, further optimizations can eliminate
// it
- *action.origin = set->value;
+ auto* value = set->value;
if (!set->isTee()) {
// we need to drop it
Drop* drop = ExpressionManipulator::convert<LocalSet, Drop>(set);
- drop->value = *action.origin;
+ drop->value = value;
*action.origin = drop;
+ } else {
+ // This is a tee, and so, as earlier in this function, we must be
+ // careful of subtyping. Above we simply avoided the problem by
+ // leaving it for other passes, but we do want to remove ineffective
+ // stores - nothing else does that as well as this pass. Instead,
+ // create a block to cast back to the original type, which avoids
+ // changing types here, and leave it to other passes to refine types
+ // and remove the block.
+ auto originalType = (*action.origin)->type;
+ if (originalType != set->value->type) {
+ (*action.origin) =
+ Builder(*getModule()).makeBlock({set->value}, originalType);
+ } else {
+ // No special handling, just use the value.
+ *action.origin = set->value;
+ }
}
continue;
}