Skip to content

Use GLB in PossibleContents::intersect #7550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2025
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
35 changes: 6 additions & 29 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,47 +182,26 @@ void PossibleContents::intersect(const PossibleContents& other) {
auto heapType = type.getHeapType();
auto otherHeapType = otherType.getHeapType();

// If both inputs are nullable then the intersection is nullable as well.
auto nullability =
type.isNullable() && otherType.isNullable() ? Nullable : NonNullable;
// Intersect the types.
auto newType = Type::getGreatestLowerBound(type, otherType);

auto setNoneOrNull = [&]() {
if (nullability == Nullable) {
if (newType.isNullable()) {
value = Literal::makeNull(heapType);
} else {
value = None();
}
};

// If the heap types are not compatible then they are in separate hierarchies
// and there is no intersection, aside from possibly a null of the bottom
// type.
auto isSubType = HeapType::isSubType(heapType, otherHeapType);
auto otherIsSubType = HeapType::isSubType(otherHeapType, heapType);
if (!isSubType && !otherIsSubType) {
if (heapType.getBottom() == otherHeapType.getBottom()) {
setNoneOrNull();
} else {
value = None();
}
if (newType == Type::unreachable || newType.isNull()) {
setNoneOrNull();
return;
}

// The heap types are compatible, so intersect the cones.
auto depthFromRoot = heapType.getDepth();
auto otherDepthFromRoot = otherHeapType.getDepth();

// To compute the new cone, find the new heap type for it, and to compute its
// depth, consider the adjustments to the existing depths that stem from the
// choice of new heap type.
HeapType newHeapType;

if (depthFromRoot < otherDepthFromRoot) {
newHeapType = otherHeapType;
} else {
newHeapType = heapType;
}

// Note the global's information, if we started as a global. In that case, the
// code below will refine our type but we can remain a global, which we will
// accomplish by restoring our global status at the end.
Expand All @@ -231,8 +210,6 @@ void PossibleContents::intersect(const PossibleContents& other) {
globalName = getGlobal();
}

auto newType = Type(newHeapType, nullability);

// By assumption |other| has full depth. Consider the other cone in |this|.
if (hasFullCone()) {
// Both are full cones, so the result is as well.
Expand All @@ -252,7 +229,7 @@ void PossibleContents::intersect(const PossibleContents& other) {
// E.g. if |this| is a cone of depth 10, and |otherHeapType| is an immediate
// subtype of |this|, then the new cone must be of depth 9.
auto newDepth = getCone().depth;
if (newHeapType == otherHeapType) {
if (newType.getHeapType() == otherHeapType) {
assert(depthFromRoot <= otherDepthFromRoot);
auto reduction = otherDepthFromRoot - depthFromRoot;
if (reduction > newDepth) {
Expand Down
36 changes: 36 additions & 0 deletions test/lit/passes/gufa-cast-all-exact.wast
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,39 @@
)
)
)

(module
;; CHECK: (type $foo (sub (struct (field i32))))
;; NO_CD: (type $foo (sub (struct (field i32))))
(type $foo (sub (struct (field i32))))

;; CHECK: (import "" "" (global $null-exact (ref null (exact $foo))))
;; NO_CD: (import "" "" (global $null-exact (ref null (exact $foo))))
(import "" "" (global $null-exact (ref null (exact $foo))))

;; CHECK: (func $as-non-null (type $1) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (global.get $null-exact)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; NO_CD: (func $as-non-null (type $1) (result i32)
;; NO_CD-NEXT: (drop
;; NO_CD-NEXT: (ref.as_non_null
;; NO_CD-NEXT: (global.get $null-exact)
;; NO_CD-NEXT: )
;; NO_CD-NEXT: )
;; NO_CD-NEXT: (unreachable)
;; NO_CD-NEXT: )
(func $as-non-null (result i32)
(struct.get $foo 0
;; Regression test for an assertion failure when the intersection here
;; dropped exactness as well as nullness.
(ref.as_non_null
(global.get $null-exact)
)
)
)
)
9 changes: 7 additions & 2 deletions test/lit/passes/gufa-refs.wast
Original file line number Diff line number Diff line change
Expand Up @@ -6069,8 +6069,13 @@
;; CHECK: (func $test-set-bottom (type $2)
;; CHECK-NEXT: (block ;; (replaces unreachable ArraySet we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast nullref
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.cast nullref
;; CHECK-NEXT: (global.get $global)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change? Previously the ref.cast emitted a nullable bottom type, and it should still keep doing so IIUC... the description mentions a change to non-nullable ones, but that's not the case here, so it must be something else?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I was referring to with non-nullable references because the possible contents in $global is a non-null value, even though its static type is nullable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right, the actual value is non-nullable, thanks!

;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
Expand Down
Loading