Skip to content
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
12 changes: 6 additions & 6 deletions src/analysis/lattices/conetype.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct ConeType {

Element get(Type type) const noexcept {
assert(!type.isTuple());
if (!type.isRef() || type.isExact() || type.isNull() ||
if (!type.isRef() || type.isExact() || type.isBottomRef() ||
type.getHeapType().isMaybeShared(HeapType::i31)) {
return Element{type, 0};
}
Expand All @@ -69,10 +69,10 @@ struct ConeType {
return changed;
}
Index joineeToLub = 0, joinerToLub = 0;
if (!joinee.isBottom() && !joinee.type.isNull()) {
if (!joinee.isBottom() && !joinee.type.isBottomRef()) {
joineeToLub = depthToSuper(joinee, lub);
}
if (!joiner.isBottom() && !joiner.type.isNull()) {
if (!joiner.isBottom() && !joiner.type.isBottomRef()) {
joinerToLub = depthToSuper(joiner, lub);
}
Index newDepth =
Expand Down Expand Up @@ -102,7 +102,7 @@ struct ConeType {
}
Index newDepth;
auto glb = Type::getGreatestLowerBound(meetee.type, meeter.type);
if (glb == Type::unreachable || glb.isNull()) {
if (glb == Type::unreachable || glb.isBottomRef()) {
newDepth = 0;
} else if (HeapType::isSubType(meetee.type.getHeapType(),
meeter.type.getHeapType())) {
Expand Down Expand Up @@ -146,14 +146,14 @@ struct ConeType {
return a.depth < b.depth ? analysis::LESS : analysis::GREATER;
}
if (Type::isSubType(a.type, b.type)) {
if (a.type.isNull()) {
if (a.type.isBottomRef()) {
return analysis::LESS;
}
Index diff = depthToSuper(a, b.type);
return a.depth + diff <= b.depth ? analysis::LESS : analysis::NO_RELATION;
}
if (Type::isSubType(b.type, a.type)) {
if (b.type.isNull()) {
if (b.type.isBottomRef()) {
return analysis::GREATER;
}
Index diff = depthToSuper(b, a.type);
Expand Down
4 changes: 2 additions & 2 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ class EffectAnalyzer {
return true;
}
assert(type.isRef());
if (type.isNull()) {
if (type.isBottomRef()) {
parent.trap = true;
return true;
}
Expand Down Expand Up @@ -1175,7 +1175,7 @@ class EffectAnalyzer {
}

void visitArrayStore(ArrayStore* curr) {
if (curr->ref->type.isNull()) {
if (curr->ref->type.isBottomRef()) {
parent.trap = true;
return;
}
Expand Down
10 changes: 3 additions & 7 deletions src/ir/gc-type-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
namespace wasm::GCTypeUtils {

inline bool isUninhabitable(Type type) {
return type.isNonNullableRef() && type.getHeapType().isBottom();
return type.isNonNullableRef() && type.isBottomRef();
}

// Helper code to evaluate a reference at compile time and check if it is of a
Expand Down Expand Up @@ -82,9 +82,7 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) {
return Unreachable;
}

auto refHeapType = refType.getHeapType();

if (castType.isNonNullableRef() && refHeapType.isBottom()) {
if (castType.isNonNullableRef() && refType.isBottomRef()) {
// Non-null references to bottom types do not exist, so there's no value
// that could make the cast succeed.
//
Expand All @@ -103,8 +101,6 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) {
return Failure;
}

auto castHeapType = castType.getHeapType();

// Check whether a value of type `a` is known to also have type `b`, assuming
// it is non-null.
auto isHeapSubtype = [](Type a, Type b) {
Expand Down Expand Up @@ -138,7 +134,7 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) {
auto castIsHeapSubType = isHeapSubtype(castType, refType);
bool heapTypesCompatible = refIsHeapSubType || castIsHeapSubType;

if (!heapTypesCompatible || castHeapType.isBottom()) {
if (!heapTypesCompatible || castType.isBottomRef()) {
// If the heap types are incompatible or if it is impossible to have a
// non-null reference to the target heap type, then the only way the cast
// can succeed is if it allows nulls and the input is null.
Expand Down
4 changes: 2 additions & 2 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ void PossibleContents::intersect(const PossibleContents& other) {
}
};

if (newType == Type::unreachable || newType.isNull()) {
if (newType == Type::unreachable || newType.isBottomRef()) {
setNoneOrNull();
return;
}
Expand Down Expand Up @@ -3182,7 +3182,7 @@ void Flower::filterPackedDataReads(PossibleContents& contents,
}

// If there is no struct or array to read, no value will ever be returned.
if (ref->type.isNull()) {
if (ref->type.isBottomRef()) {
contents = PossibleContents::none();
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/ir/properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ inline bool hasUnwritableTypeImmediate(Expression* curr) {
#define DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(id, field) \
if (curr->cast<id>()->field) { \
auto type = curr->cast<id>()->field->type; \
if (type == Type::unreachable || type.isNull()) { \
if (type == Type::unreachable || type.isBottomRef()) { \
return true; \
} \
}
Expand Down
10 changes: 5 additions & 5 deletions src/ir/struct-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ struct StructScanner : public WalkerPass<PostWalker<SubType>> {

void visitStructSet(StructSet* curr) {
auto type = curr->ref->type;
if (type == Type::unreachable || type.isNull()) {
if (type == Type::unreachable || type.isBottomRef()) {
return;
}

Expand All @@ -237,7 +237,7 @@ struct StructScanner : public WalkerPass<PostWalker<SubType>> {

void visitStructGet(StructGet* curr) {
auto type = curr->ref->type;
if (type == Type::unreachable || type.isNull()) {
if (type == Type::unreachable || type.isBottomRef()) {
return;
}

Expand All @@ -250,7 +250,7 @@ struct StructScanner : public WalkerPass<PostWalker<SubType>> {

void visitStructWait(StructWait* curr) {
auto type = curr->ref->type;
if (type == Type::unreachable || type.isNull()) {
if (type == Type::unreachable || type.isBottomRef()) {
return;
}

Expand All @@ -263,7 +263,7 @@ struct StructScanner : public WalkerPass<PostWalker<SubType>> {

void visitStructRMW(StructRMW* curr) {
auto type = curr->ref->type;
if (type == Type::unreachable || type.isNull()) {
if (type == Type::unreachable || type.isBottomRef()) {
return;
}

Expand All @@ -286,7 +286,7 @@ struct StructScanner : public WalkerPass<PostWalker<SubType>> {

void visitStructCmpxchg(StructCmpxchg* curr) {
auto type = curr->ref->type;
if (type == Type::unreachable || type.isNull()) {
if (type == Type::unreachable || type.isBottomRef()) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Literal {
bool isContinuation() const { return type.isContinuation(); }
bool isString() const { return type.isString(); }

bool isNull() const { return type.isNull(); }
bool isNull() const { return type.isBottomRef(); }

bool isZero() const {
switch (type.getBasic()) {
Expand Down
3 changes: 2 additions & 1 deletion src/passes/DeadArgumentElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <unordered_map>
#include <unordered_set>

#include "ir/gc-type-utils.h"
#include "ir/lubs.h"
#include "ir/return-utils.h"
#include "ir/type-updating.h"
Expand Down Expand Up @@ -551,7 +552,7 @@ struct DAE : public Pass {
// Do this for more complicated uninhabitable types such as non-nullable
// references to structs with non-nullable reference cycles.
bool wasReturnUninhabitable =
func->getResults().isNull() && func->getResults().isNonNullableRef();
GCTypeUtils::isUninhabitable(func->getResults());
func->setResults(Type::none);
// Remove the drops on the calls. Note that we must do this before updating
// returns in ReturnUpdater, as there may be recursive calls of this
Expand Down
11 changes: 6 additions & 5 deletions src/passes/OptimizeInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1768,7 +1768,8 @@ struct OptimizeInstructions
// function and the null does not actually flow out. We can only optimize
// here if a null definitely flows out (as only that would cause a trap).
auto flowsOutNull = [&](Expression* child) {
return child->type.isNull() && !effects(child).transfersControlFlow();
return child->type.isBottomRef() &&
!effects(child).transfersControlFlow();
};

if (auto* iff = ref->dynCast<If>()) {
Expand Down Expand Up @@ -1859,7 +1860,7 @@ struct OptimizeInstructions

auto fallthrough = getFallthrough(ref);

if (fallthrough->type.isNull()) {
if (fallthrough->type.isBottomRef()) {
replaceCurrent(
getDroppedChildrenAndAppend(curr, builder.makeUnreachable()));
return true;
Expand Down Expand Up @@ -2497,7 +2498,7 @@ struct OptimizeInstructions
// null, because then we never get around to comparing the
// descriptors. We still need to preserve the trap on null
// descriptors, though.
if (refType.isNull()) {
if (refType.isBottomRef()) {
assert(curr->type.isNullableRef());
if (curr->desc->type.isNullableRef()) {
curr->desc = builder.makeRefAs(RefAsNonNull, curr->desc);
Expand Down Expand Up @@ -2554,7 +2555,7 @@ struct OptimizeInstructions
// because the intermediate expressions might have had side effects or
// we need to check exactness. We can replace the cast with a drop
// followed by a direct return of the value, though.
if (ref->type.isNull()) {
if (ref->type.isBottomRef()) {
// We can materialize the resulting null value directly.
//
// The type must be nullable for us to do that, which it normally
Expand Down Expand Up @@ -2615,7 +2616,7 @@ struct OptimizeInstructions
// In this case, the cast succeeds because the value must be null, so we
// can fall through to handle that case.
assert(Type::isSubType(refType, ref->type));
assert(refType.getHeapType().isBottom());
assert(refType.isBottomRef());
}
[[fallthrough]];
case GCTypeUtils::SuccessOnlyIfNull: {
Expand Down
4 changes: 2 additions & 2 deletions src/passes/Precompute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class PrecomputingExpressionRunner
return Flow(NONCONSTANT_FLOW);
}
Flow visitStructGet(StructGet* curr) {
if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) {
if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) {
return Flow(NONCONSTANT_FLOW);
}
switch (curr->order) {
Expand Down Expand Up @@ -193,7 +193,7 @@ class PrecomputingExpressionRunner
Flow visitArrayRMW(ArrayRMW* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitArrayCmpxchg(ArrayCmpxchg* curr) { return Flow(NONCONSTANT_FLOW); }
Flow visitArrayGet(ArrayGet* curr) {
if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) {
if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) {
return Flow(NONCONSTANT_FLOW);
}
switch (curr->order) {
Expand Down
4 changes: 2 additions & 2 deletions src/passes/RemoveUnusedBrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {

switch (curr->op) {
case BrOnNull:
if (refType.isNull()) {
if (refType.isBottomRef()) {
// The branch will definitely be taken.
replaceCurrent(builder.makeSequence(
builder.makeDrop(curr->ref), builder.makeBreak(curr->name)));
Expand All @@ -937,7 +937,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
}
return;
case BrOnNonNull:
if (refType.isNull()) {
if (refType.isBottomRef()) {
// Definitely not taken.
replaceCurrent(builder.makeDrop(curr->ref));
worked = true;
Expand Down
2 changes: 1 addition & 1 deletion src/passes/RemoveUnusedModuleElements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ struct Noter : public PostWalker<Noter, UnifiedExpressionVisitor<Noter>> {
}

void visitStructGet(StructGet* curr) {
if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) {
if (curr->ref->type == Type::unreachable || curr->ref->type.isBottomRef()) {
return;
}
auto type = curr->ref->type.getHeapType();
Expand Down
7 changes: 4 additions & 3 deletions src/passes/TypeRefining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ struct TypeRefining : public Pass {
auto& infos = finalInfos[{type, Inexact}];
for (Index i = 0; i < fields.size(); i++) {
auto lub = infos[i].getLUB();
if (lub.isRef() && !lub.isCastable() && !lub.isNull()) {
if (lub.isRef() && !lub.isCastable() && !lub.isBottomRef()) {
infos[i] = LUBFinder(fields[i].type);
}
}
Expand Down Expand Up @@ -413,13 +413,14 @@ struct TypeRefining : public Pass {
}

Type newFieldType;
if (!curr->ref->type.isNull()) {
if (!curr->ref->type.isBottomRef()) {
auto oldType = curr->ref->type.getHeapType();
newFieldType =
parent.finalInfos[{oldType, Inexact}][curr->index].getLUB();
}

if (curr->ref->type.isNull() || newFieldType == Type::unreachable ||
if (curr->ref->type.isBottomRef() ||
newFieldType == Type::unreachable ||
!Type::isSubType(newFieldType, curr->type)) {
// This get will trap, or cannot be reached: either the ref is null,
// or the field is never written any contents, or the contents we see
Expand Down
8 changes: 5 additions & 3 deletions src/tools/fuzzing/heap-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ void Inhabitator::markBottomRefsNullable() {
auto children = type.getTypeChildren();
for (size_t i = 0; i < children.size(); ++i) {
auto child = children[i];
if (child.isNonNullableRef() && child.getHeapType().isBottom()) {
if (child.isNonNullableRef() && child.isBottomRef()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

We can simplify this check by using the helper function GCTypeUtils::isUninhabitable(child) here as well, which makes the code more expressive.

Suggested change
if (child.isNonNullableRef() && child.isBottomRef()) {
if (GCTypeUtils::isUninhabitable(child)) {

markNullable({type, i});
}
}
Expand Down Expand Up @@ -1400,9 +1400,11 @@ bool isUninhabitable(HeapType type,
bool isUninhabitable(Type type,
std::unordered_set<HeapType>& visited,
std::unordered_set<HeapType>& visiting) {
if (GCTypeUtils::isUninhabitable(type)) {
return true;
}
if (type.isNonNullableRef()) {
if (type.getHeapType().isBottom() ||
type.getHeapType().isMaybeShared(HeapType::ext)) {
if (type.getHeapType().isMaybeShared(HeapType::ext)) {
return true;
}
return isUninhabitable(type.getHeapType(), visited, visiting);
Expand Down
4 changes: 1 addition & 3 deletions src/wasm-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,7 @@ class Type {
bool isFunction() const { return isRef() && getHeapType().isFunction(); }
bool isSignature() const { return isRef() && getHeapType().isSignature(); }
bool isData() const { return isRef() && getHeapType().isData(); }

// Whether this type is only inhabited by null values.
bool isNull() const { return isRef() && getHeapType().isBottom(); }
bool isBottomRef() const { return isRef() && getHeapType().isBottom(); }
bool isStruct() const { return isRef() && getHeapType().isStruct(); }
bool isArray() const { return isRef() && getHeapType().isArray(); }
bool isExn() const { return isRef() && getHeapType().isExn(); }
Expand Down
7 changes: 3 additions & 4 deletions src/wasm/literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Literal::Literal(Type type) : type(type) {
}
}

if (type.isNull()) {
if (type.isBottomRef()) {
assert(type.isNullableRef() && !type.isExact());
new (&gcData) std::shared_ptr<GCData>();
return;
Expand Down Expand Up @@ -503,8 +503,7 @@ bool Literal::operator==(const Literal& other) const {
break;
}
} else if (type.isRef()) {
assert(type.isRef());
if (type.isNull()) {
if (type.isBottomRef()) {
return true;
}
if (type.isFunction()) {
Expand Down Expand Up @@ -567,7 +566,7 @@ bool Literal::operator<(const Literal& other) const {
}

assert(type.isRef());
if (type.isNull()) {
if (type.isBottomRef()) {
// All nulls are equal, and hence not <
return false;
}
Expand Down
Loading
Loading