summaryrefslogtreecommitdiff
path: root/src/passes/OptimizeInstructions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/OptimizeInstructions.cpp')
-rw-r--r--src/passes/OptimizeInstructions.cpp34
1 files changed, 24 insertions, 10 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index a546930c6..70df652b8 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -2018,6 +2018,22 @@ struct OptimizeInstructions
// the value, though.
if (ref->type.isNull()) {
// We can materialize the resulting null value directly.
+ //
+ // The type must be nullable for us to do that, which it normally
+ // would be, aside from the interesting corner case of
+ // uninhabitable types:
+ //
+ // (ref.cast func
+ // (block (result (ref nofunc))
+ // (unreachable)
+ // )
+ // )
+ //
+ // (ref nofunc) is a subtype of (ref func), so the cast might seem
+ // to be successful, but since the input is uninhabitable we won't
+ // even reach the cast. Such casts will be evaluated as
+ // Unreachable, so we'll not hit this assertion.
+ assert(curr->type.isNullable());
replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref),
builder.makeRefNull(nullType)));
return;
@@ -2030,8 +2046,10 @@ struct OptimizeInstructions
builder.makeSequence(builder.makeDrop(curr->ref),
builder.makeLocalGet(scratch, ref->type)));
return;
- } else if (result == GCTypeUtils::Failure) {
- // This cast cannot succeed, so it will trap.
+ } else if (result == GCTypeUtils::Failure ||
+ result == GCTypeUtils::Unreachable) {
+ // This cast cannot succeed, or it cannot even be reached, so we can
+ // trap.
// Make sure to emit a block with the same type as us; leave updating
// types for other passes.
replaceCurrent(builder.makeBlock(
@@ -2142,14 +2160,6 @@ struct OptimizeInstructions
Builder builder(*getModule());
- if (curr->ref->type.isNull()) {
- // The input is null, so we know whether this will succeed or fail.
- int32_t result = curr->castType.isNullable() ? 1 : 0;
- replaceCurrent(builder.makeBlock(
- {builder.makeDrop(curr->ref), builder.makeConst(int32_t(result))}));
- return;
- }
-
// Parallel to the code in visitRefCast
switch (GCTypeUtils::evaluateCastCheck(curr->ref->type, curr->castType)) {
case GCTypeUtils::Unknown:
@@ -2158,6 +2168,10 @@ struct OptimizeInstructions
replaceCurrent(builder.makeBlock(
{builder.makeDrop(curr->ref), builder.makeConst(int32_t(1))}));
break;
+ case GCTypeUtils::Unreachable:
+ replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref),
+ builder.makeUnreachable()));
+ break;
case GCTypeUtils::Failure:
replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref),
builder.makeConst(int32_t(0))));