summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-06-15 11:14:42 -0700
committerGitHub <noreply@github.com>2021-06-15 11:14:42 -0700
commit9d279c08b9f37b6cf2c5a5fac564eee9ea4fb927 (patch)
tree04ee164199e76d1a09ae4d12c9da820244a297a7
parente0a8f40f65b178556f6fcbed778923a36dca64e3 (diff)
downloadbinaryen-9d279c08b9f37b6cf2c5a5fac564eee9ea4fb927.tar.gz
binaryen-9d279c08b9f37b6cf2c5a5fac564eee9ea4fb927.tar.bz2
binaryen-9d279c08b9f37b6cf2c5a5fac564eee9ea4fb927.zip
[Wasm GC] Add experimental support for non-nullable locals (#3932)
This adds a new feature flag, GCNNLocals that enables support for non-nullable locals. No validation is applied to check that they are actually assigned before their use yet - this just allows experimentation to begin. This feature is not enabled by default even with -all. If we enabled it, then it would take effect in most of our tests and likely confuse current users as well. Instead, the flag must be opted in explicitly using --enable-gc-nn-locals. That is, this is an experimental feature flag, and as such must be explicitly enabled. (Once the spec stabilizes, we will remove the feature anyhow when we implement the final status of non-nullability. )
-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))
+ )
+)