diff options
author | Thomas Lively <tlively@google.com> | 2024-02-06 14:05:27 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-06 14:05:27 -0800 |
commit | 3a41065a27fc4e65d563ae983a06cbe774ad2ea7 (patch) | |
tree | bf66bf0c28465a96d97076505efca306db3db429 | |
parent | 8cce4d103a2ee54e7f09e81fc25b982b060d0e41 (diff) | |
download | binaryen-3a41065a27fc4e65d563ae983a06cbe774ad2ea7.tar.gz binaryen-3a41065a27fc4e65d563ae983a06cbe774ad2ea7.tar.bz2 binaryen-3a41065a27fc4e65d563ae983a06cbe774ad2ea7.zip |
Properly stringify names in tests (#6279)
Update identifiers used in tests to use a format supported by the new text
parser, i.e. either the standard format with its limited set of allowed
characters or the non-standard `$"..."` format. Notably, any name containing
square or curly braces now uses the string format.
Input automatically updated with this script:
https://gist.github.com/tlively/4e22311736661849e641d02e521a0748
The printer is updated to properly escape names in more places as well. The
logic for escaping names is moved to a common location so that the type
printing logic in wasm-type.cpp can use it as well.
-rw-r--r-- | src/passes/Print.cpp | 199 | ||||
-rw-r--r-- | src/support/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/support/name.cpp | 56 | ||||
-rw-r--r-- | src/support/name.h | 5 | ||||
-rw-r--r-- | src/support/string.cpp | 57 | ||||
-rw-r--r-- | src/support/string.h | 3 | ||||
-rw-r--r-- | src/wasm/wasm-type.cpp | 7 | ||||
-rw-r--r-- | test/lit/ctor-eval/array_new_data.wast | 8 | ||||
-rw-r--r-- | test/lit/passes/dae-gc-refine-params.wast | 166 | ||||
-rw-r--r-- | test/lit/passes/dae-gc-refine-return.wast | 76 | ||||
-rw-r--r-- | test/lit/passes/dae-gc.wast | 10 | ||||
-rw-r--r-- | test/lit/passes/gto-removals.wast | 44 | ||||
-rw-r--r-- | test/lit/passes/gufa-refs.wast | 18 | ||||
-rw-r--r-- | test/lit/passes/local-subtyping.wast | 4 | ||||
-rw-r--r-- | test/lit/passes/merge-similar-functions_all-features.wast | 12 | ||||
-rw-r--r-- | test/lit/passes/roundtrip-gc.wast | 6 | ||||
-rw-r--r-- | test/lit/passes/signature-refining.wast | 28 | ||||
-rw-r--r-- | test/lit/passes/vacuum-gc.wast | 20 | ||||
-rw-r--r-- | test/passes/Oz_fuzz-exec_all-features.wast | 4 |
19 files changed, 412 insertions, 313 deletions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 9cc8b52ca..6e4c1452c 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -23,6 +23,7 @@ #include <ir/table-utils.h> #include <pass.h> #include <pretty_printing.h> +#include <support/string.h> #include <wasm-stack.h> #include <wasm-type-printing.h> #include <wasm.h> @@ -51,75 +52,10 @@ bool isFullForced() { return false; } -std::ostream& printEscapedString(std::ostream& os, std::string_view str) { - os << '"'; - for (unsigned char c : str) { - switch (c) { - case '\t': - os << "\\t"; - break; - case '\n': - os << "\\n"; - break; - case '\r': - os << "\\r"; - break; - case '"': - os << "\\\""; - break; - case '\'': - os << "\\'"; - break; - case '\\': - os << "\\\\"; - break; - default: { - if (c >= 32 && c < 127) { - os << c; - } else { - os << std::hex << '\\' << (c / 16) << (c % 16) << std::dec; - } - } - } - } - return os << '"'; -} - -// TODO: Use unicode rather than char. -bool isIDChar(char c) { - if ('0' <= c && c <= '9') { - return true; - } - if ('A' <= c && c <= 'Z') { - return true; - } - if ('a' <= c && c <= 'z') { - return true; - } - static std::array<char, 23> otherIDChars = { - {'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '/', ':', - '<', '=', '>', '?', '@', '\\', '^', '_', '`', '|', '~'}}; - return std::find(otherIDChars.begin(), otherIDChars.end(), c) != - otherIDChars.end(); -} - -std::ostream& printName(Name name, std::ostream& o) { - assert(name && "Cannot print an empty name"); - // We need to quote names if they have tricky chars. - // TODO: This is not spec-compliant since the spec does not yet support quoted - // identifiers and has a limited set of valid idchars. - o << '$'; - if (std::all_of(name.str.begin(), name.str.end(), isIDChar)) { - return o << name.str; - } else { - return printEscapedString(o, name.str); - } -} - std::ostream& printMemoryName(Name name, std::ostream& o, Module* wasm) { if (!wasm || wasm->memories.size() > 1) { o << ' '; - printName(name, o); + name.print(o); } return o; } @@ -132,7 +68,7 @@ std::ostream& printLocal(Index index, Function* func, std::ostream& o) { if (!name) { name = Name::fromInt(index); } - return printName(name, o); + return name.print(o); } // Print a name from the type section, if available. Otherwise print the type @@ -246,7 +182,7 @@ struct PrintSExpression : public UnifiedExpressionVisitor<PrintSExpression> { if (type.isBasic()) { return o << type; } - return o << '$' << typePrinter.getNames(type).name; + return typePrinter.getNames(type).name.print(o); } std::ostream& printPrefixedTypes(const char* prefix, Type type); @@ -413,7 +349,7 @@ struct PrintExpressionContents printMedium(o, "block"); if (curr->name.is()) { o << ' '; - printName(curr->name, o); + curr->name.print(o); } if (curr->type.isConcrete()) { o << ' '; @@ -431,7 +367,7 @@ struct PrintExpressionContents printMedium(o, "loop"); if (curr->name.is()) { o << ' '; - printName(curr->name, o); + curr->name.print(o); } if (curr->type.isConcrete()) { o << ' '; @@ -444,16 +380,16 @@ struct PrintExpressionContents } else { printMedium(o, "br "); } - printName(curr->name, o); + curr->name.print(o); } void visitSwitch(Switch* curr) { printMedium(o, "br_table"); for (auto& t : curr->targets) { o << ' '; - printName(t, o); + t.print(o); } o << ' '; - printName(curr->default_, o); + curr->default_.print(o); } void visitCall(Call* curr) { if (curr->isReturn) { @@ -461,7 +397,7 @@ struct PrintExpressionContents } else { printMedium(o, "call "); } - printName(curr->target, o); + curr->target.print(o); } void visitCallIndirect(CallIndirect* curr) { if (curr->isReturn) { @@ -471,7 +407,7 @@ struct PrintExpressionContents } if (features.hasReferenceTypes()) { - printName(curr->table, o); + curr->table.print(o); o << ' '; } @@ -496,11 +432,11 @@ struct PrintExpressionContents } void visitGlobalGet(GlobalGet* curr) { printMedium(o, "global.get "); - printName(curr->name, o); + curr->name.print(o); } void visitGlobalSet(GlobalSet* curr) { printMedium(o, "global.set "); - printName(curr->name, o); + curr->name.print(o); } void visitLoad(Load* curr) { prepareColor(o) << forceConcrete(curr->type); @@ -871,13 +807,15 @@ struct PrintExpressionContents o << "memory.init"; restoreNormalColor(o); printMemoryName(curr->memory, o, wasm); - o << " $" << curr->segment; + o << ' '; + curr->segment.print(o); } void visitDataDrop(DataDrop* curr) { prepareColor(o); o << "data.drop"; restoreNormalColor(o); - o << " $" << curr->segment; + o << ' '; + curr->segment.print(o); } void visitMemoryCopy(MemoryCopy* curr) { prepareColor(o); @@ -1952,40 +1890,40 @@ struct PrintExpressionContents void visitRefIsNull(RefIsNull* curr) { printMedium(o, "ref.is_null"); } void visitRefFunc(RefFunc* curr) { printMedium(o, "ref.func "); - printName(curr->func, o); + curr->func.print(o); } void visitRefEq(RefEq* curr) { printMedium(o, "ref.eq"); } void visitTableGet(TableGet* curr) { printMedium(o, "table.get "); - printName(curr->table, o); + curr->table.print(o); } void visitTableSet(TableSet* curr) { printMedium(o, "table.set "); - printName(curr->table, o); + curr->table.print(o); } void visitTableSize(TableSize* curr) { printMedium(o, "table.size "); - printName(curr->table, o); + curr->table.print(o); } void visitTableGrow(TableGrow* curr) { printMedium(o, "table.grow "); - printName(curr->table, o); + curr->table.print(o); } void visitTableFill(TableFill* curr) { printMedium(o, "table.fill "); - printName(curr->table, o); + curr->table.print(o); } void visitTableCopy(TableCopy* curr) { printMedium(o, "table.copy "); - printName(curr->destTable, o); + curr->destTable.print(o); o << ' '; - printName(curr->sourceTable, o); + curr->sourceTable.print(o); } void visitTry(Try* curr) { printMedium(o, "try"); if (curr->name.is()) { o << ' '; - printName(curr->name, o); + curr->name.print(o); } if (curr->type.isConcrete()) { o << ' '; @@ -2002,22 +1940,22 @@ struct PrintExpressionContents o << " ("; if (curr->catchTags[i]) { printMedium(o, curr->catchRefs[i] ? "catch_ref " : "catch "); - printName(curr->catchTags[i], o); + curr->catchTags[i].print(o); o << ' '; } else { printMedium(o, curr->catchRefs[i] ? "catch_all_ref " : "catch_all "); } - printName(curr->catchDests[i], o); + curr->catchDests[i].print(o); o << ')'; } } void visitThrow(Throw* curr) { printMedium(o, "throw "); - printName(curr->tag, o); + curr->tag.print(o); } void visitRethrow(Rethrow* curr) { printMedium(o, "rethrow "); - printName(curr->target, o); + curr->target.print(o); } void visitThrowRef(ThrowRef* curr) { printMedium(o, "throw_ref"); } void visitNop(Nop* curr) { printMinor(o, "nop"); } @@ -2087,15 +2025,15 @@ struct PrintExpressionContents switch (curr->op) { case BrOnNull: printMedium(o, "br_on_null "); - printName(curr->name, o); + curr->name.print(o); return; case BrOnNonNull: printMedium(o, "br_on_non_null "); - printName(curr->name, o); + curr->name.print(o); return; case BrOnCast: printMedium(o, "br_on_cast "); - printName(curr->name, o); + curr->name.print(o); o << ' '; printType(curr->ref->type); o << ' '; @@ -2103,7 +2041,7 @@ struct PrintExpressionContents return; case BrOnCastFail: printMedium(o, "br_on_cast_fail "); - printName(curr->name, o); + curr->name.print(o); o << ' '; printType(curr->ref->type); o << ' '; @@ -2126,7 +2064,7 @@ struct PrintExpressionContents void printFieldName(HeapType type, Index index) { auto names = parent.typePrinter.getNames(type).fieldNames; if (auto it = names.find(index); it != names.end()) { - o << '$' << it->second; + it->second.print(o); } else { o << index; } @@ -2178,7 +2116,8 @@ struct PrintExpressionContents printMedium(o, "array.new_data"); o << ' '; printHeapType(curr->type.getHeapType()); - o << " $" << curr->segment; + o << ' '; + curr->segment.print(o); } void visitArrayNewElem(ArrayNewElem* curr) { if (printUnreachableReplacement(curr)) { @@ -2187,7 +2126,8 @@ struct PrintExpressionContents printMedium(o, "array.new_elem"); o << ' '; printHeapType(curr->type.getHeapType()); - o << " $" << curr->segment; + o << ' '; + curr->segment.print(o); } void visitArrayNewFixed(ArrayNewFixed* curr) { if (printUnreachableReplacement(curr)) { @@ -2246,7 +2186,8 @@ struct PrintExpressionContents } printMedium(o, "array.init_data "); printHeapType(curr->ref->type.getHeapType()); - o << " $" << curr->segment; + o << ' '; + curr->segment.print(o); } void visitArrayInitElem(ArrayInitElem* curr) { if (printUnreachableOrNullReplacement(curr->ref)) { @@ -2254,7 +2195,8 @@ struct PrintExpressionContents } printMedium(o, "array.init_elem "); printHeapType(curr->ref->type.getHeapType()); - o << " $" << curr->segment; + o << ' '; + curr->segment.print(o); } void visitRefAs(RefAs* curr) { switch (curr->op) { @@ -2314,7 +2256,7 @@ struct PrintExpressionContents } void visitStringConst(StringConst* curr) { printMedium(o, "string.const "); - printEscapedString(o, curr->string.str); + String::printEscaped(o, curr->string.str); } void visitStringMeasure(StringMeasure* curr) { switch (curr->op) { @@ -2448,9 +2390,9 @@ struct PrintExpressionContents for (Index i = 0; i < curr->handlerTags.size(); i++) { o << " ("; printMedium(o, "tag "); - printName(curr->handlerTags[i], o); + curr->handlerTags[i].print(o); o << ' '; - printName(curr->handlerBlocks[i], o); + curr->handlerBlocks[i].print(o); o << ')'; } } @@ -2754,7 +2696,7 @@ void PrintSExpression::visitTry(Try* curr) { printDebugDelimiterLocation(curr, i); o << '('; printMedium(o, "catch "); - printName(curr->catchTags[i], o); + curr->catchTags[i].print(o); incIndent(); maybePrintImplicitBlock(curr->catchBodies[i]); decIndent(); @@ -2779,7 +2721,7 @@ void PrintSExpression::visitTry(Try* curr) { if (curr->delegateTarget == DELEGATE_CALLER_TARGET) { o << controlFlowDepth; } else { - printName(curr->delegateTarget, o); + curr->delegateTarget.print(o); } o << ")\n"; } @@ -2866,7 +2808,8 @@ void PrintSExpression::handleSignature(HeapType curr, Name name) { Signature sig = curr.getSignature(); o << "(func"; if (name.is()) { - o << " $" << name; + o << ' '; + name.print(o); if (currModule && currModule->features.hasGC()) { o << " (type "; printHeapType(curr) << ')'; @@ -2922,7 +2865,7 @@ void PrintSExpression::visitExport(Export* curr) { WASM_UNREACHABLE("invalid ExternalKind"); } o << ' '; - printName(curr->value, o) << "))"; + curr->value.print(o) << "))"; } void PrintSExpression::emitImportHeader(Importable* curr) { @@ -2954,7 +2897,7 @@ void PrintSExpression::visitImportedGlobal(Global* curr) { o << '('; emitImportHeader(curr); o << "(global "; - printName(curr->name, o) << ' '; + curr->name.print(o) << ' '; emitGlobalType(curr); o << "))" << maybeNewLine; } @@ -2963,7 +2906,7 @@ void PrintSExpression::visitDefinedGlobal(Global* curr) { doIndent(o, indent); o << '('; printMedium(o, "global "); - printName(curr->name, o) << ' '; + curr->name.print(o) << ' '; emitGlobalType(curr); o << ' '; visit(curr->init); @@ -2999,7 +2942,7 @@ void PrintSExpression::visitDefinedFunction(Function* curr) { } o << '('; printMajor(o, "func "); - printName(curr->name, o); + curr->name.print(o); if (currModule && currModule->features.hasGC()) { o << " (type "; printHeapType(curr->type) << ')'; @@ -3080,7 +3023,7 @@ void PrintSExpression::visitImportedTag(Tag* curr) { o << '('; emitImportHeader(curr); o << "(tag "; - printName(curr->name, o); + curr->name.print(o); if (curr->sig.params != Type::none) { o << maybeSpace; printParamType(curr->sig.params); @@ -3097,7 +3040,7 @@ void PrintSExpression::visitDefinedTag(Tag* curr) { doIndent(o, indent); o << '('; printMedium(o, "tag "); - printName(curr->name, o); + curr->name.print(o); if (curr->sig.params != Type::none) { o << maybeSpace; printParamType(curr->sig.params); @@ -3112,7 +3055,7 @@ void PrintSExpression::visitDefinedTag(Tag* curr) { void PrintSExpression::printTableHeader(Table* curr) { o << '('; printMedium(o, "table") << ' '; - printName(curr->name, o) << ' '; + curr->name.print(o) << ' '; o << curr->initial; if (curr->hasMax()) { o << ' ' << curr->max; @@ -3148,13 +3091,13 @@ void PrintSExpression::visitElementSegment(ElementSegment* curr) { doIndent(o, indent); o << '('; printMedium(o, "elem "); - printName(curr->name, o); + curr->name.print(o); if (curr->table.is()) { if (usesExpressions || currModule->tables.size() > 1) { // tableuse o << " (table "; - printName(curr->table, o); + curr->table.print(o); o << ")"; } @@ -3174,7 +3117,7 @@ void PrintSExpression::visitElementSegment(ElementSegment* curr) { for (auto* entry : curr->data) { auto* refFunc = entry->cast<RefFunc>(); o << ' '; - printName(refFunc->func, o); + refFunc->func.print(o); } } else { for (auto* entry : curr->data) { @@ -3188,7 +3131,7 @@ void PrintSExpression::visitElementSegment(ElementSegment* curr) { void PrintSExpression::printMemoryHeader(Memory* curr) { o << '('; printMedium(o, "memory") << ' '; - printName(curr->name, o) << ' '; + curr->name.print(o) << ' '; if (curr->is64()) { o << "i64 "; } @@ -3220,17 +3163,19 @@ void PrintSExpression::visitDataSegment(DataSegment* curr) { doIndent(o, indent); o << '('; printMajor(o, "data "); - printName(curr->name, o); + curr->name.print(o); o << ' '; if (!curr->isPassive) { assert(!currModule || currModule->memories.size() > 0); if (!currModule || curr->memory != currModule->memories[0]->name) { - o << "(memory $" << curr->memory << ") "; + o << "(memory "; + curr->memory.print(o); + o << ") "; } visit(curr->offset); o << ' '; } - printEscapedString(o, {curr->data.data(), curr->data.size()}); + String::printEscaped(o, {curr->data.data(), curr->data.size()}); o << ')' << maybeNewLine; } @@ -3259,7 +3204,7 @@ void PrintSExpression::visitModule(Module* curr) { printMajor(o, "module"); if (curr->name.is()) { o << ' '; - printName(curr->name, o); + curr->name.print(o); } incIndent(); @@ -3320,7 +3265,7 @@ void PrintSExpression::visitModule(Module* curr) { o << " declare func"; for (auto name : elemDeclareNames) { o << ' '; - printName(name, o); + name.print(o); } o << ')' << maybeNewLine; } @@ -3334,7 +3279,7 @@ void PrintSExpression::visitModule(Module* curr) { doIndent(o, indent); o << '('; printMedium(o, "start") << ' '; - printName(curr->start, o) << ')'; + curr->start.print(o) << ')'; o << maybeNewLine; } ModuleUtils::iterDefinedFunctions( @@ -3508,7 +3453,7 @@ printStackInst(StackInst* inst, std::ostream& o, Function* func) { } case StackInst::Delegate: { printMedium(o, "delegate "); - printName(inst->origin->cast<Try>()->delegateTarget, o); + inst->origin->cast<Try>()->delegateTarget.print(o); break; } default: @@ -3580,7 +3525,7 @@ static std::ostream& printStackIR(StackIR* ir, PrintSExpression& printer) { doIndent(); printMedium(o, "catch "); Try* curr = inst->origin->cast<Try>(); - printName(curr->catchTags[catchIndexStack.back()++], o); + curr->catchTags[catchIndexStack.back()++].print(o); indent++; break; } @@ -3600,7 +3545,7 @@ static std::ostream& printStackIR(StackIR* ir, PrintSExpression& printer) { if (curr->delegateTarget == DELEGATE_CALLER_TARGET) { o << controlFlowDepth; } else { - printName(curr->delegateTarget, o); + curr->delegateTarget.print(o); } break; } diff --git a/src/support/CMakeLists.txt b/src/support/CMakeLists.txt index 13bf463e4..54ee7b206 100644 --- a/src/support/CMakeLists.txt +++ b/src/support/CMakeLists.txt @@ -9,8 +9,10 @@ set(support_SOURCES file.cpp istring.cpp json.cpp + name.cpp path.cpp safe_integer.cpp + string.cpp threads.cpp utilities.cpp ${support_HEADERS} diff --git a/src/support/name.cpp b/src/support/name.cpp new file mode 100644 index 000000000..4e53e3f83 --- /dev/null +++ b/src/support/name.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <algorithm> +#include <array> + +#include "support/name.h" +#include "support/string.h" + +namespace wasm { + +// TODO: Use unicode rather than char. +bool Name::isIDChar(char c) { + if ('0' <= c && c <= '9') { + return true; + } + if ('A' <= c && c <= 'Z') { + return true; + } + if ('a' <= c && c <= 'z') { + return true; + } + static std::array<char, 23> otherIDChars = { + {'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '/', ':', + '<', '=', '>', '?', '@', '\\', '^', '_', '`', '|', '~'}}; + return std::find(otherIDChars.begin(), otherIDChars.end(), c) != + otherIDChars.end(); +} + +std::ostream& Name::print(std::ostream& o) const { + assert(*this && "Cannot print an empty name"); + // We need to quote names if they have tricky chars. + // TODO: This is not spec-compliant since the spec does not yet support + // quoted identifiers and has a limited set of valid idchars. + o << '$'; + if (std::all_of(str.begin(), str.end(), isIDChar)) { + return o << str; + } else { + return String::printEscaped(o, str); + } +} + +} // namespace wasm diff --git a/src/support/name.h b/src/support/name.h index a22461d5d..8e3f7a291 100644 --- a/src/support/name.h +++ b/src/support/name.h @@ -58,6 +58,11 @@ struct Name : public IString { // TODO: Use C++23 `contains`. return str.find(substring.str) != std::string_view::npos; } + + std::ostream& print(std::ostream& o) const; + +private: + static bool isIDChar(char c); }; } // namespace wasm diff --git a/src/support/string.cpp b/src/support/string.cpp new file mode 100644 index 000000000..c7f8a5ff6 --- /dev/null +++ b/src/support/string.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ostream> + +#include "support/string.h" + +namespace wasm::String { + +std::ostream& printEscaped(std::ostream& os, std::string_view str) { + os << '"'; + for (unsigned char c : str) { + switch (c) { + case '\t': + os << "\\t"; + break; + case '\n': + os << "\\n"; + break; + case '\r': + os << "\\r"; + break; + case '"': + os << "\\\""; + break; + case '\'': + os << "\\'"; + break; + case '\\': + os << "\\\\"; + break; + default: { + if (c >= 32 && c < 127) { + os << c; + } else { + os << std::hex << '\\' << (c / 16) << (c % 16) << std::dec; + } + } + } + } + return os << '"'; +} + +} // namespace wasm::String diff --git a/src/support/string.h b/src/support/string.h index 751efdac5..6fe3faf60 100644 --- a/src/support/string.h +++ b/src/support/string.h @@ -24,6 +24,7 @@ #include "support/utilities.h" #include <algorithm> #include <cctype> +#include <ostream> #include <string> #include <vector> @@ -152,6 +153,8 @@ inline bool isNumber(const std::string& str) { return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit); } +std::ostream& printEscaped(std::ostream& os, std::string_view str); + } // namespace wasm::String #endif // wasm_support_string_h diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index f1ceca51a..31042835c 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -1788,7 +1788,7 @@ void TypePrinter::printHeapTypeName(HeapType type) { print(type); return; } - os << '$' << generator(type).name; + generator(type).name.print(os); #if TRACE_CANONICALIZATION os << "(;" << ((type.getID() >> 4) % 1000) << ";) "; #endif @@ -1915,7 +1915,8 @@ std::ostream& TypePrinter::print(HeapType type) { auto names = generator(type); - os << "(type $" << names.name << ' '; + os << "(type "; + names.name.print(os) << ' '; if (isTemp(type)) { os << "(; temp ;) "; @@ -2018,7 +2019,7 @@ TypePrinter::print(const Struct& struct_, // TODO: move this to the function for printing fields. os << " (field "; if (auto it = fieldNames.find(i); it != fieldNames.end()) { - os << '$' << it->second << ' '; + it->second.print(os) << ' '; } print(struct_.fields[i]); os << ')'; diff --git a/test/lit/ctor-eval/array_new_data.wast b/test/lit/ctor-eval/array_new_data.wast index 90551862d..c82fb22fa 100644 --- a/test/lit/ctor-eval/array_new_data.wast +++ b/test/lit/ctor-eval/array_new_data.wast @@ -4,8 +4,8 @@ (module ;; CHECK: (type $0 (func)) - ;; CHECK: (type $[i8] (array i8)) - (type $[i8] (array i8)) + ;; CHECK: (type $"[i8]" (array i8)) + (type $"[i8]" (array i8)) ;; CHECK: (memory $0 16 17 shared) (memory $0 16 17 shared) @@ -18,7 +18,7 @@ ;; CHECK: (func $test (type $0) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (array.new_data $[i8] $1 + ;; CHECK-NEXT: (array.new_data $"[i8]" $1 ;; CHECK-NEXT: (i32.const 16) ;; CHECK-NEXT: (i32.const 8) ;; CHECK-NEXT: ) @@ -29,7 +29,7 @@ ;; atm. In fact the module would not validate as we refer to segment 1 here ;; but after flattening only segment 0 exists. (drop - (array.new_data $[i8] $1 + (array.new_data $"[i8]" $1 (i32.const 16) (i32.const 8) ) diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast index 51e97456c..78b732a3f 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -2,22 +2,22 @@ ;; RUN: wasm-opt %s -all --dae -S -o - | filecheck %s (module - ;; CHECK: (type ${} (sub (struct ))) - (type ${} (sub (struct))) + ;; CHECK: (type $"{}" (sub (struct ))) + (type $"{}" (sub (struct))) - ;; CHECK: (type ${i32} (sub ${} (struct (field i32)))) - (type ${i32} (sub ${} (struct (field i32)))) + ;; CHECK: (type $"{i32}" (sub $"{}" (struct (field i32)))) + (type $"{i32}" (sub $"{}" (struct (field i32)))) - ;; CHECK: (type ${i32_i64} (sub ${i32} (struct (field i32) (field i64)))) + ;; CHECK: (type $"{i32_i64}" (sub $"{i32}" (struct (field i32) (field i64)))) - ;; CHECK: (type ${i32_f32} (sub ${i32} (struct (field i32) (field f32)))) + ;; CHECK: (type $"{i32_f32}" (sub $"{i32}" (struct (field i32) (field f32)))) - ;; CHECK: (type ${f64} (sub ${} (struct (field f64)))) - (type ${f64} (sub ${} (struct (field f64)))) + ;; CHECK: (type $"{f64}" (sub $"{}" (struct (field f64)))) + (type $"{f64}" (sub $"{}" (struct (field f64)))) - (type ${i32_i64} (sub ${i32} (struct (field i32) (field i64)))) + (type $"{i32_i64}" (sub $"{i32}" (struct (field i32) (field i64)))) - (type ${i32_f32} (sub ${i32} (struct (field i32) (field f32)))) + (type $"{i32_f32}" (sub $"{i32}" (struct (field i32) (field f32)))) ;; CHECK: (func $call-various-params-no (type $0) ;; CHECK-NEXT: (call $various-params-no @@ -35,17 +35,17 @@ ;; all nulls are identical and we could do other optimization work due to ;; that. (call $various-params-no - (call $get_{}) - (call $get_{i32}) + (call $"get_{}") + (call $"get_{i32}") ) (call $various-params-no - (call $get_{i32}) - (call $get_{f64}) + (call $"get_{i32}") + (call $"get_{f64}") ) ) ;; This function is called in ways that do not allow us to alter the types of ;; its parameters (see last function). - ;; CHECK: (func $various-params-no (type $7) (param $x (ref null ${})) (param $y (ref null ${})) + ;; CHECK: (func $various-params-no (type $7) (param $x (ref null $"{}")) (param $y (ref null $"{}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) @@ -53,19 +53,28 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $various-params-no (param $x (ref null ${})) (param $y (ref null ${})) + (func $various-params-no (param $x (ref null $"{}")) (param $y (ref null $"{}")) ;; "Use" the locals to avoid other optimizations kicking in. (drop (local.get $x)) (drop (local.get $y)) ) - (func $get_{} (result (ref null ${})) + ;; CHECK: (func $"get_{}" (type $8) (result (ref null $"{}")) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $"get_{}" (result (ref null $"{}")) (unreachable) ) - (func $get_{i32} (result (ref null ${i32})) + ;; CHECK: (func $"get_{i32}" (type $5) (result (ref null $"{i32}")) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $"get_{i32}" (result (ref null $"{i32}")) (unreachable) ) - (func $get_{f64} (result (ref null ${f64})) + ;; CHECK: (func $"get_{f64}" (type $10) (result (ref null $"{f64}")) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $"get_{f64}" (result (ref null $"{f64}")) (unreachable) ) @@ -86,19 +95,19 @@ ;; both of those pairs can be optimized to {i32}. ;; There is also an i32 in the middle, which should not confuse us. (call $various-params-yes - (call $get_null_{i32}) + (call $"get_null_{i32}") (i32.const 0) - (call $get_null_{i32}) + (call $"get_null_{i32}") ) (call $various-params-yes - (call $get_null_{i32}) + (call $"get_null_{i32}") (i32.const 1) - (call $get_null_{i32_i64}) + (call $"get_null_{i32_i64}") ) ) ;; This function is called in ways that *do* allow us to alter the types of ;; its parameters (see last function). - ;; CHECK: (func $various-params-yes (type $11) (param $x (ref null ${i32})) (param $i i32) (param $y (ref null ${i32})) + ;; CHECK: (func $various-params-yes (type $11) (param $x (ref null $"{i32}")) (param $i i32) (param $y (ref null $"{i32}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) @@ -109,7 +118,7 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $various-params-yes (param $x (ref null ${})) (param $i i32) (param $y (ref null ${})) + (func $various-params-yes (param $x (ref null $"{}")) (param $i i32) (param $y (ref null $"{}")) ;; "Use" the locals to avoid other optimizations kicking in. (drop (local.get $x)) (drop (local.get $i)) @@ -130,19 +139,19 @@ ;; The first argument gets {i32} and {i32}; the second {i32} and {i32_i64; ;; both of those pairs can be optimized to {i32} (call $various-params-set - (call $get_null_{i32}) - (call $get_null_{i32}) + (call $"get_null_{i32}") + (call $"get_null_{i32}") ) (call $various-params-set - (call $get_null_{i32}) - (call $get_null_{i32_i64}) + (call $"get_null_{i32}") + (call $"get_null_{i32_i64}") ) ) ;; This function is called in ways that *do* allow us to alter the types of ;; its parameters (see last function), however, we reuse the parameters by ;; writing to them, which causes problems in one case. - ;; CHECK: (func $various-params-set (type $12) (param $x (ref null ${i32})) (param $y (ref null ${i32})) - ;; CHECK-NEXT: (local $2 (ref null ${})) + ;; CHECK: (func $various-params-set (type $12) (param $x (ref null $"{i32}")) (param $y (ref null $"{i32}")) + ;; CHECK-NEXT: (local $2 (ref null $"{}")) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) @@ -154,7 +163,7 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (struct.new_default ${}) + ;; CHECK-NEXT: (struct.new_default $"{}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) @@ -167,7 +176,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $various-params-set (param $x (ref null ${})) (param $y (ref null ${})) + (func $various-params-set (param $x (ref null $"{}")) (param $y (ref null $"{}")) ;; "Use" the locals to avoid other optimizations kicking in. (drop (local.get $x)) (drop (local.get $y)) @@ -175,13 +184,13 @@ ;; force us to do a fixup: the param will get the new type, and a new local ;; will stay at the old type, and we will use that local throughout the ;; function. - (local.set $x (struct.new ${})) + (local.set $x (struct.new $"{}")) (drop (local.get $x) ) ;; Write to $y in a way that does not cause any issue, and we should not do ;; any fixup while we refine the type. - (local.set $y (call $get_null_{i32_i64})) + (local.set $y (call $"get_null_{i32_i64}")) (drop (local.get $y) ) @@ -195,30 +204,30 @@ (func $call-various-params-tee ;; The argument gets {i32}, which allows us to refine. (call $various-params-tee - (call $get_null_{i32}) + (call $"get_null_{i32}") ) ) - ;; CHECK: (func $various-params-tee (type $6) (param $x (ref null ${i32})) + ;; CHECK: (func $various-params-tee (type $6) (param $x (ref null $"{i32}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null ${i32})) + ;; CHECK-NEXT: (block (result (ref null $"{i32}")) ;; CHECK-NEXT: (local.tee $x ;; CHECK-NEXT: (call $"get_null_{i32_i64}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $various-params-tee (param $x (ref null ${})) + (func $various-params-tee (param $x (ref null $"{}")) ;; "Use" the locals to avoid other optimizations kicking in. (drop (local.get $x)) ;; Write to $x in a way that allows us to make the type more specific. We ;; must also update the type of the tee (if we do not, a validation error ;; would occur), and that will also cause the block's type to update as well. (drop - (block (result (ref null ${})) - (local.tee $x (call $get_null_{i32_i64})) + (block (result (ref null $"{}")) + (local.tee $x (call $"get_null_{i32_i64}")) ) ) ) @@ -243,17 +252,17 @@ ;; The first argument gets non-null values, allowing us to refine it. The ;; second gets only one. (call $various-params-null - (ref.as_non_null (ref.null ${i32})) - (call $get_null_{i32}) + (ref.as_non_null (ref.null $"{i32}")) + (call $"get_null_{i32}") ) (call $various-params-null - (ref.as_non_null (ref.null ${i32})) - (ref.as_non_null (ref.null ${i32})) + (ref.as_non_null (ref.null $"{i32}")) + (ref.as_non_null (ref.null $"{i32}")) ) ) ;; This function is called in ways that allow us to make the first parameter ;; non-nullable. - ;; CHECK: (func $various-params-null (type $13) (param $x (ref none)) (param $y (ref null ${i32})) + ;; CHECK: (func $various-params-null (type $13) (param $x (ref none)) (param $y (ref null $"{i32}")) ;; CHECK-NEXT: (local $temp i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) @@ -265,7 +274,7 @@ ;; CHECK-NEXT: (local.get $temp) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $various-params-null (param $x (ref null ${})) (param $y (ref null ${})) + (func $various-params-null (param $x (ref null $"{}")) (param $y (ref null $"{}")) (local $temp i32) ;; "Use" the locals to avoid other optimizations kicking in. (drop (local.get $x)) @@ -289,18 +298,18 @@ ;; The argument gets {i32_i64} and {i32_f32}. This allows us to refine from ;; {} to {i32}, a type "in the middle". (call $various-params-middle - (call $get_null_{i32_i64}) + (call $"get_null_{i32_i64}") ) (call $various-params-middle - (call $get_null_{i32_f32}) + (call $"get_null_{i32_f32}") ) ) - ;; CHECK: (func $various-params-middle (type $6) (param $x (ref null ${i32})) + ;; CHECK: (func $various-params-middle (type $6) (param $x (ref null $"{i32}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $various-params-middle (param $x (ref null ${})) + (func $various-params-middle (param $x (ref null $"{}")) ;; "Use" the local to avoid other optimizations kicking in. (drop (local.get $x)) ) @@ -310,14 +319,14 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $unused-and-refinable (param $0 structref) - ;; This function does not use $0. It is called with ${}, so it is also + ;; This function does not use $0. It is called with $"{}", so it is also ;; a parameter whose type we can refine. Do not do both operations: instead, ;; just remove it because it is ignored, without altering the type (handling ;; both operations would introduce some corner cases, and it just isn't worth ;; handling them if the param is completely unused anyhow). We should see in ;; the test output that the local $0 (the unused param) becomes a local ;; because it is unused, and that local does *not* have its type refined to - ;; ${} (it will however be changed to be nullable, which it must be as a + ;; $"{}" (it will however be changed to be nullable, which it must be as a ;; local). ) @@ -326,11 +335,11 @@ ;; CHECK-NEXT: ) (func $call-unused-and-refinable (call $unused-and-refinable - (struct.new_default ${}) + (struct.new_default $"{}") ) ) - ;; CHECK: (func $non-nullable-fixup (type $14) (param $0 (ref ${})) + ;; CHECK: (func $non-nullable-fixup (type $14) (param $0 (ref $"{}")) ;; CHECK-NEXT: (local $1 structref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $0) @@ -350,12 +359,12 @@ ;; CHECK: (func $call-non-nullable-fixup (type $0) ;; CHECK-NEXT: (call $non-nullable-fixup - ;; CHECK-NEXT: (struct.new_default ${}) + ;; CHECK-NEXT: (struct.new_default $"{}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-non-nullable-fixup (call $non-nullable-fixup - (struct.new_default ${}) + (struct.new_default $"{}") ) ) @@ -364,7 +373,7 @@ ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $update-null - ;; CHECK-NEXT: (struct.new_default ${}) + ;; CHECK-NEXT: (struct.new_default $"{}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $call-update-null @@ -374,44 +383,65 @@ (ref.null any) ) (call $update-null - (struct.new_default ${}) + (struct.new_default $"{}") ) ) - ;; CHECK: (func $update-null (type $15) (param $x (ref null ${})) + ;; CHECK: (func $update-null (type $15) (param $x (ref null $"{}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $update-null (param $x (ref null any)) ;; "Use" the param to avoid other optimizations kicking in. We should only - ;; see the type of the param refined to a null ${} after updating the null + ;; see the type of the param refined to a null $"{}" after updating the null ;; in the caller. (drop (local.get $x)) ) - (func $get_null_{i32} (result (ref null ${i32})) - ;; Helper function that returns a null value of ${i32}. We use this instead of + ;; CHECK: (func $"get_null_{i32}" (type $5) (result (ref null $"{i32}")) + ;; CHECK-NEXT: (select (result (ref null $"{i32}")) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (struct.new_default $"{i32}") + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $"get_null_{i32}" (result (ref null $"{i32}")) + ;; Helper function that returns a null value of $"{i32}." We use this instead of ;; a direct ref.null because those can be rewritten by LUBFinder. (select (ref.null none) - (struct.new_default ${i32}) + (struct.new_default $"{i32}") (i32.const 0) ) ) - (func $get_null_{i32_i64} (result (ref null ${i32_i64})) + ;; CHECK: (func $"get_null_{i32_i64}" (type $16) (result (ref null $"{i32_i64}")) + ;; CHECK-NEXT: (select (result (ref null $"{i32_i64}")) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (struct.new_default $"{i32_i64}") + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $"get_null_{i32_i64}" (result (ref null $"{i32_i64}")) (select (ref.null none) - (struct.new_default ${i32_i64}) + (struct.new_default $"{i32_i64}") (i32.const 0) ) ) - (func $get_null_{i32_f32} (result (ref null ${i32_f32})) + ;; CHECK: (func $"get_null_{i32_f32}" (type $17) (result (ref null $"{i32_f32}")) + ;; CHECK-NEXT: (select (result (ref null $"{i32_f32}")) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (struct.new_default $"{i32_f32}") + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $"get_null_{i32_f32}" (result (ref null $"{i32_f32}")) (select (ref.null none) - (struct.new_default ${i32_f32}) + (struct.new_default $"{i32_f32}") (i32.const 0) ) ) diff --git a/test/lit/passes/dae-gc-refine-return.wast b/test/lit/passes/dae-gc-refine-return.wast index f478c2ff3..24ad4e61b 100644 --- a/test/lit/passes/dae-gc-refine-return.wast +++ b/test/lit/passes/dae-gc-refine-return.wast @@ -2,20 +2,20 @@ ;; RUN: wasm-opt %s -all --dae -S -o - | filecheck %s (module - ;; CHECK: (type ${} (sub (struct ))) - (type ${} (sub (struct))) + ;; CHECK: (type $"{}" (sub (struct ))) + (type $"{}" (sub (struct))) - ;; CHECK: (type $return_{} (func (result (ref ${})))) - (type $return_{} (func (result (ref ${})))) + ;; CHECK: (type $"return_{}" (func (result (ref $"{}")))) + (type $"return_{}" (func (result (ref $"{}")))) - ;; CHECK: (type ${i32} (sub ${} (struct (field i32)))) - (type ${i32} (sub ${} (struct (field i32)))) + ;; CHECK: (type $"{i32}" (sub $"{}" (struct (field i32)))) + (type $"{i32}" (sub $"{}" (struct (field i32)))) - ;; CHECK: (type ${i32_f32} (sub ${i32} (struct (field i32) (field f32)))) - (type ${i32_f32} (sub ${i32} (struct (field i32) (field f32)))) + ;; CHECK: (type $"{i32_f32}" (sub $"{i32}" (struct (field i32) (field f32)))) + (type $"{i32_f32}" (sub $"{i32}" (struct (field i32) (field f32)))) - ;; CHECK: (type ${i32_i64} (sub ${i32} (struct (field i32) (field i64)))) - (type ${i32_i64} (sub ${i32} (struct (field i32) (field i64)))) + ;; CHECK: (type $"{i32_i64}" (sub $"{i32}" (struct (field i32) (field i64)))) + (type $"{i32_i64}" (sub $"{i32}" (struct (field i32) (field i64)))) (table 1 1 funcref) @@ -315,13 +315,13 @@ ;; Show that we can optimize the return type of a function that does a tail ;; call. - ;; CHECK: (func $tail-callee (type $return_{}) (result (ref ${})) + ;; CHECK: (func $tail-callee (type $"return_{}") (result (ref $"{}")) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - (func $tail-callee (result (ref ${})) + (func $tail-callee (result (ref $"{}")) (unreachable) ) - ;; CHECK: (func $tail-caller-yes (type $return_{}) (result (ref ${})) + ;; CHECK: (func $tail-caller-yes (type $"return_{}") (result (ref $"{}")) ;; CHECK-NEXT: (return_call $tail-callee) ;; CHECK-NEXT: ) (func $tail-caller-yes (result anyref) @@ -372,19 +372,19 @@ ) ;; As above, but with an indirect tail call. - ;; CHECK: (func $tail-callee-indirect (type $return_{}) (result (ref ${})) + ;; CHECK: (func $tail-callee-indirect (type $"return_{}") (result (ref $"{}")) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - (func $tail-callee-indirect (result (ref ${})) + (func $tail-callee-indirect (result (ref $"{}")) (unreachable) ) - ;; CHECK: (func $tail-caller-indirect-yes (type $return_{}) (result (ref ${})) - ;; CHECK-NEXT: (return_call_indirect $0 (type $return_{}) + ;; CHECK: (func $tail-caller-indirect-yes (type $"return_{}") (result (ref $"{}")) + ;; CHECK-NEXT: (return_call_indirect $0 (type $"return_{}") ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $tail-caller-indirect-yes (result anyref) - (return_call_indirect (type $return_{}) (i32.const 0)) + (return_call_indirect (type $"return_{}") (i32.const 0)) ) ;; CHECK: (func $tail-caller-indirect-no (type $2) (result anyref) ;; CHECK-NEXT: (local $any anyref) @@ -396,7 +396,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (return_call_indirect $0 (type $return_{}) + ;; CHECK-NEXT: (return_call_indirect $0 (type $"return_{}") ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -408,7 +408,7 @@ (return (local.get $any)) ) ) - (return_call_indirect (type $return_{}) (i32.const 0)) + (return_call_indirect (type $"return_{}") (i32.const 0)) ) ;; CHECK: (func $tail-call-caller-indirect (type $4) ;; CHECK-NEXT: (drop @@ -428,26 +428,26 @@ ) ;; As above, but with a tail call by function reference. - ;; CHECK: (func $tail-callee-call_ref (type $return_{}) (result (ref ${})) + ;; CHECK: (func $tail-callee-call_ref (type $"return_{}") (result (ref $"{}")) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - (func $tail-callee-call_ref (result (ref ${})) + (func $tail-callee-call_ref (result (ref $"{}")) (unreachable) ) - ;; CHECK: (func $tail-caller-call_ref-yes (type $return_{}) (result (ref ${})) - ;; CHECK-NEXT: (local $"return_{}" (ref null $return_{})) - ;; CHECK-NEXT: (return_call_ref $return_{} + ;; CHECK: (func $tail-caller-call_ref-yes (type $"return_{}") (result (ref $"{}")) + ;; CHECK-NEXT: (local $"return_{}" (ref null $"return_{}")) + ;; CHECK-NEXT: (return_call_ref $"return_{}" ;; CHECK-NEXT: (local.get $"return_{}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $tail-caller-call_ref-yes (result anyref) - (local $return_{} (ref null $return_{})) + (local $"return_{}" (ref null $"return_{}")) - (return_call_ref $return_{} (local.get $return_{})) + (return_call_ref $"return_{}" (local.get $"return_{}")) ) ;; CHECK: (func $tail-caller-call_ref-no (type $2) (result anyref) ;; CHECK-NEXT: (local $any anyref) - ;; CHECK-NEXT: (local $"return_{}" (ref null $return_{})) + ;; CHECK-NEXT: (local $"return_{}" (ref null $"return_{}")) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (then @@ -456,20 +456,20 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (return_call_ref $return_{} + ;; CHECK-NEXT: (return_call_ref $"return_{}" ;; CHECK-NEXT: (local.get $"return_{}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $tail-caller-call_ref-no (result anyref) (local $any anyref) - (local $return_{} (ref null $return_{})) + (local $"return_{}" (ref null $"return_{}")) (if (i32.const 1) (then (return (local.get $any)) ) ) - (return_call_ref $return_{} (local.get $return_{})) + (return_call_ref $"return_{}" (local.get $"return_{}")) ) ;; CHECK: (func $tail-caller-call_ref-unreachable (type $2) (result anyref) ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) @@ -482,7 +482,7 @@ (func $tail-caller-call_ref-unreachable (result anyref) ;; An unreachable means there is no function signature to even look at. We ;; should not hit an assertion on such things. - (return_call_ref $return_{} (unreachable)) + (return_call_ref $"return_{}" (unreachable)) ) ;; CHECK: (func $tail-call-caller-call_ref (type $4) ;; CHECK-NEXT: (drop @@ -507,7 +507,7 @@ ) ) - ;; CHECK: (func $update-null (type $10) (param $x i32) (param $y i32) (result (ref null ${i32})) + ;; CHECK: (func $update-null (type $10) (param $x i32) (param $y i32) (result (ref null $"{i32}")) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (then @@ -515,7 +515,7 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: (then ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (struct.new_default ${i32_f32}) + ;; CHECK-NEXT: (struct.new_default $"{i32_f32}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else @@ -527,21 +527,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (else ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (struct.new_default ${i32_i64}) + ;; CHECK-NEXT: (struct.new_default $"{i32_i64}") ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $update-null (param $x i32) (param $y i32) (result anyref) ;; Of the three returns here, the null can be updated, and the LUB is - ;; determined by the other two, and is their shared parent ${}. + ;; determined by the other two, and is their shared parent $"{}." (if (local.get $x) (then (if (local.get $y) (then - (return (struct.new_default ${i32_f32})) + (return (struct.new_default $"{i32_f32}")) ) (else (return (ref.null any)) @@ -549,7 +549,7 @@ ) ) (else - (return (struct.new_default ${i32_i64})) + (return (struct.new_default $"{i32_i64}")) ) ) ) diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index 02a2462db..a5625b852 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -2,8 +2,8 @@ ;; RUN: foreach %s %t wasm-opt -all --dae -S -o - | filecheck %s (module - ;; CHECK: (type ${} (struct )) - (type ${} (struct)) + ;; CHECK: (type $"{}" (struct )) + (type $"{}" (struct)) ;; CHECK: (func $foo (type $0) ;; CHECK-NEXT: (call $bar) @@ -50,10 +50,10 @@ ;; A function that gets a non-nullable reference that is never used. We can ;; still create a non-nullable local for that parameter. ;; CHECK: (func $get-nonnull (type $0) - ;; CHECK-NEXT: (local $0 (ref ${})) + ;; CHECK-NEXT: (local $0 (ref $"{}")) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) - (func $get-nonnull (param $0 (ref ${})) + (func $get-nonnull (param $0 (ref $"{}")) (nop) ) ;; CHECK: (func $send-nonnull (type $0) @@ -61,7 +61,7 @@ ;; CHECK-NEXT: ) (func $send-nonnull (call $get-nonnull - (struct.new ${}) + (struct.new $"{}") ) ) ) diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast index ec4cc38df..bcc3f0463 100644 --- a/test/lit/passes/gto-removals.wast +++ b/test/lit/passes/gto-removals.wast @@ -796,21 +796,21 @@ (module ;; CHECK: (rec - ;; CHECK-NEXT: (type $0 (func (result (ref ${mut:i8})))) + ;; CHECK-NEXT: (type $0 (func (result (ref $"{mut:i8}")))) ;; CHECK: (type $1 (func (result i32))) ;; CHECK: (type $2 (func)) - ;; CHECK: (type ${mut:i8} (sub (struct ))) - (type ${mut:i8} (sub (struct (field (mut i8))))) + ;; CHECK: (type $"{mut:i8}" (sub (struct ))) + (type $"{mut:i8}" (sub (struct (field (mut i8))))) - ;; CHECK: (type $4 (func (param (ref null ${mut:i8})))) + ;; CHECK: (type $4 (func (param (ref null $"{mut:i8}")))) - ;; CHECK: (func $unreachable-set (type $4) (param $"{mut:i8}" (ref null ${mut:i8})) + ;; CHECK: (func $unreachable-set (type $4) (param $"{mut:i8}" (ref null $"{mut:i8}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref null ${mut:i8})) + ;; CHECK-NEXT: (block (result (ref null $"{mut:i8}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $helper-i32) ;; CHECK-NEXT: ) @@ -819,19 +819,19 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unreachable-set (param ${mut:i8} (ref null ${mut:i8})) + (func $unreachable-set (param $"{mut:i8}" (ref null $"{mut:i8}")) ;; The struct type has no reads, so we want to remove all of the sets of it. ;; This struct.set will trap on null, but first the call must run. When we ;; optimize here we should be careful to not emit something with different ;; ordering (naively emitting ref.as_non_null on the reference would trap ;; before the call, so we must reorder). - (struct.set ${mut:i8} 0 - (local.get ${mut:i8}) + (struct.set $"{mut:i8}" 0 + (local.get $"{mut:i8}") (call $helper-i32) ) ) - ;; CHECK: (func $unreachable-set-2 (type $4) (param $"{mut:i8}" (ref null ${mut:i8})) + ;; CHECK: (func $unreachable-set-2 (type $4) (param $"{mut:i8}" (ref null $"{mut:i8}")) ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null @@ -847,18 +847,18 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unreachable-set-2 (param ${mut:i8} (ref null ${mut:i8})) + (func $unreachable-set-2 (param $"{mut:i8}" (ref null $"{mut:i8}")) ;; As above, but the side effects now are a br. Again, the br must happen ;; before the trap (in fact, the br will skip the trap here). (block - (struct.set ${mut:i8} 0 - (local.get ${mut:i8}) + (struct.set $"{mut:i8}" 0 + (local.get $"{mut:i8}") (br $block) ) ) ) - ;; CHECK: (func $unreachable-set-2b (type $4) (param $"{mut:i8}" (ref null ${mut:i8})) + ;; CHECK: (func $unreachable-set-2b (type $4) (param $"{mut:i8}" (ref null $"{mut:i8}")) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null @@ -873,23 +873,23 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unreachable-set-2b (param ${mut:i8} (ref null ${mut:i8})) + (func $unreachable-set-2b (param $"{mut:i8}" (ref null $"{mut:i8}")) ;; As above, but with an unreachable instead of a br. We add a nop here so ;; that we are inside of a block, and then validation would fail if we do ;; not keep the type of the replacement for the struct.set identical to the ;; struct.set. That is, the type must remain unreachable. (nop) - (struct.set ${mut:i8} 0 - (local.get ${mut:i8}) + (struct.set $"{mut:i8}" 0 + (local.get $"{mut:i8}") (unreachable) ) ) ;; CHECK: (func $unreachable-set-3 (type $2) - ;; CHECK-NEXT: (local $0 (ref ${mut:i8})) + ;; CHECK-NEXT: (local $0 (ref $"{mut:i8}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref ${mut:i8})) + ;; CHECK-NEXT: (block (result (ref $"{mut:i8}")) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (call $helper-ref) ;; CHECK-NEXT: ) @@ -904,7 +904,7 @@ (func $unreachable-set-3 ;; As above, but now we have side effects in both children. (block - (struct.set ${mut:i8} 0 + (struct.set $"{mut:i8}" 0 (call $helper-ref) (call $helper-i32) ) @@ -918,10 +918,10 @@ (i32.const 1) ) - ;; CHECK: (func $helper-ref (type $0) (result (ref ${mut:i8})) + ;; CHECK: (func $helper-ref (type $0) (result (ref $"{mut:i8}")) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - (func $helper-ref (result (ref ${mut:i8})) + (func $helper-ref (result (ref $"{mut:i8}")) (unreachable) ) ) diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 168fcd0df..c2c9564ad 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -2207,12 +2207,12 @@ ) (module - ;; CHECK: (type ${} (sub (struct ))) - (type ${} (sub (struct))) + ;; CHECK: (type $"{}" (sub (struct ))) + (type $"{}" (sub (struct))) - ;; CHECK: (type $1 (func (result (ref ${})))) + ;; CHECK: (type $1 (func (result (ref $"{}")))) - ;; CHECK: (func $func (type $1) (result (ref ${})) + ;; CHECK: (func $func (type $1) (result (ref $"{}")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $block (result (ref none)) ;; CHECK-NEXT: (br_on_non_null $block @@ -2223,7 +2223,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - (func $func (result (ref ${})) + (func $func (result (ref $"{}")) ;; This block can only return a null in theory (in practice, not even that - ;; the br will not be taken, but this pass is not smart enough to see that). ;; We can optimize to an unreachable here, but must be careful - we cannot @@ -2231,9 +2231,9 @@ ;; removed the br, which we don't do atm). All we will do is add an ;; unreachable after the block, on the outside of it (which would help other ;; passes do more work). - (block $block (result (ref ${})) + (block $block (result (ref $"{}")) (br_on_non_null $block - (ref.null ${}) + (ref.null $"{}") ) (unreachable) ) @@ -5624,7 +5624,7 @@ ;; Test that we do not error on array.init of a bottom type. (module - (type $[mut:i32] (array (mut i32))) + (type $"[mut:i32]" (array (mut i32))) ;; CHECK: (type $0 (func)) @@ -5640,7 +5640,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $test - (array.init_data $[mut:i32] $0 + (array.init_data $"[mut:i32]" $0 (ref.as_non_null (ref.null none) ) diff --git a/test/lit/passes/local-subtyping.wast b/test/lit/passes/local-subtyping.wast index 89ba6429a..b25bb41b1 100644 --- a/test/lit/passes/local-subtyping.wast +++ b/test/lit/passes/local-subtyping.wast @@ -8,9 +8,9 @@ ;; testcases. (module - (type ${} (sub (struct))) + (type $"{}" (sub (struct))) - (type ${i32} (sub (struct (field i32)))) + (type $"{i32}" (sub (struct (field i32)))) (type $array (sub (array i8))) diff --git a/test/lit/passes/merge-similar-functions_all-features.wast b/test/lit/passes/merge-similar-functions_all-features.wast index ddc9a200f..74abd8c52 100644 --- a/test/lit/passes/merge-similar-functions_all-features.wast +++ b/test/lit/passes/merge-similar-functions_all-features.wast @@ -4,8 +4,8 @@ (module ;; CHECK: (type $0 (func)) - ;; CHECK: (type $[i8] (array i8)) - (type $[i8] (array i8)) + ;; CHECK: (type $"[i8]" (array i8)) + (type $"[i8]" (array i8)) ;; CHECK: (type $2 (func (param arrayref))) @@ -50,7 +50,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (call $take-ref-null-array - ;; CHECK-NEXT: (array.new_fixed $[i8] 0) + ;; CHECK-NEXT: (array.new_fixed $"[i8]" 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $no-call-subtyping-same-operand-0 @@ -58,7 +58,7 @@ (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (call $take-ref-null-array - (array.new_fixed $[i8] 0) + (array.new_fixed $"[i8]" 0) ) ) ;; CHECK: (func $no-call-subtyping-same-operand-1 (type $0) @@ -81,7 +81,7 @@ ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (call $take-ref-eq - ;; CHECK-NEXT: (array.new_fixed $[i8] 0) + ;; CHECK-NEXT: (array.new_fixed $"[i8]" 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $no-call-subtyping-same-operand-1 @@ -89,7 +89,7 @@ (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (nop) (call $take-ref-eq - (array.new_fixed $[i8] 0) + (array.new_fixed $"[i8]" 0) ) ) ) diff --git a/test/lit/passes/roundtrip-gc.wast b/test/lit/passes/roundtrip-gc.wast index 382f238d9..57300def5 100644 --- a/test/lit/passes/roundtrip-gc.wast +++ b/test/lit/passes/roundtrip-gc.wast @@ -2,7 +2,7 @@ ;; RUN: wasm-opt %s -all --generate-stack-ir --optimize-stack-ir --roundtrip -S -o - | filecheck %s (module - (type ${i32} (struct (field i32))) + (type $"{i32}" (struct (field i32))) ;; CHECK: (export "export" (func $test)) (export "export" (func $test)) ;; CHECK: (func $test (type $1) @@ -20,7 +20,7 @@ ;; CHECK-NEXT: ) (func $test (call $help - (struct.new_default ${i32}) + (struct.new_default $"{i32}") ;; Stack IR optimizations can remove this block, leaving a call in an odd ;; "stacky" location. On load, we will use a local to work around that. It ;; is fine for the local to be non-nullable since the get is later in that @@ -33,7 +33,7 @@ ) ;; CHECK: (func $help (type $2) (param $3 (ref $\7bi32\7d)) (param $4 i32) ;; CHECK-NEXT: ) - (func $help (param $3 (ref ${i32})) (param $4 i32) + (func $help (param $3 (ref $"{i32}")) (param $4 i32) (nop) ) diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast index 103cbe7f9..7b4b7921e 100644 --- a/test/lit/passes/signature-refining.wast +++ b/test/lit/passes/signature-refining.wast @@ -728,12 +728,12 @@ ) (module - ;; CHECK: (type ${} (struct )) - (type ${} (struct)) + ;; CHECK: (type $"{}" (struct )) + (type $"{}" (struct)) - ;; CHECK: (type $1 (func (param (ref ${}) i32))) + ;; CHECK: (type $1 (func (param (ref $"{}") i32))) - ;; CHECK: (func $foo (type $1) (param $ref (ref ${})) (param $i32 i32) + ;; CHECK: (func $foo (type $1) (param $ref (ref $"{}")) (param $i32 i32) ;; CHECK-NEXT: (local $2 eqref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (local.get $ref) @@ -752,19 +752,19 @@ ;; CHECK-NEXT: ) (func $foo (param $ref eqref) (param $i32 i32) (call $foo - ;; The only reference to the ${} type is in this block signature. Even + ;; The only reference to the $"{}" type is in this block signature. Even ;; this will go away in the internal ReFinalize (which makes the block ;; type unreachable). - (block (result (ref ${})) + (block (result (ref $"{}")) (unreachable) ) (i32.const 0) ) ;; Write something of type eqref into $ref. When we refine the type of the - ;; parameter from eqref to ${} we must do something here, as we can no + ;; parameter from eqref to $"{}" we must do something here, as we can no ;; longer just write this (ref.null eq) into a parameter of the more ;; refined type. While doing so, we must not be confused by the fact that - ;; the only mention of ${} in the original module gets removed during our + ;; the only mention of $"{}" in the original module gets removed during our ;; processing, as mentioned in the earlier comment. This is a regression ;; test for a crash because of that. (local.set $ref @@ -873,25 +873,25 @@ (module ;; CHECK: (rec - ;; CHECK-NEXT: (type $0 (func (param (ref $[i8])))) + ;; CHECK-NEXT: (type $0 (func (param (ref $"[i8]")))) - ;; CHECK: (type $[i8] (array i8)) - (type $[i8] (array i8)) + ;; CHECK: (type $"[i8]" (array i8)) + (type $"[i8]" (array i8)) ;; CHECK: (type $2 (func)) ;; CHECK: (func $0 (type $2) ;; CHECK-NEXT: (call $1 - ;; CHECK-NEXT: (array.new_fixed $[i8] 0) + ;; CHECK-NEXT: (array.new_fixed $"[i8]" 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $0 (call $1 - (array.new_fixed $[i8] 0) + (array.new_fixed $"[i8]" 0) ) ) - ;; CHECK: (func $1 (type $0) (param $2 (ref $[i8])) + ;; CHECK: (func $1 (type $0) (param $2 (ref $"[i8]")) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast (ref none) ;; CHECK-NEXT: (local.get $2) diff --git a/test/lit/passes/vacuum-gc.wast b/test/lit/passes/vacuum-gc.wast index 27cd6f52d..778ee8cd5 100644 --- a/test/lit/passes/vacuum-gc.wast +++ b/test/lit/passes/vacuum-gc.wast @@ -2,14 +2,14 @@ ;; RUN: wasm-opt %s --vacuum -all -S -o - | filecheck %s (module - ;; CHECK: (type ${} (struct )) + ;; CHECK: (type $"{}" (struct )) ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects (type $2) (param i32 i32 funcref) (result anyref))) (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects (param i32 i32 funcref) (result (ref null any)))) ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects.non.null (type $3) (param i32 i32 funcref) (result (ref any)))) (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects.non.null (param i32 i32 funcref) (result (ref any)))) - (type ${} (struct)) + (type $"{}" (struct)) ;; CHECK: (func $drop-ref-as (type $4) (param $x anyref) ;; CHECK-NEXT: (drop @@ -43,7 +43,7 @@ ;; CHECK-NEXT: ) (func $vacuum-nonnull (drop - (if (result (ref ${})) + (if (result (ref $"{}")) (i32.const 1) ;; This block's result is not used. As a consequence vacuum will try to ;; generate a replacement zero for the block's fallthrough value. A @@ -52,8 +52,8 @@ ;; on this case, though. Instead, the end result of this function should ;; simply be empty, as everything here can be vacuumed away. (then - (block (result (ref ${})) - (struct.new ${}) + (block (result (ref $"{}")) + (struct.new $"{}") ) ) (else @@ -84,18 +84,18 @@ ) ) - ;; CHECK: (func $ref.cast.null.block (type $6) (param $ref (ref ${})) (result structref) - ;; CHECK-NEXT: (ref.cast (ref ${}) + ;; CHECK: (func $ref.cast.null.block (type $6) (param $ref (ref $"{}")) (result structref) + ;; CHECK-NEXT: (ref.cast (ref $"{}") ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $ref.cast.null.block (param $ref (ref ${})) (result (ref null struct)) + (func $ref.cast.null.block (param $ref (ref $"{}")) (result (ref null struct)) ;; We can vacuum away the block, which will make this ref.cast null operate ;; on a non-nullable input. That is, we are refining the input to the cast. ;; The cast must be updated properly following that, to be a non-nullable ;; cast. - (ref.cast (ref null ${}) - (block (result (ref null ${})) + (ref.cast (ref null $"{}") + (block (result (ref null $"{}")) (local.get $ref) ) ) diff --git a/test/passes/Oz_fuzz-exec_all-features.wast b/test/passes/Oz_fuzz-exec_all-features.wast index 3893ddccd..7e45febf7 100644 --- a/test/passes/Oz_fuzz-exec_all-features.wast +++ b/test/passes/Oz_fuzz-exec_all-features.wast @@ -393,13 +393,13 @@ ) ) (module - (type $[mut:i8] (array (mut i8))) + (type $"[mut:i8]" (array (mut i8))) (func $foo (export "foo") (result i32) ;; before opts this will trap on failing to allocate -1 >>> 0 bytes. after ;; opts the unused value is removed so there is no trap, and a value is ;; returned, which should not confuse the fuzzer. (drop - (array.new_default $[mut:i8] + (array.new_default $"[mut:i8]" (i32.const -1) ) ) |