diff options
Diffstat (limited to 'src/ir/possible-contents.cpp')
-rw-r--r-- | src/ir/possible-contents.cpp | 59 |
1 files changed, 49 insertions, 10 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 83d55e6f9..4755c9904 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -86,7 +86,7 @@ void PossibleContents::combine(const PossibleContents& other) { // combination here is if they have the same type (since we've already ruled // out the case of them being equal). If they have the same type then // neither is a reference and we can emit an exact type (since subtyping is - // not relevant for non-references. + // not relevant for non-references). if (type == otherType) { value = ExactType(type); } else { @@ -132,6 +132,48 @@ void PossibleContents::combine(const PossibleContents& other) { value = Many(); } +bool PossibleContents::haveIntersection(const PossibleContents& a, + const PossibleContents& b) { + if (a.isNone() || b.isNone()) { + // One is the empty set, so nothing can intersect here. + return false; + } + + if (a.isMany() || b.isMany()) { + // One is the set of all things, so definitely something can intersect since + // we've ruled out an empty set for both. + return true; + } + + auto aType = a.getType(); + auto bType = b.getType(); + + if (aType.isNullable() && bType.isNullable()) { + // Null is possible on both sides. Assume that an intersection can exist, + // but we could be more precise here and check if the types belong to + // different hierarchies, in which case the nulls would differ TODO. For + // now we only use this API from the RefEq logic, so this is fully precise. + return true; + } + + if (a.hasExactType() && b.hasExactType() && a.getType() != b.getType()) { + // The values must be different since their types are different. + return false; + } + + if (!Type::isSubType(aType, bType) && !Type::isSubType(bType, aType)) { + // No type can appear in both a and b, so the types differ, so the values + // differ. + return false; + } + + // TODO: we can also optimize things like different Literals, but existing + // passes do such things already so it is low priority. + + // It appears they can intersect. + return true; +} + namespace { // We are going to do a very large flow operation, potentially, as we create @@ -378,9 +420,6 @@ struct InfoCollector PossibleContents::literal(Literal(curr->func, curr->type.getHeapType()))); } void visitRefEq(RefEq* curr) { - // TODO: optimize when possible (e.g. when both sides must contain the same - // global, or if we infer exact types that are different then the - // result must be 0) addRoot(curr); } void visitTableGet(TableGet* curr) { @@ -416,12 +455,9 @@ struct InfoCollector } void visitRefCast(RefCast* curr) { - // We will handle this in a special way later during the flow, as ref.cast - // only allows valid values to flow through. addChildParentLink(curr->ref, curr); } void visitRefTest(RefTest* curr) { - // We will handle this similarly to RefCast. addChildParentLink(curr->ref, curr); } void visitBrOn(BrOn* curr) { @@ -1114,7 +1150,11 @@ private: // values to flow through it. void flowRefCast(const PossibleContents& contents, RefCast* cast); - // The possible contents may allow us to infer an outcome, like with RefCast. + // The possible contents may allow us to infer an outcome in various + // instructions. If the expression has a single child, that is what is + // updated by the new |contents| (which we pass in to avoid doing an extra + // lookup); if there is more than one child, then to keep the code simple we + // expect the function to look up the children's effects manually. void flowRefTest(const PossibleContents& contents, RefTest* test); // We will need subtypes during the flow, so compute them once ahead of time. @@ -1734,6 +1774,7 @@ void Flower::flowRefCast(const PossibleContents& contents, RefCast* cast) { } void Flower::flowRefTest(const PossibleContents& contents, RefTest* test) { + // TODO move to gufa pass; this must happen at the end PossibleContents filtered; if (contents.isMany()) { // Just pass the Many through. @@ -1792,8 +1833,6 @@ void Flower::dump(Location location) { std::cout << " sigresultloc " << '\n'; } else if (auto* loc = std::get_if<NullLocation>(&location)) { std::cout << " Nullloc " << loc->type << '\n'; - } else if (auto* loc = std::get_if<UniqueLocation>(&location)) { - std::cout << " Specialloc " << loc->index << '\n'; } else { std::cout << " (other)\n"; } |