summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ir/type-updating.cpp3
-rw-r--r--src/tools/tool-options.h9
-rw-r--r--src/wasm-features.h25
-rw-r--r--src/wasm/wasm-validator.cpp3
-rw-r--r--test/binaryen.js/kitchen-sink.js.txt2
-rw-r--r--test/example/c-api-kitchen-sink.txt2
-rw-r--r--test/lit/passes/ssa-gc-nn-locals.wast27
7 files changed, 62 insertions, 9 deletions
diff --git a/src/ir/type-updating.cpp b/src/ir/type-updating.cpp
index 658fabc83..2dc60d2df 100644
--- a/src/ir/type-updating.cpp
+++ b/src/ir/type-updating.cpp
@@ -29,6 +29,9 @@ bool canHandleAsLocal(Type type) {
void handleNonDefaultableLocals(Function* func, Module& wasm) {
// Check if this is an issue.
+ if (wasm.features.hasGCNNLocals()) {
+ return;
+ }
bool hasNonNullable = false;
for (auto type : func->vars) {
if (type.isRef() && !type.isNullable()) {
diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h
index 49eca1adc..350b7babd 100644
--- a/src/tools/tool-options.h
+++ b/src/tools/tool-options.h
@@ -42,7 +42,7 @@ struct ToolOptions : public Options {
Arguments::Zero,
[this](Options*, const std::string&) {
hasFeatureOptions = true;
- enabledFeatures.makeMVP();
+ enabledFeatures.setMVP();
disabledFeatures.setAll();
})
.add("--all-features",
@@ -52,7 +52,7 @@ struct ToolOptions : public Options {
[this](Options*, const std::string&) {
hasFeatureOptions = true;
enabledFeatures.setAll();
- disabledFeatures.makeMVP();
+ disabledFeatures.setMVP();
})
.add("--detect-features",
"",
@@ -61,8 +61,8 @@ struct ToolOptions : public Options {
[this](Options*, const std::string&) {
hasFeatureOptions = true;
detectFeatures = true;
- enabledFeatures.makeMVP();
- disabledFeatures.makeMVP();
+ enabledFeatures.setMVP();
+ disabledFeatures.setMVP();
})
.add("--quiet",
"-q",
@@ -91,6 +91,7 @@ struct ToolOptions : public Options {
.addFeature(FeatureSet::Memory64, "memory64")
.addFeature(FeatureSet::TypedFunctionReferences,
"typed function references")
+ .addFeature(FeatureSet::GCNNLocals, "GC non-null locals")
.add("--no-validation",
"-n",
"Disables validation, assumes inputs are correct",
diff --git a/src/wasm-features.h b/src/wasm-features.h
index 237dc7757..e28dcf4d1 100644
--- a/src/wasm-features.h
+++ b/src/wasm-features.h
@@ -39,7 +39,9 @@ struct FeatureSet {
GC = 1 << 10,
Memory64 = 1 << 11,
TypedFunctionReferences = 1 << 12,
- All = (1 << 13) - 1
+ // TODO: Remove this feature when the wasm spec stabilizes.
+ GCNNLocals = 1 << 13,
+ All = (1 << 14) - 1
};
static std::string toString(Feature f) {
@@ -70,6 +72,8 @@ struct FeatureSet {
return "memory64";
case TypedFunctionReferences:
return "typed-function-references";
+ case GCNNLocals:
+ return "gc-nn-locals";
default:
WASM_UNREACHABLE("unexpected feature");
}
@@ -113,9 +117,9 @@ struct FeatureSet {
bool hasTypedFunctionReferences() const {
return (features & TypedFunctionReferences) != 0;
}
+ bool hasGCNNLocals() const { return (features & GCNNLocals) != 0; }
bool hasAll() const { return (features & All) != 0; }
- void makeMVP() { features = MVP; }
void set(FeatureSet f, bool v = true) {
features = v ? (features | f) : (features & ~f);
}
@@ -134,7 +138,22 @@ struct FeatureSet {
void setTypedFunctionReferences(bool v = true) {
set(TypedFunctionReferences, v);
}
- void setAll(bool v = true) { features = v ? All : MVP; }
+ void setGCNNLocals(bool v = true) { set(GCNNLocals, v); }
+ void setMVP() { features = MVP; }
+ void setAll() {
+ // Do not set GCNNLocals, which forces the user to opt in to that feature
+ // explicitly. That is, wasm-opt -all will enable GC but *not* enable
+ // non-nullable locals. To get them, do wasm-opt -all --enable-gc-nn-locals
+ // FIXME: When the wasm spec stabilizes, this feature will go away, as the
+ // non-nullable locals experiment will either become the standard,
+ // or it will go away.
+ // Leave the old GCNNLocals value unmodified. This makes things like
+ // --enable-gc-nn-locals -all work (that is, if we enable the feature,
+ // then -all does not disable it; it simply does not enable it by itself).
+ auto oldGCNNLocals = hasGCNNLocals();
+ features = All;
+ setGCNNLocals(oldGCNNLocals);
+ }
void enable(const FeatureSet& other) { features |= other.features; }
void disable(const FeatureSet& other) {
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 15b17bf26..d704ee15e 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2496,6 +2496,9 @@ void FunctionValidator::visitFunction(Function* curr) {
shouldBeTrue(result.isConcrete(), curr, "results must be concretely typed");
}
for (const auto& var : curr->vars) {
+ if (var.isRef() && getModule()->features.hasGCNNLocals()) {
+ continue;
+ }
features |= var.getFeatures();
shouldBeTrue(var.isDefaultable(), var, "vars must be defaultable");
}
diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt
index 600795c05..b8b671de5 100644
--- a/test/binaryen.js/kitchen-sink.js.txt
+++ b/test/binaryen.js/kitchen-sink.js.txt
@@ -42,7 +42,7 @@ Features.Multivalue: 512
Features.GC: 1024
Features.Memory64: 2048
Features.TypedFunctionReferences: 4096
-Features.All: 8191
+Features.All: 16383
InvalidId: 0
BlockId: 1
IfId: 2
diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt
index fd1b5e64c..eb83ffb33 100644
--- a/test/example/c-api-kitchen-sink.txt
+++ b/test/example/c-api-kitchen-sink.txt
@@ -26,7 +26,7 @@ BinaryenFeatureMultivalue: 512
BinaryenFeatureGC: 1024
BinaryenFeatureMemory64: 2048
BinaryenFeatureTypedFunctionReferences: 4096
-BinaryenFeatureAll: 8191
+BinaryenFeatureAll: 16383
(f32.neg
(f32.const -33.61199951171875)
)
diff --git a/test/lit/passes/ssa-gc-nn-locals.wast b/test/lit/passes/ssa-gc-nn-locals.wast
new file mode 100644
index 000000000..149a0c5c7
--- /dev/null
+++ b/test/lit/passes/ssa-gc-nn-locals.wast
@@ -0,0 +1,27 @@
+;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
+;; RUN: wasm-opt %s -all --ssa --enable-gc-nn-locals -S -o - | filecheck %s
+
+(module
+ ;; CHECK: (func $nn-locals
+ ;; CHECK-NEXT: (local $x (ref func))
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (ref.func $nn-locals)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $nn-locals
+ ;; A non-nullable local
+ (local $x (ref func))
+ ;; Set the local, and get it later. The SSA pass will normally handle non-
+ ;; nullability using ref.as_non_null, but with --gc-nn-locals nothing should
+ ;; be done.
+ (local.set $x (ref.func $nn-locals))
+ (drop (local.get $x))
+ (drop (local.get $x))
+ )
+)