diff options
-rw-r--r-- | src/ir/type-updating.cpp | 3 | ||||
-rw-r--r-- | src/tools/tool-options.h | 9 | ||||
-rw-r--r-- | src/wasm-features.h | 25 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 3 | ||||
-rw-r--r-- | test/binaryen.js/kitchen-sink.js.txt | 2 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.txt | 2 | ||||
-rw-r--r-- | test/lit/passes/ssa-gc-nn-locals.wast | 27 |
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)) + ) +) |