summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/ConstantFieldPropagation.cpp21
1 files changed, 20 insertions, 1 deletions
diff --git a/src/passes/ConstantFieldPropagation.cpp b/src/passes/ConstantFieldPropagation.cpp
index 26cc8316b..a3dd6aa6f 100644
--- a/src/passes/ConstantFieldPropagation.cpp
+++ b/src/passes/ConstantFieldPropagation.cpp
@@ -179,7 +179,26 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> {
auto* value = info.makeExpression(*getModule());
auto field = GCTypeUtils::getField(type, curr->index);
assert(field);
- return Bits::makePackedFieldGet(value, *field, curr->signed_, *getModule());
+ // Apply packing, if needed.
+ value =
+ Bits::makePackedFieldGet(value, *field, curr->signed_, *getModule());
+ // Check if the value makes sense. The analysis below flows values around
+ // without considering where they are placed, that is, when we see a parent
+ // type can contain a value in a field then we assume a child may as well
+ // (which in general it can, e.g., using a reference to the parent, we can
+ // write that value to it, but the reference might actually point to a
+ // child instance). If we tracked the types of fields then we might avoid
+ // flowing values into places they cannot reside, like when a child field is
+ // a subtype, and so we could ignore things not refined enough for it (GUFA
+ // does a better job at this). For here, just check we do not break
+ // validation, and if we do, then we've inferred the only possible value is
+ // an impossible one, making the code unreachable.
+ if (!Type::isSubType(value->type, field->type)) {
+ Builder builder(*getModule());
+ value = builder.makeSequence(builder.makeDrop(value),
+ builder.makeUnreachable());
+ }
+ return value;
}
void optimizeUsingRefTest(StructGet* curr) {