summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-01-09 16:23:57 -0600
committerGitHub <noreply@github.com>2023-01-09 14:23:57 -0800
commit67abc2a1b9adcdf080387a29e0c92b6f5a31057a (patch)
treed8e8304e9ecdd700b56b949bb5132b26e09362f4
parente3d9b82d9f8910063373e2952582de545659d448 (diff)
downloadbinaryen-67abc2a1b9adcdf080387a29e0c92b6f5a31057a.tar.gz
binaryen-67abc2a1b9adcdf080387a29e0c92b6f5a31057a.tar.bz2
binaryen-67abc2a1b9adcdf080387a29e0c92b6f5a31057a.zip
Replace `RefIs` with `RefIsNull` (#5401)
* Replace `RefIs` with `RefIsNull` The other `ref.is*` instructions are deprecated and expressible in terms of `ref.test`. Update binary and text parsing to parse those instructions as `RefTest` expressions. Also update the printing and emitting of `RefTest` expressions to emit the legacy instructions for now to minimize test changes and make this a mostly non-functional change. Since `ref.is_null` is the only `RefIs` instruction left, remove the `RefIsOp` field and rename the expression class to `RefIsNull`. The few test changes are due to the fact that `ref.is*` instructions are now subject to `ref.test` validation, and in particular it is no longer valid to perform a `ref.is_func` on a value outside of the `func` type hierarchy.
-rw-r--r--CHANGELOG.md2
-rwxr-xr-xscripts/gen-s-parser.py8
-rw-r--r--src/binaryen-c.cpp37
-rw-r--r--src/binaryen-c.h24
-rw-r--r--src/gen-s-parser.inc16
-rw-r--r--src/ir/ReFinalize.cpp2
-rw-r--r--src/ir/boolean.h4
-rw-r--r--src/ir/cost.h2
-rw-r--r--src/ir/effects.h2
-rw-r--r--src/ir/gc-type-utils.h18
-rw-r--r--src/ir/possible-contents.cpp2
-rw-r--r--src/js/binaryen.js-post.js34
-rw-r--r--src/passes/Inlining.cpp2
-rw-r--r--src/passes/OptimizeInstructions.cpp81
-rw-r--r--src/passes/Print.cpp36
-rw-r--r--src/tools/fuzzing/fuzzing.cpp3
-rw-r--r--src/wasm-binary.h3
-rw-r--r--src/wasm-builder.h5
-rw-r--r--src/wasm-delegations-fields.def9
-rw-r--r--src/wasm-delegations.def2
-rw-r--r--src/wasm-interpreter.h17
-rw-r--r--src/wasm-s-parser.h5
-rw-r--r--src/wasm.h16
-rw-r--r--src/wasm/wasm-binary.cpp24
-rw-r--r--src/wasm/wasm-s-parser.cpp23
-rw-r--r--src/wasm/wasm-stack.cpp36
-rw-r--r--src/wasm/wasm-validator.cpp13
-rw-r--r--src/wasm/wasm.cpp2
-rw-r--r--src/wasm/wat-parser.cpp21
-rw-r--r--src/wasm2js.h2
-rw-r--r--test/binaryen.js/expressions.js53
-rw-r--r--test/binaryen.js/expressions.js.txt2
-rw-r--r--test/binaryen.js/kitchen-sink.js2
-rw-r--r--test/binaryen.js/kitchen-sink.js.txt2
-rw-r--r--test/example/c-api-kitchen-sink.c13
-rw-r--r--test/example/c-api-kitchen-sink.txt15
-rw-r--r--test/heap-types.wast1
-rw-r--r--test/heap-types.wast.from-wast6
-rw-r--r--test/heap-types.wast.fromBinary6
-rw-r--r--test/heap-types.wast.fromBinary.noDebugInfo6
-rw-r--r--test/lit/cast-to-basic.wast2
-rw-r--r--test/lit/passes/inlining_splitting.wast6
-rw-r--r--test/lit/passes/optimize-instructions-gc-tnh.wast31
-rw-r--r--test/lit/passes/optimize-instructions-gc.wast127
-rw-r--r--test/lit/wat-kitchen-sink.wast37
-rw-r--r--test/passes/translate-to-fuzz_all-features_metrics_noprint.txt2
46 files changed, 209 insertions, 553 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 466e98e77..43407c611 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,8 @@ Current Trunk
- The isorecursive WasmGC type system (i.e. --hybrid) is now the default to
match the spec and the old default equirecursive (i.e. --structural) system
has been removed.
+- `ref.is_func`, `ref.is_data`, and `ref.is_i31` have been removed from the C
+ and JS APIs and `RefIs` has been replaced with `RefIsNull`.
v111
----
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py
index 46b62711a..232429fe0 100755
--- a/scripts/gen-s-parser.py
+++ b/scripts/gen-s-parser.py
@@ -539,7 +539,7 @@ instructions = [
# reference types instructions
("ref.null", "makeRefNull(s)"),
- ("ref.is_null", "makeRefIs(s, RefIsNull)"),
+ ("ref.is_null", "makeRefIsNull(s)"),
("ref.func", "makeRefFunc(s)"),
("ref.eq", "makeRefEq(s)"),
# table instructions
@@ -602,9 +602,9 @@ instructions = [
("array.set", "makeArraySet(s)"),
("array.len", "makeArrayLen(s)"),
("array.copy", "makeArrayCopy(s)"),
- ("ref.is_func", "makeRefIs(s, RefIsFunc)"),
- ("ref.is_data", "makeRefIs(s, RefIsData)"),
- ("ref.is_i31", "makeRefIs(s, RefIsI31)"),
+ ("ref.is_func", "makeRefTest(s, Type(HeapType::func, NonNullable))"),
+ ("ref.is_data", "makeRefTest(s, Type(HeapType::data, NonNullable))"),
+ ("ref.is_i31", "makeRefTest(s, Type(HeapType::i31, NonNullable))"),
("ref.as_non_null", "makeRefAs(s, RefAsNonNull)"),
("ref.as_func", "makeRefAs(s, RefAsFunc)"),
("ref.as_data", "makeRefAs(s, RefAsData)"),
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp
index 7ff827aac..416c8d45b 100644
--- a/src/binaryen-c.cpp
+++ b/src/binaryen-c.cpp
@@ -1008,10 +1008,6 @@ BinaryenOp BinaryenPromoteLowVecF32x4ToVecF64x2(void) {
return PromoteLowVecF32x4ToVecF64x2;
}
BinaryenOp BinaryenSwizzleVecI8x16(void) { return SwizzleVecI8x16; }
-BinaryenOp BinaryenRefIsNull(void) { return RefIsNull; }
-BinaryenOp BinaryenRefIsFunc(void) { return RefIsFunc; }
-BinaryenOp BinaryenRefIsData(void) { return RefIsData; }
-BinaryenOp BinaryenRefIsI31(void) { return RefIsI31; }
BinaryenOp BinaryenRefAsNonNull(void) { return RefAsNonNull; }
BinaryenOp BinaryenRefAsFunc(void) { return RefAsFunc; }
BinaryenOp BinaryenRefAsData(void) { return RefAsData; }
@@ -1598,11 +1594,10 @@ BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
Builder(*(Module*)module).makeRefNull(type_.getHeapType()));
}
-BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module,
- BinaryenOp op,
- BinaryenExpressionRef value) {
+BinaryenExpressionRef BinaryenRefIsNull(BinaryenModuleRef module,
+ BinaryenExpressionRef value) {
return static_cast<Expression*>(
- Builder(*(Module*)module).makeRefIs(RefIsOp(op), (Expression*)value));
+ Builder(*(Module*)module).makeRefIsNull((Expression*)value));
}
BinaryenExpressionRef BinaryenRefAs(BinaryenModuleRef module,
@@ -3579,28 +3574,18 @@ void BinaryenMemoryFillSetSize(BinaryenExpressionRef expr,
assert(sizeExpr);
static_cast<MemoryFill*>(expression)->size = (Expression*)sizeExpr;
}
-// RefIs
-BinaryenOp BinaryenRefIsGetOp(BinaryenExpressionRef expr) {
- auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
- return static_cast<RefIs*>(expression)->op;
-}
-void BinaryenRefIsSetOp(BinaryenExpressionRef expr, BinaryenOp op) {
+// RefIsNull
+BinaryenExpressionRef BinaryenRefIsNullGetValue(BinaryenExpressionRef expr) {
auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
- static_cast<RefIs*>(expression)->op = RefIsOp(op);
+ assert(expression->is<RefIsNull>());
+ return static_cast<RefIsNull*>(expression)->value;
}
-BinaryenExpressionRef BinaryenRefIsGetValue(BinaryenExpressionRef expr) {
- auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
- return static_cast<RefIs*>(expression)->value;
-}
-void BinaryenRefIsSetValue(BinaryenExpressionRef expr,
- BinaryenExpressionRef valueExpr) {
+void BinaryenRefIsNullSetValue(BinaryenExpressionRef expr,
+ BinaryenExpressionRef valueExpr) {
auto* expression = (Expression*)expr;
- assert(expression->is<RefIs>());
+ assert(expression->is<RefIsNull>());
assert(valueExpr);
- static_cast<RefIs*>(expression)->value = (Expression*)valueExpr;
+ static_cast<RefIsNull*>(expression)->value = (Expression*)valueExpr;
}
// RefAs
BinaryenOp BinaryenRefAsGetOp(BinaryenExpressionRef expr) {
diff --git a/src/binaryen-c.h b/src/binaryen-c.h
index 171d1248d..2c861a141 100644
--- a/src/binaryen-c.h
+++ b/src/binaryen-c.h
@@ -670,10 +670,6 @@ BINARYEN_API BinaryenOp BinaryenTruncSatZeroUVecF64x2ToVecI32x4(void);
BINARYEN_API BinaryenOp BinaryenDemoteZeroVecF64x2ToVecF32x4(void);
BINARYEN_API BinaryenOp BinaryenPromoteLowVecF32x4ToVecF64x2(void);
BINARYEN_API BinaryenOp BinaryenSwizzleVecI8x16(void);
-BINARYEN_API BinaryenOp BinaryenRefIsNull(void);
-BINARYEN_API BinaryenOp BinaryenRefIsFunc(void);
-BINARYEN_API BinaryenOp BinaryenRefIsData(void);
-BINARYEN_API BinaryenOp BinaryenRefIsI31(void);
BINARYEN_API BinaryenOp BinaryenRefAsNonNull(void);
BINARYEN_API BinaryenOp BinaryenRefAsFunc(void);
BINARYEN_API BinaryenOp BinaryenRefAsData(void);
@@ -967,9 +963,8 @@ BinaryenMemoryFill(BinaryenModuleRef module,
const char* memoryName);
BINARYEN_API BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module,
BinaryenType type);
-BINARYEN_API BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module,
- BinaryenOp op,
- BinaryenExpressionRef value);
+BINARYEN_API BinaryenExpressionRef
+BinaryenRefIsNull(BinaryenModuleRef module, BinaryenExpressionRef value);
BINARYEN_API BinaryenExpressionRef BinaryenRefAs(BinaryenModuleRef module,
BinaryenOp op,
BinaryenExpressionRef value);
@@ -2092,18 +2087,13 @@ BinaryenMemoryFillGetSize(BinaryenExpressionRef expr);
BINARYEN_API void BinaryenMemoryFillSetSize(BinaryenExpressionRef expr,
BinaryenExpressionRef sizeExpr);
-// RefIs
+// RefIsNull
-// Gets the operation performed by a `ref.is_*` expression.
-BINARYEN_API BinaryenOp BinaryenRefIsGetOp(BinaryenExpressionRef expr);
-// Sets the operation performed by a `ref.is_*` expression.
-BINARYEN_API void BinaryenRefIsSetOp(BinaryenExpressionRef expr, BinaryenOp op);
-// Gets the value expression tested by a `ref.is_*` expression.
BINARYEN_API BinaryenExpressionRef
-BinaryenRefIsGetValue(BinaryenExpressionRef expr);
-// Sets the value expression tested by a `ref.is_*` expression.
-BINARYEN_API void BinaryenRefIsSetValue(BinaryenExpressionRef expr,
- BinaryenExpressionRef valueExpr);
+BinaryenRefIsNullGetValue(BinaryenExpressionRef expr);
+// Sets the value expression tested by a `ref.is_null` expression.
+BINARYEN_API void BinaryenRefIsNullSetValue(BinaryenExpressionRef expr,
+ BinaryenExpressionRef valueExpr);
// RefAs
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index acae3af50..70644827c 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -3050,16 +3050,16 @@ switch (buf[0]) {
case 'i': {
switch (buf[7]) {
case 'd':
- if (op == "ref.is_data"sv) { return makeRefIs(s, RefIsData); }
+ if (op == "ref.is_data"sv) { return makeRefTest(s, Type(HeapType::data, NonNullable)); }
goto parse_error;
case 'f':
- if (op == "ref.is_func"sv) { return makeRefIs(s, RefIsFunc); }
+ if (op == "ref.is_func"sv) { return makeRefTest(s, Type(HeapType::func, NonNullable)); }
goto parse_error;
case 'i':
- if (op == "ref.is_i31"sv) { return makeRefIs(s, RefIsI31); }
+ if (op == "ref.is_i31"sv) { return makeRefTest(s, Type(HeapType::i31, NonNullable)); }
goto parse_error;
case 'n':
- if (op == "ref.is_null"sv) { return makeRefIs(s, RefIsNull); }
+ if (op == "ref.is_null"sv) { return makeRefIsNull(s); }
goto parse_error;
default: goto parse_error;
}
@@ -8689,28 +8689,28 @@ switch (buf[0]) {
switch (buf[7]) {
case 'd':
if (op == "ref.is_data"sv) {
- auto ret = makeRefIs(ctx, pos, RefIsData);
+ auto ret = makeRefTest(ctx, pos, Type(HeapType::data, NonNullable));
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case 'f':
if (op == "ref.is_func"sv) {
- auto ret = makeRefIs(ctx, pos, RefIsFunc);
+ auto ret = makeRefTest(ctx, pos, Type(HeapType::func, NonNullable));
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case 'i':
if (op == "ref.is_i31"sv) {
- auto ret = makeRefIs(ctx, pos, RefIsI31);
+ auto ret = makeRefTest(ctx, pos, Type(HeapType::i31, NonNullable));
CHECK_ERR(ret);
return *ret;
}
goto parse_error;
case 'n':
if (op == "ref.is_null"sv) {
- auto ret = makeRefIs(ctx, pos, RefIsNull);
+ auto ret = makeRefIsNull(ctx, pos);
CHECK_ERR(ret);
return *ret;
}
diff --git a/src/ir/ReFinalize.cpp b/src/ir/ReFinalize.cpp
index 5ae6a67ce..a5651c6b6 100644
--- a/src/ir/ReFinalize.cpp
+++ b/src/ir/ReFinalize.cpp
@@ -128,7 +128,7 @@ void ReFinalize::visitReturn(Return* curr) { curr->finalize(); }
void ReFinalize::visitMemorySize(MemorySize* curr) { curr->finalize(); }
void ReFinalize::visitMemoryGrow(MemoryGrow* curr) { curr->finalize(); }
void ReFinalize::visitRefNull(RefNull* curr) { curr->finalize(); }
-void ReFinalize::visitRefIs(RefIs* curr) { curr->finalize(); }
+void ReFinalize::visitRefIsNull(RefIsNull* curr) { curr->finalize(); }
void ReFinalize::visitRefFunc(RefFunc* curr) {
// TODO: should we look up the function and update the type from there? This
// could handle a change to the function's type, but is also not really what
diff --git a/src/ir/boolean.h b/src/ir/boolean.h
index 58601c2ce..68dfb8b32 100644
--- a/src/ir/boolean.h
+++ b/src/ir/boolean.h
@@ -26,8 +26,8 @@ inline bool emitsBoolean(Expression* curr) {
return unary->isRelational();
} else if (auto* binary = curr->dynCast<Binary>()) {
return binary->isRelational();
- } else if (curr->is<RefIs>() || curr->is<RefEq>() || curr->is<RefTest>() ||
- curr->is<StringEq>()) {
+ } else if (curr->is<RefIsNull>() || curr->is<RefEq>() ||
+ curr->is<RefTest>() || curr->is<StringEq>()) {
return true;
}
return false;
diff --git a/src/ir/cost.h b/src/ir/cost.h
index 59b738b1b..11c179d40 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -561,7 +561,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 1 + visit(curr->left) + visit(curr->right);
}
CostType visitRefNull(RefNull* curr) { return 1; }
- CostType visitRefIs(RefIs* curr) { return 1 + visit(curr->value); }
+ CostType visitRefIsNull(RefIsNull* curr) { return 1 + visit(curr->value); }
CostType visitRefFunc(RefFunc* curr) { return 1; }
CostType visitRefEq(RefEq* curr) {
return 1 + visit(curr->left) + visit(curr->right);
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 70e9192c0..4ea577f7a 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -648,7 +648,7 @@ private:
parent.isAtomic = true;
}
void visitRefNull(RefNull* curr) {}
- void visitRefIs(RefIs* curr) {}
+ void visitRefIsNull(RefIsNull* curr) {}
void visitRefFunc(RefFunc* curr) {}
void visitRefEq(RefEq* curr) {}
void visitTableGet(TableGet* curr) {
diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h
index 1646e47c3..5f1b4807c 100644
--- a/src/ir/gc-type-utils.h
+++ b/src/ir/gc-type-utils.h
@@ -75,24 +75,6 @@ inline EvaluationResult evaluateKindCheck(Expression* curr) {
WASM_UNREACHABLE("unhandled BrOn");
}
child = br->ref;
- } else if (auto* is = curr->dynCast<RefIs>()) {
- switch (is->op) {
- // We don't check nullability here.
- case RefIsNull:
- return Unknown;
- case RefIsFunc:
- expected = Func;
- break;
- case RefIsData:
- expected = Data;
- break;
- case RefIsI31:
- expected = I31;
- break;
- default:
- WASM_UNREACHABLE("unhandled RefIs");
- }
- child = is->value;
} else if (auto* as = curr->dynCast<RefAs>()) {
switch (as->op) {
// We don't check nullability here.
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp
index 52b05057f..cf30cd917 100644
--- a/src/ir/possible-contents.cpp
+++ b/src/ir/possible-contents.cpp
@@ -587,7 +587,7 @@ struct InfoCollector
curr,
PossibleContents::literal(Literal::makeNull(curr->type.getHeapType())));
}
- void visitRefIs(RefIs* curr) {
+ void visitRefIsNull(RefIsNull* curr) {
// TODO: Optimize when possible. For example, if we can infer an exact type
// here which allows us to know the result then we should do so. This
// is unlike the case in visitUnary, above: the information that lets
diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js
index d4395359e..2a08c5e5a 100644
--- a/src/js/binaryen.js-post.js
+++ b/src/js/binaryen.js-post.js
@@ -92,7 +92,7 @@ function initializeConstants() {
'MemoryCopy',
'MemoryFill',
'RefNull',
- 'RefIs',
+ 'RefIsNull',
'RefFunc',
'RefEq',
'TableGet',
@@ -549,10 +549,6 @@ function initializeConstants() {
'DemoteZeroVecF64x2ToVecF32x4',
'PromoteLowVecF32x4ToVecF64x2',
'SwizzleVecI8x16',
- 'RefIsNull',
- 'RefIsFunc',
- 'RefIsData',
- 'RefIsI31',
'RefAsNonNull',
'RefAsFunc',
'RefAsData',
@@ -2344,16 +2340,7 @@ function wrapModule(module, self = {}) {
return Module['_BinaryenRefNull'](module, type);
},
'is_null'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsNull'], value);
- },
- 'is_func'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsFunc'], value);
- },
- 'is_data'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsData'], value);
- },
- 'is_i31'(value) {
- return Module['_BinaryenRefIs'](module, Module['RefIsI31'], value);
+ return Module['_BinaryenRefIsNull'](module, value);
},
'as_non_null'(value) {
return Module['_BinaryenRefAs'](module, Module['RefAsNonNull'], value);
@@ -3203,12 +3190,11 @@ Module['getExpressionInfo'] = function(expr) {
'id': id,
'type': type
};
- case Module['RefIsId']:
+ case Module['RefIsNullId']:
return {
'id': id,
'type': type,
- 'op': Module['_BinaryenRefIsGetOp'](expr),
- 'value': Module['_BinaryenRefIsGetValue'](expr)
+ 'value': Module['_BinaryenRefIsNullGetValue'](expr)
};
case Module['RefAsId']:
return {
@@ -4622,18 +4608,12 @@ Module['MemoryFill'] = makeExpressionWrapper({
}
});
-Module['RefIs'] = makeExpressionWrapper({
- 'getOp'(expr) {
- return Module['_BinaryenRefIsGetOp'](expr);
- },
- 'setOp'(expr, op) {
- Module['_BinaryenRefIsSetOp'](expr, op);
- },
+Module['RefIsNull'] = makeExpressionWrapper({
'getValue'(expr) {
- return Module['_BinaryenRefIsGetValue'](expr);
+ return Module['_BinaryenRefIsNullGetValue'](expr);
},
'setValue'(expr, valueExpr) {
- Module['_BinaryenRefIsSetValue'](expr, valueExpr);
+ Module['_BinaryenRefIsNullSetValue'](expr, valueExpr);
}
});
diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp
index 41083567c..4475db7b0 100644
--- a/src/passes/Inlining.cpp
+++ b/src/passes/Inlining.cpp
@@ -834,7 +834,7 @@ private:
if (auto* unary = curr->dynCast<Unary>()) {
return isSimple(unary->value);
}
- if (auto* is = curr->dynCast<RefIs>()) {
+ if (auto* is = curr->dynCast<RefIsNull>()) {
return isSimple(is->value);
}
return false;
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp
index 7902eaebd..36f5fbc25 100644
--- a/src/passes/OptimizeInstructions.cpp
+++ b/src/passes/OptimizeInstructions.cpp
@@ -1705,7 +1705,7 @@ struct OptimizeInstructions
// RefEq of a value to Null can be replaced with RefIsNull.
if (curr->right->is<RefNull>()) {
- replaceCurrent(Builder(*getModule()).makeRefIs(RefIsNull, curr->left));
+ replaceCurrent(Builder(*getModule()).makeRefIsNull(curr->left));
}
}
@@ -2154,78 +2154,27 @@ struct OptimizeInstructions
}
}
- void visitRefIs(RefIs* curr) {
+ void visitRefIsNull(RefIsNull* curr) {
if (curr->type == Type::unreachable) {
return;
}
- // Optimizating RefIs is not that obvious, since even if we know the result
- // evaluates to 0 or 1 then the replacement may not actually save code size,
- // since RefIsNull is a single byte (the others are 2), while adding a Const
- // of 0 would be two bytes. Other factors are that we can remove the input
- // and the added drop on it if it has no side effects, and that replacing
- // with a constant may allow further optimizations later. For now, replace
- // with a constant, but this warrants more investigation. TODO
+ // Optimizing RefIsNull is not that obvious, since even if we know the
+ // result evaluates to 0 or 1 then the replacement may not actually save
+ // code size, since RefIsNull is a single byte while adding a Const of 0
+ // would be two bytes. Other factors are that we can remove the input and
+ // the added drop on it if it has no side effects, and that replacing with a
+ // constant may allow further optimizations later. For now, replace with a
+ // constant, but this warrants more investigation. TODO
Builder builder(*getModule());
-
- auto nonNull = !curr->value->type.isNullable();
-
- if (curr->op == RefIsNull) {
- if (nonNull) {
- replaceCurrent(builder.makeSequence(
- builder.makeDrop(curr->value),
- builder.makeConst(Literal::makeZero(Type::i32))));
- } else {
- // See the comment on the other call to this lower down. Because of that
- // other code path we run this optimization at the end (though in this
- // code path it would be fine either way).
- skipCast(curr->value);
- }
- return;
- }
-
- // Check if the type is the kind we are checking for.
- auto result = GCTypeUtils::evaluateKindCheck(curr);
-
- if (result != GCTypeUtils::Unknown) {
- // We know the kind. Now we must also take into account nullability.
- if (nonNull) {
- // We know the entire result.
- replaceCurrent(
- builder.makeSequence(builder.makeDrop(curr->value),
- builder.makeConst(Literal::makeFromInt32(
- result == GCTypeUtils::Success, Type::i32))));
- } else {
- // The value may be null. Leave only a check for that.
- curr->op = RefIsNull;
- if (result == GCTypeUtils::Success) {
- // The input is of the right kind. If it is not null then the result
- // is 1, and otherwise it is 0, so we need to flip the result of
- // RefIsNull.
- // Note that even after adding an eqz here we do not regress code size
- // as RefIsNull is a single byte while the others are two. So we keep
- // code size identical. However, in theory this may be more work, if
- // a VM considers ref.is_X to be as fast as ref.is_null, and if eqz is
- // not free, so this is worth more investigation. TODO
- replaceCurrent(builder.makeUnary(EqZInt32, curr));
- } else {
- // The input is of the wrong kind. In this case if it is null we
- // return zero because of that, and if it is not then we return zero
- // because of the kind, so the result is always the same.
- assert(result == GCTypeUtils::Failure);
- replaceCurrent(builder.makeSequence(
- builder.makeDrop(curr->value),
- builder.makeConst(Literal::makeZero(Type::i32))));
- }
- }
+ if (curr->value->type.isNonNullable()) {
+ replaceCurrent(
+ builder.makeSequence(builder.makeDrop(curr->value),
+ builder.makeConst(Literal::makeZero(Type::i32))));
+ } else {
+ skipCast(curr->value);
}
-
- // What the reference points to does not depend on the type, so casts
- // may be removable. Do this right before returning because removing a
- // cast may remove info that we could have used to optimize, see
- // "notes on removing casts".
- skipCast(curr->value);
}
void visitRefAs(RefAs* curr) {
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 988b1d251..12c185e69 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -2000,24 +2000,7 @@ struct PrintExpressionContents
printMedium(o, "ref.null ");
printHeapType(o, curr->type.getHeapType(), wasm);
}
- void visitRefIs(RefIs* curr) {
- switch (curr->op) {
- case RefIsNull:
- printMedium(o, "ref.is_null");
- break;
- case RefIsFunc:
- printMedium(o, "ref.is_func");
- break;
- case RefIsData:
- printMedium(o, "ref.is_data");
- break;
- case RefIsI31:
- printMedium(o, "ref.is_i31");
- break;
- default:
- WASM_UNREACHABLE("unimplemented ref.is_*");
- }
- }
+ void visitRefIsNull(RefIsNull* curr) { printMedium(o, "ref.is_null"); }
void visitRefFunc(RefFunc* curr) {
printMedium(o, "ref.func ");
printName(curr->func, o);
@@ -2109,6 +2092,23 @@ struct PrintExpressionContents
printHeapType(o, curr->target->type.getHeapType(), wasm);
}
void visitRefTest(RefTest* curr) {
+ // TODO: These instructions are deprecated. Remove them.
+ if (auto type = curr->castType.getHeapType();
+ curr->castType.isNonNullable() && type.isBasic()) {
+ switch (type.getBasic()) {
+ case HeapType::func:
+ printMedium(o, "ref.is_func");
+ return;
+ case HeapType::data:
+ printMedium(o, "ref.is_data");
+ return;
+ case HeapType::i31:
+ printMedium(o, "ref.is_i31");
+ return;
+ default:
+ break;
+ }
+ }
printMedium(o, "ref.test ");
if (curr->castType.isNullable()) {
printMedium(o, "null ");
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index cda14c989..18568271b 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -2954,11 +2954,10 @@ Expression* TranslateToFuzzReader::makeBulkMemory(Type type) {
WASM_UNREACHABLE("invalid value");
}
-// TODO: support other RefIs variants, and rename this
Expression* TranslateToFuzzReader::makeRefIsNull(Type type) {
assert(type == Type::i32);
assert(wasm.features.hasReferenceTypes());
- return builder.makeRefIs(RefIsNull, make(getReferenceType()));
+ return builder.makeRefIsNull(make(getReferenceType()));
}
Expression* TranslateToFuzzReader::makeRefEq(Type type) {
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 303c81128..1a3e5c82b 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1738,7 +1738,8 @@ public:
void visitUnreachable(Unreachable* curr);
void visitDrop(Drop* curr);
void visitRefNull(RefNull* curr);
- void visitRefIs(RefIs* curr, uint8_t code);
+ void visitRefIsNull(RefIsNull* curr);
+ void visitRefIs(RefTest* curr, uint8_t code);
void visitRefFunc(RefFunc* curr);
void visitRefEq(RefEq* curr);
void visitTableGet(TableGet* curr);
diff --git a/src/wasm-builder.h b/src/wasm-builder.h
index 915c189ae..263ee80fd 100644
--- a/src/wasm-builder.h
+++ b/src/wasm-builder.h
@@ -716,9 +716,8 @@ public:
ret->finalize(type);
return ret;
}
- RefIs* makeRefIs(RefIsOp op, Expression* value) {
- auto* ret = wasm.allocator.alloc<RefIs>();
- ret->op = op;
+ RefIsNull* makeRefIsNull(Expression* value) {
+ auto* ret = wasm.allocator.alloc<RefIsNull>();
ret->value = value;
ret->finalize();
return ret;
diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def
index f929def4a..019cdbc0d 100644
--- a/src/wasm-delegations-fields.def
+++ b/src/wasm-delegations-fields.def
@@ -491,11 +491,10 @@ switch (DELEGATE_ID) {
DELEGATE_END(RefNull);
break;
}
- case Expression::Id::RefIsId: {
- DELEGATE_START(RefIs);
- DELEGATE_FIELD_INT(RefIs, op);
- DELEGATE_FIELD_CHILD(RefIs, value);
- DELEGATE_END(RefIs);
+ case Expression::Id::RefIsNullId: {
+ DELEGATE_START(RefIsNull);
+ DELEGATE_FIELD_CHILD(RefIsNull, value);
+ DELEGATE_END(RefIsNull);
break;
}
case Expression::Id::RefFuncId: {
diff --git a/src/wasm-delegations.def b/src/wasm-delegations.def
index dbdef3a86..d2b5dfa2e 100644
--- a/src/wasm-delegations.def
+++ b/src/wasm-delegations.def
@@ -55,7 +55,7 @@ DELEGATE(MemoryGrow);
DELEGATE(Unreachable);
DELEGATE(Pop);
DELEGATE(RefNull);
-DELEGATE(RefIs);
+DELEGATE(RefIsNull);
DELEGATE(RefFunc);
DELEGATE(RefEq);
DELEGATE(TableGet);
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 181114c92..104f06585 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -1336,26 +1336,15 @@ public:
NOTE_ENTER("RefNull");
return Literal::makeNull(curr->type.getHeapType());
}
- Flow visitRefIs(RefIs* curr) {
- NOTE_ENTER("RefIs");
+ Flow visitRefIsNull(RefIsNull* curr) {
+ NOTE_ENTER("RefIsNull");
Flow flow = visit(curr->value);
if (flow.breaking()) {
return flow;
}
const auto& value = flow.getSingleValue();
NOTE_EVAL1(value);
- switch (curr->op) {
- case RefIsNull:
- return Literal(value.isNull());
- case RefIsFunc:
- return Literal(value.type.isFunction());
- case RefIsData:
- return Literal(value.isData());
- case RefIsI31:
- return Literal(value.type.getHeapType() == HeapType::i31);
- default:
- WASM_UNREACHABLE("unimplemented ref.is_*");
- }
+ return Literal(int32_t(value.isNull()));
}
Flow visitRefFunc(RefFunc* curr) {
NOTE_ENTER("RefFunc");
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 04c832869..6ae3e57be 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -267,7 +267,7 @@ private:
Expression* makeBreakTable(Element& s);
Expression* makeReturn(Element& s);
Expression* makeRefNull(Element& s);
- Expression* makeRefIs(Element& s, RefIsOp op);
+ Expression* makeRefIsNull(Element& s);
Expression* makeRefFunc(Element& s);
Expression* makeRefEq(Element& s);
Expression* makeTableGet(Element& s);
@@ -283,7 +283,8 @@ private:
Expression* makeCallRef(Element& s, bool isReturn);
Expression* makeI31New(Element& s);
Expression* makeI31Get(Element& s, bool signed_);
- Expression* makeRefTest(Element& s);
+ Expression* makeRefTest(Element& s,
+ std::optional<Type> castType = std::nullopt);
Expression* makeRefCast(Element& s);
Expression* makeRefCastNop(Element& s);
Expression* makeBrOnNull(Element& s, bool onFail = false);
diff --git a/src/wasm.h b/src/wasm.h
index ae88bc4d9..7b75ec3b8 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -557,13 +557,6 @@ enum SIMDTernaryOp {
DotI8x16I7x16AddSToVecI32x4,
};
-enum RefIsOp {
- RefIsNull,
- RefIsFunc,
- RefIsData,
- RefIsI31,
-};
-
enum RefAsOp {
RefAsNonNull,
RefAsFunc,
@@ -696,7 +689,7 @@ public:
MemoryFillId,
PopId,
RefNullId,
- RefIsId,
+ RefIsNullId,
RefFuncId,
RefEqId,
TableGetId,
@@ -1346,12 +1339,9 @@ public:
void finalize(Type type);
};
-class RefIs : public SpecificExpression<Expression::RefIsId> {
+class RefIsNull : public SpecificExpression<Expression::RefIsNullId> {
public:
- RefIs(MixedArena& allocator) {}
-
- // RefIs can represent ref.is_null, ref.is_func, ref.is_data, and ref.is_i31.
- RefIsOp op;
+ RefIsNull(MixedArena& allocator) {}
Expression* value;
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 2639599d5..b1f4b8907 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -3795,7 +3795,7 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
visitRefNull((curr = allocator.alloc<RefNull>())->cast<RefNull>());
break;
case BinaryConsts::RefIsNull:
- visitRefIs((curr = allocator.alloc<RefIs>())->cast<RefIs>(), code);
+ visitRefIsNull((curr = allocator.alloc<RefIsNull>())->cast<RefIsNull>());
break;
case BinaryConsts::RefFunc:
visitRefFunc((curr = allocator.alloc<RefFunc>())->cast<RefFunc>());
@@ -4026,7 +4026,8 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (opcode == BinaryConsts::RefIsFunc ||
opcode == BinaryConsts::RefIsData ||
opcode == BinaryConsts::RefIsI31) {
- visitRefIs((curr = allocator.alloc<RefIs>())->cast<RefIs>(), opcode);
+ visitRefIs((curr = allocator.alloc<RefTest>())->cast<RefTest>(),
+ opcode);
break;
}
if (opcode == BinaryConsts::RefAsFunc ||
@@ -6591,25 +6592,28 @@ void WasmBinaryBuilder::visitRefNull(RefNull* curr) {
curr->finalize(getHeapType().getBottom());
}
-void WasmBinaryBuilder::visitRefIs(RefIs* curr, uint8_t code) {
+void WasmBinaryBuilder::visitRefIsNull(RefIsNull* curr) {
+ BYN_TRACE("zz node: RefIsNull\n");
+ curr->value = popNonVoidExpression();
+ curr->finalize();
+}
+
+void WasmBinaryBuilder::visitRefIs(RefTest* curr, uint8_t code) {
BYN_TRACE("zz node: RefIs\n");
switch (code) {
- case BinaryConsts::RefIsNull:
- curr->op = RefIsNull;
- break;
case BinaryConsts::RefIsFunc:
- curr->op = RefIsFunc;
+ curr->castType = Type(HeapType::func, NonNullable);
break;
case BinaryConsts::RefIsData:
- curr->op = RefIsData;
+ curr->castType = Type(HeapType::data, NonNullable);
break;
case BinaryConsts::RefIsI31:
- curr->op = RefIsI31;
+ curr->castType = Type(HeapType::i31, NonNullable);
break;
default:
WASM_UNREACHABLE("invalid code for ref.is_*");
}
- curr->value = popNonVoidExpression();
+ curr->ref = popNonVoidExpression();
curr->finalize();
}
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp
index 638dfbebf..4f725d48b 100644
--- a/src/wasm/wasm-s-parser.cpp
+++ b/src/wasm/wasm-s-parser.cpp
@@ -2536,9 +2536,8 @@ Expression* SExpressionWasmBuilder::makeRefNull(Element& s) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeRefIs(Element& s, RefIsOp op) {
- auto ret = allocator.alloc<RefIs>();
- ret->op = op;
+Expression* SExpressionWasmBuilder::makeRefIsNull(Element& s) {
+ auto ret = allocator.alloc<RefIsNull>();
ret->value = parseExpression(s[1]);
ret->finalize();
return ret;
@@ -2775,16 +2774,20 @@ Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) {
return ret;
}
-Expression* SExpressionWasmBuilder::makeRefTest(Element& s) {
+Expression* SExpressionWasmBuilder::makeRefTest(Element& s,
+ std::optional<Type> castType) {
int i = 1;
- auto nullability = NonNullable;
- if (s[0]->str().str != "ref.test_static" && s[1]->str().str == "null") {
- nullability = Nullable;
- ++i;
+ if (!castType) {
+ auto nullability = NonNullable;
+ if (s[0]->str().str != "ref.test_static" && s[1]->str().str == "null") {
+ nullability = Nullable;
+ ++i;
+ }
+ auto type = parseHeapType(*s[i++]);
+ castType = Type(type, nullability);
}
- auto heapType = parseHeapType(*s[i++]);
auto* ref = parseExpression(*s[i++]);
- return Builder(wasm).makeRefTest(ref, Type(heapType, nullability));
+ return Builder(wasm).makeRefTest(ref, *castType);
}
Expression* SExpressionWasmBuilder::makeRefCast(Element& s) {
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index 24710f206..82c7c511f 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1875,23 +1875,8 @@ void BinaryInstWriter::visitRefNull(RefNull* curr) {
parent.writeHeapType(curr->type.getHeapType());
}
-void BinaryInstWriter::visitRefIs(RefIs* curr) {
- switch (curr->op) {
- case RefIsNull:
- o << int8_t(BinaryConsts::RefIsNull);
- break;
- case RefIsFunc:
- o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefIsFunc);
- break;
- case RefIsData:
- o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefIsData);
- break;
- case RefIsI31:
- o << int8_t(BinaryConsts::GCPrefix) << int8_t(BinaryConsts::RefIsI31);
- break;
- default:
- WASM_UNREACHABLE("unimplemented ref.is_*");
- }
+void BinaryInstWriter::visitRefIsNull(RefIsNull* curr) {
+ o << int8_t(BinaryConsts::RefIsNull);
}
void BinaryInstWriter::visitRefFunc(RefFunc* curr) {
@@ -2025,6 +2010,23 @@ void BinaryInstWriter::visitCallRef(CallRef* curr) {
void BinaryInstWriter::visitRefTest(RefTest* curr) {
o << int8_t(BinaryConsts::GCPrefix);
+ // TODO: These instructions are deprecated. Remove them.
+ if (auto type = curr->castType.getHeapType();
+ curr->castType.isNonNullable() && type.isBasic()) {
+ switch (type.getBasic()) {
+ case HeapType::func:
+ o << U32LEB(BinaryConsts::RefIsFunc);
+ return;
+ case HeapType::data:
+ o << U32LEB(BinaryConsts::RefIsData);
+ return;
+ case HeapType::i31:
+ o << U32LEB(BinaryConsts::RefIsI31);
+ return;
+ default:
+ break;
+ }
+ }
if (curr->castType.isNullable()) {
o << U32LEB(BinaryConsts::RefTestNull);
} else {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 486f13d24..28526cb33 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -427,7 +427,7 @@ public:
void visitMemorySize(MemorySize* curr);
void visitMemoryGrow(MemoryGrow* curr);
void visitRefNull(RefNull* curr);
- void visitRefIs(RefIs* curr);
+ void visitRefIsNull(RefIsNull* curr);
void visitRefAs(RefAs* curr);
void visitRefFunc(RefFunc* curr);
void visitRefEq(RefEq* curr);
@@ -2132,14 +2132,15 @@ void FunctionValidator::visitRefNull(RefNull* curr) {
curr->type.isNull(), curr, "ref.null must have a bottom heap type");
}
-void FunctionValidator::visitRefIs(RefIs* curr) {
- shouldBeTrue(getModule()->features.hasReferenceTypes(),
- curr,
- "ref.is_* requires reference-types [--enable-reference-types]");
+void FunctionValidator::visitRefIsNull(RefIsNull* curr) {
+ shouldBeTrue(
+ getModule()->features.hasReferenceTypes(),
+ curr,
+ "ref.is_null requires reference-types [--enable-reference-types]");
shouldBeTrue(curr->value->type == Type::unreachable ||
curr->value->type.isRef(),
curr->value,
- "ref.is_*'s argument should be a reference type");
+ "ref.is_null's argument should be a reference type");
}
void FunctionValidator::visitRefAs(RefAs* curr) {
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index c6779a328..c121ba89a 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -805,7 +805,7 @@ void RefNull::finalize(Type type_) { type = type_; }
void RefNull::finalize() {}
-void RefIs::finalize() {
+void RefIsNull::finalize() {
if (value->type == Type::unreachable) {
type = Type::unreachable;
} else {
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index 14d30db1c..08eec41c6 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -758,7 +758,7 @@ struct NullInstrParserCtx {
template<typename HeapTypeT> InstrT makeRefNull(Index, HeapTypeT) {
return Ok{};
}
- InstrT makeRefIs(Index, RefIsOp) { return Ok{}; }
+ InstrT makeRefIsNull(Index) { return Ok{}; }
InstrT makeRefEq(Index) { return Ok{}; }
@@ -2053,10 +2053,10 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> {
return push(pos, builder.makeRefNull(type));
}
- Result<> makeRefIs(Index pos, RefIsOp op) {
+ Result<> makeRefIsNull(Index pos) {
auto ref = pop(pos);
CHECK_ERR(ref);
- return push(pos, builder.makeRefIs(op, *ref));
+ return push(pos, builder.makeRefIsNull(*ref));
}
Result<> makeRefEq(Index pos) {
@@ -2322,8 +2322,7 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeBreak(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeBreakTable(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeReturn(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefNull(Ctx&, Index);
-template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefIs(Ctx&, Index, RefIsOp op);
+template<typename Ctx> Result<typename Ctx::InstrT> makeRefIsNull(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefFunc(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefEq(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeTableGet(Ctx&, Index);
@@ -2344,8 +2343,9 @@ Result<typename Ctx::InstrT> makeCallRef(Ctx&, Index, bool isReturn);
template<typename Ctx> Result<typename Ctx::InstrT> makeI31New(Ctx&, Index);
template<typename Ctx>
Result<typename Ctx::InstrT> makeI31Get(Ctx&, Index, bool signed_);
-template<typename Ctx> Result<typename Ctx::InstrT> makeRefTest(Ctx&, Index);
-template<typename Ctx> Result<typename Ctx::InstrT> makeRefTest(Ctx&, Index);
+template<typename Ctx>
+Result<typename Ctx::InstrT>
+makeRefTest(Ctx&, Index, std::optional<Type> castType = std::nullopt);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefCast(Ctx&, Index);
template<typename Ctx> Result<typename Ctx::InstrT> makeRefCastNop(Ctx&, Index);
template<typename Ctx>
@@ -3357,8 +3357,8 @@ Result<typename Ctx::InstrT> makeRefNull(Ctx& ctx, Index pos) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefIs(Ctx& ctx, Index pos, RefIsOp op) {
- return ctx.makeRefIs(pos, op);
+Result<typename Ctx::InstrT> makeRefIsNull(Ctx& ctx, Index pos) {
+ return ctx.makeRefIsNull(pos);
}
template<typename Ctx>
@@ -3438,7 +3438,8 @@ Result<typename Ctx::InstrT> makeI31Get(Ctx& ctx, Index pos, bool signed_) {
}
template<typename Ctx>
-Result<typename Ctx::InstrT> makeRefTest(Ctx& ctx, Index pos) {
+Result<typename Ctx::InstrT>
+makeRefTest(Ctx& ctx, Index pos, std::optional<Type> castType) {
return ctx.in.err("unimplemented instruction");
}
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 25931db85..eddb26866 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -2206,7 +2206,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
- Ref visitRefIs(RefIs* curr) {
+ Ref visitRefIsNull(RefIsNull* curr) {
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
diff --git a/test/binaryen.js/expressions.js b/test/binaryen.js/expressions.js
index c0bc402a0..ee55ee90b 100644
--- a/test/binaryen.js/expressions.js
+++ b/test/binaryen.js/expressions.js
@@ -1417,51 +1417,30 @@ console.log("# MemoryFill");
module.dispose();
})();
-console.log("# RefIs");
-(function testRefIs() {
+console.log("# RefIsNull");
+(function testRefIsNull() {
const module = new binaryen.Module();
- var op = binaryen.Operations.RefIsNull;
var value = module.local.get(1, binaryen.externref);
- const theRefIs = binaryen.RefIs(module.ref.is_null(value));
- assert(theRefIs instanceof binaryen.RefIs);
- assert(theRefIs instanceof binaryen.Expression);
- assert(theRefIs.op === op);
- assert(theRefIs.value === value);
- assert(theRefIs.type === binaryen.i32);
-
- theRefIs.op = op = binaryen.Operations.RefIsFunc;
- assert(theRefIs.op === op);
- theRefIs.op = op = binaryen.Operations.RefIsNull;
- theRefIs.value = value = module.local.get(2, binaryen.externref);
- assert(theRefIs.value === value);
- theRefIs.type = binaryen.f64;
- theRefIs.finalize();
- assert(theRefIs.type === binaryen.i32);
-
- console.log(theRefIs.toText());
+ const theRefIsNull = binaryen.RefIsNull(module.ref.is_null(value));
+ assert(theRefIsNull instanceof binaryen.RefIsNull);
+ assert(theRefIsNull instanceof binaryen.Expression);
+ assert(theRefIsNull.value === value);
+ assert(theRefIsNull.type === binaryen.i32);
+
+ theRefIsNull.value = value = module.local.get(2, binaryen.externref);
+ assert(theRefIsNull.value === value);
+ theRefIsNull.type = binaryen.f64;
+ theRefIsNull.finalize();
+ assert(theRefIsNull.type === binaryen.i32);
+
+ console.log(theRefIsNull.toText());
assert(
- theRefIs.toText()
+ theRefIsNull.toText()
==
"(ref.is_null\n (local.get $2)\n)\n"
);
- assert(
- binaryen.RefIs(module.ref.is_func(value)).toText()
- ==
- "(ref.is_func\n (local.get $2)\n)\n"
- );
- assert(
- binaryen.RefIs(module.ref.is_data(value)).toText()
- ==
- "(ref.is_data\n (local.get $2)\n)\n"
- );
- assert(
- binaryen.RefIs(module.ref.is_i31(value)).toText()
- ==
- "(ref.is_i31\n (local.get $2)\n)\n"
- );
-
module.dispose();
})();
diff --git a/test/binaryen.js/expressions.js.txt b/test/binaryen.js/expressions.js.txt
index fbf69888a..75f3a8d54 100644
--- a/test/binaryen.js/expressions.js.txt
+++ b/test/binaryen.js/expressions.js.txt
@@ -214,7 +214,7 @@
(i32.const 6)
)
-# RefIs
+# RefIsNull
(ref.is_null
(local.get $2)
)
diff --git a/test/binaryen.js/kitchen-sink.js b/test/binaryen.js/kitchen-sink.js
index 52d8fd16f..0de23883a 100644
--- a/test/binaryen.js/kitchen-sink.js
+++ b/test/binaryen.js/kitchen-sink.js
@@ -145,7 +145,7 @@ function test_ids() {
console.log("MemoryFillId: " + binaryen.MemoryFillId);
console.log("PopId: " + binaryen.PopId);
console.log("RefNullId: " + binaryen.RefNullId);
- console.log("RefIsId: " + binaryen.RefIsId);
+ console.log("RefIsNullId: " + binaryen.RefIsNullId);
console.log("RefFuncId: " + binaryen.RefFuncId);
console.log("RefEqId: " + binaryen.RefEqId);
console.log("TableGetId: " + binaryen.TableGetId);
diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt
index c59c2dac1..4798c8592 100644
--- a/test/binaryen.js/kitchen-sink.js.txt
+++ b/test/binaryen.js/kitchen-sink.js.txt
@@ -75,7 +75,7 @@ MemoryCopyId: 38
MemoryFillId: 39
PopId: 40
RefNullId: 41
-RefIsId: 42
+RefIsNullId: 42
RefFuncId: 43
RefEqId: 44
TableGetId: 45
diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c
index de105d239..cc2c96538 100644
--- a/test/example/c-api-kitchen-sink.c
+++ b/test/example/c-api-kitchen-sink.c
@@ -1002,8 +1002,8 @@ void test_core() {
iIfF,
BinaryenTypeInt32()),
// Reference types
- BinaryenRefIs(module, BinaryenRefIsNull(), externrefExpr),
- BinaryenRefIs(module, BinaryenRefIsNull(), funcrefExpr),
+ BinaryenRefIsNull(module, externrefExpr),
+ BinaryenRefIsNull(module, funcrefExpr),
BinaryenSelect(
module,
temp10,
@@ -1014,15 +1014,6 @@ void test_core() {
BinaryenRefEq(module,
BinaryenRefNull(module, BinaryenTypeNullref()),
BinaryenRefNull(module, BinaryenTypeNullref())),
- BinaryenRefIs(module,
- BinaryenRefIsFunc(),
- BinaryenRefNull(module, BinaryenTypeNullref())),
- BinaryenRefIs(module,
- BinaryenRefIsData(),
- BinaryenRefNull(module, BinaryenTypeNullref())),
- BinaryenRefIs(module,
- BinaryenRefIsI31(),
- BinaryenRefNull(module, BinaryenTypeNullref())),
BinaryenRefAs(module,
BinaryenRefAsNonNull(),
BinaryenRefNull(module, BinaryenTypeNullref())),
diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt
index 1ee529eb3..51298d1a2 100644
--- a/test/example/c-api-kitchen-sink.txt
+++ b/test/example/c-api-kitchen-sink.txt
@@ -2004,21 +2004,6 @@ BinaryenFeatureAll: 126975
)
)
(drop
- (ref.is_func
- (ref.null none)
- )
- )
- (drop
- (ref.is_data
- (ref.null none)
- )
- )
- (drop
- (ref.is_i31
- (ref.null none)
- )
- )
- (drop
(ref.as_non_null
(ref.null none)
)
diff --git a/test/heap-types.wast b/test/heap-types.wast
index f75622142..5171d5a66 100644
--- a/test/heap-types.wast
+++ b/test/heap-types.wast
@@ -182,7 +182,6 @@
(unreachable)
)
(func $ref.is_X (param $x anyref)
- (if (ref.is_func (local.get $x)) (unreachable))
(if (ref.is_data (local.get $x)) (unreachable))
(if (ref.is_i31 (local.get $x)) (unreachable))
)
diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast
index 9eafd633b..b551a9073 100644
--- a/test/heap-types.wast.from-wast
+++ b/test/heap-types.wast.from-wast
@@ -177,12 +177,6 @@
)
(func $ref.is_X (type $anyref_=>_none) (param $x anyref)
(if
- (ref.is_func
- (local.get $x)
- )
- (unreachable)
- )
- (if
(ref.is_data
(local.get $x)
)
diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary
index 04e9bbe05..485611fef 100644
--- a/test/heap-types.wast.fromBinary
+++ b/test/heap-types.wast.fromBinary
@@ -175,12 +175,6 @@
)
(func $ref.is_X (type $anyref_=>_none) (param $x anyref)
(if
- (ref.is_func
- (local.get $x)
- )
- (unreachable)
- )
- (if
(ref.is_data
(local.get $x)
)
diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo
index 472c3288f..03047def7 100644
--- a/test/heap-types.wast.fromBinary.noDebugInfo
+++ b/test/heap-types.wast.fromBinary.noDebugInfo
@@ -175,12 +175,6 @@
)
(func $2 (type $anyref_=>_none) (param $0 anyref)
(if
- (ref.is_func
- (local.get $0)
- )
- (unreachable)
- )
- (if
(ref.is_data
(local.get $0)
)
diff --git a/test/lit/cast-to-basic.wast b/test/lit/cast-to-basic.wast
index 239fd820c..9433c3ba1 100644
--- a/test/lit/cast-to-basic.wast
+++ b/test/lit/cast-to-basic.wast
@@ -6,7 +6,7 @@
(module
;; CHECK: (func $test (type $none_=>_i32) (result i32)
- ;; CHECK-NEXT: (ref.test data
+ ;; CHECK-NEXT: (ref.is_data
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
diff --git a/test/lit/passes/inlining_splitting.wast b/test/lit/passes/inlining_splitting.wast
index efd6b3c7d..2f840a494 100644
--- a/test/lit/passes/inlining_splitting.wast
+++ b/test/lit/passes/inlining_splitting.wast
@@ -1163,7 +1163,7 @@
)
;; A second if. We can outline both if bodies.
(if
- (ref.is_func
+ (ref.is_null
(local.get $x)
)
(loop $x
@@ -1200,7 +1200,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (ref.is_func
+ ;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_0
@@ -1231,7 +1231,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
- ;; CHECK-NEXT: (ref.is_func
+ ;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $byn-split-outlined-B$multi-if_0
diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast
index fec4c17f0..67f15de6c 100644
--- a/test/lit/passes/optimize-instructions-gc-tnh.wast
+++ b/test/lit/passes/optimize-instructions-gc-tnh.wast
@@ -140,7 +140,7 @@
)
)
- ;; TNH: (func $ref.is_func_a (type $anyref_=>_i32) (param $a anyref) (result i32)
+ ;; TNH: (func $ref.is_func (type $anyref_=>_i32) (param $a anyref) (result i32)
;; TNH-NEXT: (drop
;; TNH-NEXT: (ref.as_func
;; TNH-NEXT: (local.get $a)
@@ -148,7 +148,7 @@
;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
- ;; NO_TNH: (func $ref.is_func_a (type $anyref_=>_i32) (param $a anyref) (result i32)
+ ;; NO_TNH: (func $ref.is_func (type $anyref_=>_i32) (param $a anyref) (result i32)
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.as_func
;; NO_TNH-NEXT: (local.get $a)
@@ -156,7 +156,7 @@
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (i32.const 1)
;; NO_TNH-NEXT: )
- (func $ref.is_func_a (param $a (ref null any)) (result i32)
+ (func $ref.is_func (param $a (ref null any)) (result i32)
;; The check must succeed. We can return 1 here, and drop the rest, with or
;; without TNH (in particular, TNH should not just remove the cast but not
;; return a 1).
@@ -167,31 +167,6 @@
)
)
- ;; TNH: (func $ref.is_func_b (type $anyref_=>_i32) (param $a anyref) (result i32)
- ;; TNH-NEXT: (drop
- ;; TNH-NEXT: (ref.as_data
- ;; TNH-NEXT: (local.get $a)
- ;; TNH-NEXT: )
- ;; TNH-NEXT: )
- ;; TNH-NEXT: (i32.const 0)
- ;; TNH-NEXT: )
- ;; NO_TNH: (func $ref.is_func_b (type $anyref_=>_i32) (param $a anyref) (result i32)
- ;; NO_TNH-NEXT: (drop
- ;; NO_TNH-NEXT: (ref.as_data
- ;; NO_TNH-NEXT: (local.get $a)
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: )
- ;; NO_TNH-NEXT: (i32.const 0)
- ;; NO_TNH-NEXT: )
- (func $ref.is_func_b (param $a (ref null any)) (result i32)
- ;; A case where the type cannot match, and we return 0.
- (ref.is_func
- (ref.as_data
- (local.get $a)
- )
- )
- )
-
;; TNH: (func $if.arm.null (type $i32_ref|$struct|_=>_none) (param $x i32) (param $ref (ref $struct))
;; TNH-NEXT: (struct.set $struct 0
;; TNH-NEXT: (block (result (ref $struct))
diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast
index c0ea515d0..42b915c38 100644
--- a/test/lit/passes/optimize-instructions-gc.wast
+++ b/test/lit/passes/optimize-instructions-gc.wast
@@ -238,17 +238,13 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (ref.is_null
- ;; CHECK-NEXT: (local.get $func)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.is_func
+ ;; CHECK-NEXT: (local.get $func)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (i32.eqz
- ;; CHECK-NEXT: (ref.is_null
- ;; CHECK-NEXT: (local.get $i31)
- ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (ref.is_i31
+ ;; CHECK-NEXT: (local.get $i31)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -259,17 +255,13 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (i32.eqz
- ;; NOMNL-NEXT: (ref.is_null
- ;; NOMNL-NEXT: (local.get $func)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.is_func
+ ;; NOMNL-NEXT: (local.get $func)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (i32.eqz
- ;; NOMNL-NEXT: (ref.is_null
- ;; NOMNL-NEXT: (local.get $i31)
- ;; NOMNL-NEXT: )
+ ;; NOMNL-NEXT: (ref.is_i31
+ ;; NOMNL-NEXT: (local.get $i31)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
@@ -288,103 +280,6 @@
)
)
- ;; similar to $unneeded_is, but the values are of mixed kind (is_func of
- ;; struct, etc.). regardless of nullability the result here is always 0.
- ;; CHECK: (func $unneeded_is_bad_kinds (type $funcref_dataref_i31ref_=>_none) (param $func funcref) (param $struct dataref) (param $i31 i31ref)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block (result i32)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $struct)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block (result i32)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (local.get $func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block (result i32)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (local.get $struct)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (block (result i32)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.as_non_null
- ;; CHECK-NEXT: (local.get $func)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (i32.const 0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; NOMNL: (func $unneeded_is_bad_kinds (type $funcref_dataref_i31ref_=>_none) (param $func funcref) (param $struct dataref) (param $i31 i31ref)
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block (result i32)
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (local.get $struct)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (i32.const 0)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block (result i32)
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (local.get $func)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (i32.const 0)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block (result i32)
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (local.get $struct)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (i32.const 0)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (block (result i32)
- ;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.as_non_null
- ;; NOMNL-NEXT: (local.get $func)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: (i32.const 0)
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- ;; NOMNL-NEXT: )
- (func $unneeded_is_bad_kinds
- (param $func (ref null func))
- (param $struct (ref null struct))
- (param $i31 (ref null i31))
- (drop
- (ref.is_func (local.get $struct))
- )
- (drop
- (ref.is_i31 (local.get $func))
- )
- ;; also check non-nullable types as inputs
- (drop
- (ref.is_func (ref.as_non_null (local.get $struct)))
- )
- (drop
- (ref.is_i31 (ref.as_non_null (local.get $func)))
- )
- )
-
;; ref.as_non_null is not needed on a non-nullable value, and if something is
;; a func we don't need that either etc., and can just return the value.
;; CHECK: (func $unneeded_as (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31))
@@ -2952,7 +2847,7 @@
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.is_func
+ ;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -2970,7 +2865,7 @@
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
;; NOMNL-NEXT: (drop
- ;; NOMNL-NEXT: (ref.is_func
+ ;; NOMNL-NEXT: (ref.is_null
;; NOMNL-NEXT: (local.get $x)
;; NOMNL-NEXT: )
;; NOMNL-NEXT: )
@@ -2994,7 +2889,7 @@
;; likewise ref.is and ref.test
(drop
(i32.and
- (ref.is_func
+ (ref.is_null
(local.get $x)
)
(i32.const 1)
diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast
index 889b82fc4..00801b0c5 100644
--- a/test/lit/wat-kitchen-sink.wast
+++ b/test/lit/wat-kitchen-sink.wast
@@ -59,7 +59,7 @@
;; CHECK: (type $none_=>_i32_i64 (func (result i32 i64)))
- ;; CHECK: (type $anyref_=>_none (func (param anyref)))
+ ;; CHECK: (type $anyref_=>_i32 (func (param anyref) (result i32)))
;; CHECK: (type $eqref_eqref_=>_i32 (func (param eqref eqref) (result i32)))
@@ -1398,41 +1398,14 @@
return
)
- ;; CHECK: (func $ref-is (type $anyref_=>_none) (param $0 anyref)
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.is_null
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.is_func
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.is_data
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: )
- ;; CHECK-NEXT: (drop
- ;; CHECK-NEXT: (ref.is_i31
- ;; CHECK-NEXT: (local.get $0)
- ;; CHECK-NEXT: )
+ ;; CHECK: (func $ref-is-null (type $anyref_=>_i32) (param $0 anyref) (result i32)
+ ;; CHECK-NEXT: (ref.is_null
+ ;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $ref-is (param anyref)
+ (func $ref-is-null (param anyref) (result i32)
local.get 0
ref.is_null
- drop
- local.get 0
- ref.is_func
- drop
- local.get 0
- ref.is_data
- drop
- local.get 0
- ref.is_i31
- drop
)
;; CHECK: (func $ref-eq (type $eqref_eqref_=>_i32) (param $0 eqref) (param $1 eqref) (result i32)
diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
index 8006cb2a6..fb11af060 100644
--- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -36,7 +36,7 @@ total
RefAs : 4
RefEq : 2
RefFunc : 9
- RefIs : 1
+ RefIsNull : 1
RefNull : 5
Return : 29
SIMDExtract : 3