summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/possible-contents.cpp92
-rw-r--r--src/ir/possible-contents.h5
-rw-r--r--test/gtest/possible-contents.cpp28
3 files changed, 89 insertions, 36 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index 3430bc872..916a39f2c 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -140,8 +140,21 @@ PossibleContents PossibleContents::combine(const PossibleContents& a,
return ConeType{lub, newDepth};
}
-void PossibleContents::intersectWithFullCone(const PossibleContents& other) {
- assert(other.isFullConeType());
+void PossibleContents::intersect(const PossibleContents& other) {
+ // This does not yet handle all possible content.
+ assert(other.isFullConeType() || other.isLiteral() || other.isNone());
+
+ if (*this == other) {
+ // Nothing changes.
+ return;
+ }
+
+ if (!haveIntersection(*this, other)) {
+ // There is no intersection at all.
+ // Note that this code path handles |this| or |other| being None.
+ value = None();
+ return;
+ }
if (isSubContents(other, *this)) {
// The intersection is just |other|.
@@ -150,16 +163,18 @@ void PossibleContents::intersectWithFullCone(const PossibleContents& other) {
return;
}
- if (!haveIntersection(*this, other)) {
- // There is no intersection at all.
- // Note that this code path handles |this| being None.
+ if (isSubContents(*this, other)) {
+ // The intersection is just |this|.
+ return;
+ }
+
+ if (isLiteral() || other.isLiteral()) {
+ // We've ruled out either being a subcontents of the other. A literal has
+ // no other intersection possibility.
value = None();
return;
}
- // There is an intersection here. Note that this implies |this| is a reference
- // type, as it has an intersection with |other| which is a full cone type
- // (which must be a reference type).
auto type = getType();
auto otherType = other.getType();
auto heapType = type.getHeapType();
@@ -290,13 +305,19 @@ bool PossibleContents::haveIntersection(const PossibleContents& a,
return true;
}
+ if (a == b) {
+ // The intersection is equal to them.
+ return true;
+ }
+
auto aType = a.getType();
auto bType = b.getType();
if (!aType.isRef() || !bType.isRef()) {
// At least one is not a reference. The only way they can intersect is if
- // the type is identical.
- return aType == bType;
+ // the type is identical, and they are not both literals (we've already
+ // ruled out them being identical earlier).
+ return aType == bType && (!a.isLiteral() || !b.isLiteral());
}
// From here on we focus on references.
@@ -350,15 +371,37 @@ bool PossibleContents::haveIntersection(const PossibleContents& a,
bool PossibleContents::isSubContents(const PossibleContents& a,
const PossibleContents& b) {
- // TODO: Everything else. For now we only call this when |a| or |b| is a full
- // cone type.
+ if (a == b) {
+ return true;
+ }
+
+ if (a.isNone()) {
+ return true;
+ }
+
+ if (b.isNone()) {
+ return false;
+ }
+
+ if (a.isMany()) {
+ return false;
+ }
+
+ if (b.isMany()) {
+ return true;
+ }
+
+ if (a.isLiteral()) {
+ // Note we already checked for |a == b| above. We need b to be a set that
+ // contains the literal a.
+ return !b.isLiteral() && Type::isSubType(a.getType(), b.getType());
+ }
+
+ if (b.isLiteral()) {
+ return false;
+ }
+
if (b.isFullConeType()) {
- if (a.isNone()) {
- return true;
- }
- if (a.isMany()) {
- return false;
- }
if (a.isNull()) {
return b.getType().isNullable();
}
@@ -366,12 +409,11 @@ bool PossibleContents::isSubContents(const PossibleContents& a,
}
if (a.isFullConeType()) {
- // We've already ruled out b being a full cone type before, so the only way
- // |a| can be contained in |b| is if |b| is everything.
- return b.isMany();
+ // We've already ruled out b being a full cone type before.
+ return false;
}
- WASM_UNREACHABLE("a or b must be a full cone");
+ WASM_UNREACHABLE("unhandled case of isSubContents");
}
namespace {
@@ -1932,7 +1974,7 @@ void Flower::filterExpressionContents(PossibleContents& contents,
// The maximal contents here are the declared type and all subtypes. Nothing
// else can pass through, so filter such things out.
auto maximalContents = PossibleContents::fullConeType(type);
- contents.intersectWithFullCone(maximalContents);
+ contents.intersect(maximalContents);
if (contents.isNone()) {
// Nothing was left here at all.
return;
@@ -1966,9 +2008,7 @@ void Flower::filterExpressionContents(PossibleContents& contents,
normalizeConeType(contents);
// There is a chance that the intersection is equal to the maximal contents,
- // which would mean nothing more can arrive here. (Note that we can't
- // normalize |maximalContents| before the intersection as
- // intersectWithFullCone assumes a full/infinite cone.)
+ // which would mean nothing more can arrive here.
normalizeConeType(maximalContents);
if (contents == maximalContents) {
diff --git a/src/ir/possible-contents.h b/src/ir/possible-contents.h
index b4326688e..018cf197c 100644
--- a/src/ir/possible-contents.h
+++ b/src/ir/possible-contents.h
@@ -176,9 +176,8 @@ public:
}
// Removes anything not in |other| from this object, so that it ends up with
- // only their intersection. Currently this only handles an intersection with a
- // full cone.
- void intersectWithFullCone(const PossibleContents& other);
+ // only their intersection.
+ void intersect(const PossibleContents& other);
bool isNone() const { return std::get_if<None>(&value); }
bool isLiteral() const { return std::get_if<Literal>(&value); }
diff --git a/test/gtest/possible-contents.cpp b/test/gtest/possible-contents.cpp
index 85a4e86fd..e10773550 100644
--- a/test/gtest/possible-contents.cpp
+++ b/test/gtest/possible-contents.cpp
@@ -325,7 +325,7 @@ TEST_F(PossibleContentsTest, TestIntersection) {
assertHaveIntersection(exactI32, exactI32);
assertHaveIntersection(i32Zero, i32Zero);
assertHaveIntersection(exactFuncSignatureType, exactFuncSignatureType);
- assertHaveIntersection(i32Zero, i32One); // TODO: this could be inferred false
+ assertLackIntersection(i32Zero, i32One);
// Exact types only differing by nullability can intersect (not on the null,
// but on something else).
@@ -426,12 +426,12 @@ TEST_F(PossibleContentsTest, TestIntersectWithCombinations) {
assertHaveIntersection(normalizedCone, item);
}
- // Test intersectWithFullCone() method, which is supported with a full
- // cone type. In that case we can test that the intersection of A with
- // A + B is simply A.
+ // Test intersect() method, which is supported with a full cone type.
+ // In that case we can test that the intersection of A with A + B is
+ // simply A.
if (combination.isFullConeType()) {
auto intersection = item;
- intersection.intersectWithFullCone(combination);
+ intersection.intersect(combination);
EXPECT_EQ(intersection, item);
#if BINARYEN_TEST_DEBUG
if (intersection != item) {
@@ -522,9 +522,8 @@ void assertIntersection(PossibleContents a,
PossibleContents b,
PossibleContents result) {
auto intersection = a;
- intersection.intersectWithFullCone(b);
+ intersection.intersect(b);
EXPECT_EQ(intersection, result);
-
EXPECT_EQ(PossibleContents::haveIntersection(a, b), !result.isNone());
}
@@ -810,6 +809,21 @@ TEST_F(PossibleContentsTest, TestStructCones) {
assertIntersection(
literalNullA, PossibleContents::fullConeType(funcref), none);
+ // Computing intersections is also supported with a Literal.
+ assertIntersection(i32Zero, i32Zero, i32Zero);
+ assertIntersection(i32One, i32Zero, none);
+ assertIntersection(i32Global1, i32Zero, i32Zero);
+ assertIntersection(funcGlobal, i32Zero, none);
+ assertIntersection(
+ PossibleContents::fullConeType(Type::i32), i32Zero, i32Zero);
+ assertIntersection(PossibleContents::fullConeType(Type::f64), i32Zero, none);
+
+ // Computing intersections is also supported with empty contents.
+ assertIntersection(none, none, none);
+ assertIntersection(literalNullA, none, none);
+ assertIntersection(funcGlobal, none, none);
+ assertIntersection(PossibleContents::fullConeType(signature), none, none);
+
// Subcontents. This API only supports the case where one of the inputs is a
// full cone type.
// First, compare exact types to such a cone.