From a4f2d46543f00eee32b9bd9328cb4cc4e8c27ce2 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 19 Jun 2024 16:55:59 +0200 Subject: [PATCH 01/11] Allow multiple noinline instances with different arguments. --- src/pass.h | 25 +++++++++++++++++++------ src/passes/NoInline.cpp | 6 ++++-- src/passes/pass.cpp | 24 +++++++++++++++++++++--- src/tools/optimization-options.h | 13 ++++++++++--- 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/pass.h b/src/pass.h index ab060309b4b..7c90650267e 100644 --- a/src/pass.h +++ b/src/pass.h @@ -38,7 +38,11 @@ struct PassRegistry { using Creator = std::function; - void registerPass(const char* name, const char* description, Creator create); + void registerPass(const char* name, + const char* description, + Creator create, + bool allowMultipleInstancesWithArgs = false); + ; // Register a pass that's used for internal testing. These passes do not show // up in --help. void @@ -47,6 +51,7 @@ struct PassRegistry { std::vector getRegisteredNames(); std::string getPassDescription(std::string name); bool isPassHidden(std::string name); + bool doesPassAllowMultipleInstancesWithArgs(std::string name); private: void registerPasses(); @@ -55,9 +60,14 @@ struct PassRegistry { std::string description; Creator create; bool hidden; + bool allowMultipleInstancesWithArgs; PassInfo() = default; - PassInfo(std::string description, Creator create, bool hidden = false) - : description(description), create(create), hidden(hidden) {} + PassInfo(std::string description, + Creator create, + bool hidden = false, + bool allowMultipleInstancesWithArgs = false) + : description(description), create(create), hidden(hidden), + allowMultipleInstancesWithArgs(allowMultipleInstancesWithArgs) {} }; std::map passInfos; }; @@ -322,9 +332,8 @@ struct PassRunner { } // Add a pass using its name. - void add(std::string passName) { - doAdd(PassRegistry::get()->createPass(passName)); - } + void add(std::string passName, + std::optional passArg = std::optional()); // Add a pass given an instance. void add(std::unique_ptr pass) { doAdd(std::move(pass)); } @@ -486,6 +495,8 @@ class Pass { // to imports must override this to return true. virtual bool addsEffects() { return false; } + void setPassArg(std::string value) { passArg = value; } + std::string name; PassRunner* getPassRunner() { return runner; } @@ -497,6 +508,8 @@ class Pass { PassOptions& getPassOptions() { return runner->options; } protected: + std::optional passArg; + Pass() = default; Pass(const Pass&) = default; Pass(Pass&&) = default; diff --git a/src/passes/NoInline.cpp b/src/passes/NoInline.cpp index 59e4f7e2ca8..95303683155 100644 --- a/src/passes/NoInline.cpp +++ b/src/passes/NoInline.cpp @@ -48,8 +48,10 @@ struct NoInline : public Pass { NoInline(NoInlineMode mode) : mode(mode) {} void run(Module* module) override { - std::string pattern = getPassOptions().getArgument( - name, "Usage usage: wasm-opt --" + name + "=WILDCARD"); + std::string pattern = + passArg ? *passArg + : getPassOptions().getArgument( + name, "Usage usage: wasm-opt --" + name + "=WILDCARD"); for (auto& func : module->functions) { if (!String::wildcardMatch(pattern, func->name.toString())) { diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index b226d6ec9ad..a606d10e36c 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -43,9 +43,11 @@ PassRegistry* PassRegistry::get() { return &singleton; } void PassRegistry::registerPass(const char* name, const char* description, - Creator create) { + Creator create, + bool allowMultipleInstancesWithArgs) { assert(passInfos.find(name) == passInfos.end()); - passInfos[name] = PassInfo(description, create); + passInfos[name] = + PassInfo(description, create, false, allowMultipleInstancesWithArgs); } void PassRegistry::registerTestPass(const char* name, @@ -83,6 +85,12 @@ bool PassRegistry::isPassHidden(std::string name) { return passInfos[name].hidden; } +bool PassRegistry::doesPassAllowMultipleInstancesWithArgs(std::string name) { + assert(passInfos.find(name) != passInfos.end()); + + return passInfos[name].allowMultipleInstancesWithArgs; +} + // PassRunner void PassRegistry::registerPasses() { @@ -307,7 +315,8 @@ void PassRegistry::registerPasses() { createMultiMemoryLoweringWithBoundsChecksPass); registerPass("nm", "name list", createNameListPass); registerPass("name-types", "(re)name all heap types", createNameTypesPass); - registerPass("no-inline", "mark functions as no-inline", createNoInlinePass); + registerPass( + "no-inline", "mark functions as no-inline", createNoInlinePass, true); registerPass("no-full-inline", "mark functions as no-inline (for full inlining only)", createNoFullInlinePass); @@ -715,6 +724,15 @@ void PassRunner::addDefaultGlobalOptimizationPrePasses() { // which can lead to more opportunities for global effects to matter. } +void PassRunner::add(std::string passName, std::optional passArg) { + auto pass = PassRegistry::get()->createPass(passName); + if (passArg) { + pass->setPassArg(*passArg); + } + + doAdd(std::move(pass)); +} + void PassRunner::addDefaultGlobalOptimizationPostPasses() { if (options.optimizeLevel >= 2 || options.shrinkLevel >= 1) { addIfNoDWARFIssues("dae-optimizing"); diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index af468769d69..67c2e1b57b4 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -51,6 +51,8 @@ struct OptimizationOptions : public ToolOptions { // The name of the pass to run. std::string name; + std::optional argument; + // The optimize and shrink levels to run the pass with, if specified. If not // specified then the defaults are used. std::optional optimizeLevel; @@ -330,13 +332,18 @@ struct OptimizationOptions : public ToolOptions { // --foo --pass-arg=foo@ARG Options::Arguments::Optional, [this, p](Options*, const std::string& arg) { + PassInfo info(p); if (!arg.empty()) { - if (passOptions.arguments.count(p)) { + if (passOptions.arguments.count(p) && + !PassRegistry::get()->doesPassAllowMultipleInstancesWithArgs( + p)) { Fatal() << "Cannot pass multiple pass arguments to " << p; } passOptions.arguments[p] = arg; + info.argument = arg; } - passes.push_back(p); + + passes.push_back(info); }, PassRegistry::get()->isPassHidden(p)); } @@ -393,7 +400,7 @@ struct OptimizationOptions : public ToolOptions { passRunner.options.shrinkLevel = passOptions.shrinkLevel; } else { // This is a normal pass. Add it to the queue for execution. - passRunner.add(pass.name); + passRunner.add(pass.name, pass.argument); // Normal passes do not set their own optimize/shrinkLevels. assert(!pass.optimizeLevel); From 83464327d234dbbaee520080adec95b85dd71213 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Tue, 25 Jun 2024 23:38:53 +0200 Subject: [PATCH 02/11] Allow multiple invocations with arguments for all passes, allow --pass-arg only for additional arguments. --- src/binaryen-c.cpp | 9 +++++-- src/pass.h | 23 +++++++--------- src/passes/Asyncify.cpp | 39 ++++++++++++--------------- src/passes/Directize.cpp | 2 +- src/passes/ExtractFunction.cpp | 9 +++---- src/passes/FuncCastEmulation.cpp | 3 +-- src/passes/JSPI.cpp | 11 ++++---- src/passes/LegalizeJSInterface.cpp | 5 ++-- src/passes/LogExecution.cpp | 3 +-- src/passes/NoInline.cpp | 4 +-- src/passes/PostEmscripten.cpp | 6 ++--- src/passes/PrintFunctionMap.cpp | 2 +- src/passes/SeparateDataSegments.cpp | 14 +++++----- src/passes/SetGlobals.cpp | 6 ++--- src/passes/StackCheck.cpp | 3 +-- src/passes/pass.cpp | 39 ++++++++++++++++++--------- src/tools/optimization-options.h | 6 ----- src/tools/wasm-split/wasm-split.cpp | 3 +-- test/lit/passes/extract-function.wast | 2 -- test/passes/set-globals.passes | 2 +- 20 files changed, 92 insertions(+), 99 deletions(-) diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index be80206f568..7428f53be2f 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -5453,7 +5453,9 @@ void BinaryenModuleRunPasses(BinaryenModuleRef module, PassRunner passRunner((Module*)module); passRunner.options = globalPassOptions; for (BinaryenIndex i = 0; i < numPasses; i++) { - passRunner.add(passes[i]); + passRunner.add(passes[i]), globalPassOptions.arguments.count(passes[i]) > 0 + ? globalPassOptions.arguments[passes[i]] + : std::optional(); } passRunner.run(); } @@ -5704,7 +5706,10 @@ void BinaryenFunctionRunPasses(BinaryenFunctionRef func, PassRunner passRunner((Module*)module); passRunner.options = globalPassOptions; for (BinaryenIndex i = 0; i < numPasses; i++) { - passRunner.add(passes[i]); + passRunner.add(passes[i], + globalPassOptions.arguments.count(passes[i]) > 0 + ? globalPassOptions.arguments[passes[i]] + : std::optional()); } passRunner.runOnFunction((Function*)func); } diff --git a/src/pass.h b/src/pass.h index 7c90650267e..e6e94d3908c 100644 --- a/src/pass.h +++ b/src/pass.h @@ -38,10 +38,7 @@ struct PassRegistry { using Creator = std::function; - void registerPass(const char* name, - const char* description, - Creator create, - bool allowMultipleInstancesWithArgs = false); + void registerPass(const char* name, const char* description, Creator create); ; // Register a pass that's used for internal testing. These passes do not show // up in --help. @@ -51,7 +48,6 @@ struct PassRegistry { std::vector getRegisteredNames(); std::string getPassDescription(std::string name); bool isPassHidden(std::string name); - bool doesPassAllowMultipleInstancesWithArgs(std::string name); private: void registerPasses(); @@ -60,14 +56,9 @@ struct PassRegistry { std::string description; Creator create; bool hidden; - bool allowMultipleInstancesWithArgs; PassInfo() = default; - PassInfo(std::string description, - Creator create, - bool hidden = false, - bool allowMultipleInstancesWithArgs = false) - : description(description), create(create), hidden(hidden), - allowMultipleInstancesWithArgs(allowMultipleInstancesWithArgs) {} + PassInfo(std::string description, Creator create, bool hidden = false) + : description(description), create(create), hidden(hidden) {} }; std::map passInfos; }; @@ -495,7 +486,7 @@ class Pass { // to imports must override this to return true. virtual bool addsEffects() { return false; } - void setPassArg(std::string value) { passArg = value; } + void setPassArg(const std::string& value) { passArg = value; } std::string name; @@ -508,6 +499,12 @@ class Pass { PassOptions& getPassOptions() { return runner->options; } protected: + bool hasArgument(const std::string& key); + std::string getArgument(const std::string& key, + const std::string& errorTextIfMissing); + std::string getArgumentOrDefault(const std::string& key, + const std::string& defaultValue); + std::optional passArg; Pass() = default; diff --git a/src/passes/Asyncify.cpp b/src/passes/Asyncify.cpp index 1ba764387e8..7ac9cf48921 100644 --- a/src/passes/Asyncify.cpp +++ b/src/passes/Asyncify.cpp @@ -1608,54 +1608,49 @@ struct Asyncify : public Pass { bool addsEffects() override { return true; } void run(Module* module) override { - auto& options = getPassOptions(); - bool optimize = options.optimizeLevel > 0; + bool optimize = getPassOptions().optimizeLevel > 0; // Find which things can change the state. auto stateChangingImports = String::trim(read_possible_response_file( - options.getArgumentOrDefault("asyncify-imports", ""))); - auto ignoreImports = - options.getArgumentOrDefault("asyncify-ignore-imports", ""); + getArgumentOrDefault("asyncify-imports", ""))); + auto ignoreImports = getArgumentOrDefault("asyncify-ignore-imports", ""); bool allImportsCanChangeState = stateChangingImports == "" && ignoreImports == ""; String::Split listedImports(stateChangingImports, String::Split::NewLineOr(",")); // canIndirectChangeState is the default. asyncify-ignore-indirect sets it // to false. - auto canIndirectChangeState = - !options.hasArgument("asyncify-ignore-indirect"); + auto canIndirectChangeState = !hasArgument("asyncify-ignore-indirect"); std::string removeListInput = - options.getArgumentOrDefault("asyncify-removelist", ""); + getArgumentOrDefault("asyncify-removelist", ""); if (removeListInput.empty()) { // Support old name for now to avoid immediate breakage TODO remove - removeListInput = options.getArgumentOrDefault("asyncify-blacklist", ""); + removeListInput = getArgumentOrDefault("asyncify-blacklist", ""); } String::Split removeList( String::trim(read_possible_response_file(removeListInput)), String::Split::NewLineOr(",")); - String::Split addList( - String::trim(read_possible_response_file( - options.getArgumentOrDefault("asyncify-addlist", ""))), - String::Split::NewLineOr(",")); - std::string onlyListInput = - options.getArgumentOrDefault("asyncify-onlylist", ""); + String::Split addList(String::trim(read_possible_response_file( + getArgumentOrDefault("asyncify-addlist", ""))), + String::Split::NewLineOr(",")); + std::string onlyListInput = getArgumentOrDefault("asyncify-onlylist", ""); if (onlyListInput.empty()) { // Support old name for now to avoid immediate breakage TODO remove - onlyListInput = options.getArgumentOrDefault("asyncify-whitelist", ""); + onlyListInput = getArgumentOrDefault("asyncify-whitelist", ""); } String::Split onlyList( String::trim(read_possible_response_file(onlyListInput)), String::Split::NewLineOr(",")); - auto asserts = options.hasArgument("asyncify-asserts"); - auto verbose = options.hasArgument("asyncify-verbose"); - auto relocatable = options.hasArgument("asyncify-relocatable"); - auto secondaryMemory = options.hasArgument("asyncify-in-secondary-memory"); - auto propagateAddList = options.hasArgument("asyncify-propagate-addlist"); + auto asserts = hasArgument("asyncify-asserts"); + auto verbose = hasArgument("asyncify-verbose"); + auto relocatable = hasArgument("asyncify-relocatable"); + auto secondaryMemory = hasArgument("asyncify-in-secondary-memory"); + auto propagateAddList = hasArgument("asyncify-propagate-addlist"); // Ensure there is a memory, as we need it. if (secondaryMemory) { auto secondaryMemorySizeString = - options.getArgumentOrDefault("asyncify-secondary-memory-size", "1"); + getArgumentOrDefault("asyncify-secondary-memory-size", "1"); Address secondaryMemorySize = std::stoi(secondaryMemorySizeString); asyncifyMemory = createSecondaryMemory(module, secondaryMemorySize); } else { diff --git a/src/passes/Directize.cpp b/src/passes/Directize.cpp index 66b42d3867f..6cb4e46d8c2 100644 --- a/src/passes/Directize.cpp +++ b/src/passes/Directize.cpp @@ -203,7 +203,7 @@ struct Directize : public Pass { // TODO: consider a per-table option here auto initialContentsImmutable = - getPassOptions().hasArgument("directize-initial-contents-immutable"); + hasArgument("directize-initial-contents-immutable"); // Set up the initial info. TableInfoMap tables; diff --git a/src/passes/ExtractFunction.cpp b/src/passes/ExtractFunction.cpp index 440468ede19..df53afbf2ba 100644 --- a/src/passes/ExtractFunction.cpp +++ b/src/passes/ExtractFunction.cpp @@ -62,7 +62,7 @@ struct ExtractFunction : public Pass { bool addsEffects() override { return true; } void run(Module* module) override { - Name name = getPassOptions().getArgument( + Name name = getArgument( "extract-function", "ExtractFunction usage: wasm-opt --extract-function=FUNCTION_NAME"); extract(getPassRunner(), module, name); @@ -74,10 +74,9 @@ struct ExtractFunctionIndex : public Pass { bool addsEffects() override { return true; } void run(Module* module) override { - std::string index = - getPassOptions().getArgument("extract-function-index", - "ExtractFunctionIndex usage: wasm-opt " - "--extract-function-index=FUNCTION_INDEX"); + std::string index = getArgument("extract-function-index", + "ExtractFunctionIndex usage: wasm-opt " + "--extract-function-index=FUNCTION_INDEX"); for (char c : index) { if (!std::isdigit(c)) { Fatal() << "Expected numeric function index"; diff --git a/src/passes/FuncCastEmulation.cpp b/src/passes/FuncCastEmulation.cpp index 23eb98a8c0d..972cf719cb7 100644 --- a/src/passes/FuncCastEmulation.cpp +++ b/src/passes/FuncCastEmulation.cpp @@ -157,8 +157,7 @@ struct FuncCastEmulation : public Pass { bool addsEffects() override { return true; } void run(Module* module) override { - Index numParams = std::stoul( - getPassOptions().getArgumentOrDefault("max-func-params", "16")); + Index numParams = std::stoul(getArgumentOrDefault("max-func-params", "16")); // we just need the one ABI function type for all indirect calls HeapType ABIType( Signature(Type(std::vector(numParams, Type::i64)), Type::i64)); diff --git a/src/passes/JSPI.cpp b/src/passes/JSPI.cpp index 1adf0de4ca2..d5fed1faf63 100644 --- a/src/passes/JSPI.cpp +++ b/src/passes/JSPI.cpp @@ -83,18 +83,17 @@ struct JSPI : public Pass { void run(Module* module) override { Builder builder(*module); - auto& options = getPassOptions(); // Find which imports can suspend. - auto stateChangingImports = String::trim(read_possible_response_file( - options.getArgumentOrDefault("jspi-imports", ""))); + auto stateChangingImports = String::trim( + read_possible_response_file(getArgumentOrDefault("jspi-imports", ""))); String::Split listedImports(stateChangingImports, ","); // Find which exports should create a promise. - auto stateChangingExports = String::trim(read_possible_response_file( - options.getArgumentOrDefault("jspi-exports", ""))); + auto stateChangingExports = String::trim( + read_possible_response_file(getArgumentOrDefault("jspi-exports", ""))); String::Split listedExports(stateChangingExports, ","); - bool wasmSplit = options.hasArgument("jspi-split-module"); + bool wasmSplit = hasArgument("jspi-split-module"); if (wasmSplit) { // Make an import for the load secondary module function so a JSPI wrapper // version will be created. diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp index a0b526a811e..bfc7e192b15 100644 --- a/src/passes/LegalizeJSInterface.cpp +++ b/src/passes/LegalizeJSInterface.cpp @@ -64,9 +64,8 @@ struct LegalizeJSInterface : public Pass { setTempRet0 = nullptr; getTempRet0 = nullptr; auto exportOriginals = - getPassOptions().hasArgument("legalize-js-interface-export-originals"); - exportedHelpers = - getPassOptions().hasArgument("legalize-js-interface-exported-helpers"); + hasArgument("legalize-js-interface-export-originals"); + exportedHelpers = hasArgument("legalize-js-interface-exported-helpers"); // for each illegal export, we must export a legalized stub instead std::vector> newExports; for (auto& ex : module->exports) { diff --git a/src/passes/LogExecution.cpp b/src/passes/LogExecution.cpp index f1d48012f85..aa7948963bc 100644 --- a/src/passes/LogExecution.cpp +++ b/src/passes/LogExecution.cpp @@ -46,8 +46,7 @@ struct LogExecution : public WalkerPass> { bool addsEffects() override { return true; } void run(Module* module) override { - auto& options = getPassOptions(); - loggerModule = options.getArgumentOrDefault("log-execution", ""); + loggerModule = getArgumentOrDefault("log-execution", ""); super::run(module); } diff --git a/src/passes/NoInline.cpp b/src/passes/NoInline.cpp index 95303683155..34f693e296b 100644 --- a/src/passes/NoInline.cpp +++ b/src/passes/NoInline.cpp @@ -49,9 +49,7 @@ struct NoInline : public Pass { void run(Module* module) override { std::string pattern = - passArg ? *passArg - : getPassOptions().getArgument( - name, "Usage usage: wasm-opt --" + name + "=WILDCARD"); + getArgument(name, "Usage usage: wasm-opt --" + name + "=WILDCARD"); for (auto& func : module->functions) { if (!String::wildcardMatch(pattern, func->name.toString())) { diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index 7ade801cceb..0e2c268dec0 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -214,8 +214,7 @@ struct PostEmscripten : public Pass { std::vector
segmentOffsets; // segment index => address offset calcSegmentOffsets(module, segmentOffsets); - auto& options = getPassOptions(); - auto sideModule = options.hasArgument("post-emscripten-side-module"); + auto sideModule = hasArgument("post-emscripten-side-module"); if (!sideModule) { removeData(module, segmentOffsets, "__start_em_asm", "__stop_em_asm"); removeData(module, segmentOffsets, "__start_em_js", "__stop_em_js"); @@ -235,8 +234,7 @@ struct PostEmscripten : public Pass { } void removeEmJsExports(Module& module) { - auto& options = getPassOptions(); - auto sideModule = options.hasArgument("post-emscripten-side-module"); + auto sideModule = hasArgument("post-emscripten-side-module"); EmJsWalker walker(sideModule); walker.walkModule(&module); for (const Export& exp : walker.toRemove) { diff --git a/src/passes/PrintFunctionMap.cpp b/src/passes/PrintFunctionMap.cpp index 08f5a359bb7..4fe266ec084 100644 --- a/src/passes/PrintFunctionMap.cpp +++ b/src/passes/PrintFunctionMap.cpp @@ -37,7 +37,7 @@ struct PrintFunctionMap : public Pass { void run(Module* module) override { // If an argument is provided, write to that file; otherwise write to // stdout. - auto outFile = getPassOptions().getArgumentOrDefault("symbolmap", ""); + auto outFile = getArgumentOrDefault("symbolmap", ""); Output output(outFile, Flags::Text); auto& o = output.getStream(); Index i = 0; diff --git a/src/passes/SeparateDataSegments.cpp b/src/passes/SeparateDataSegments.cpp index 3e48d14bc0e..bd684dbe82c 100644 --- a/src/passes/SeparateDataSegments.cpp +++ b/src/passes/SeparateDataSegments.cpp @@ -33,14 +33,14 @@ struct SeparateDataSegments : public Pass { void run(Module* module) override { std::string outfileName = - getPassOptions().getArgument("separate-data-segments", - "SeparateDataSegments usage: wasm-opt " - "--separate-data-segments@FILENAME"); + getArgument("separate-data-segments", + "SeparateDataSegments usage: wasm-opt " + "--separate-data-segments@FILENAME"); Output outfile(outfileName, Flags::Binary); - std::string baseStr = getPassOptions().getArgument( - "separate-data-segments-global-base", - "SeparateDataSegments usage: wasm-opt " - "--pass-arg=separate-data-segments-global-base@NUMBER"); + std::string baseStr = + getArgument("separate-data-segments-global-base", + "SeparateDataSegments usage: wasm-opt " + "--pass-arg=separate-data-segments-global-base@NUMBER"); Address base = std::stoi(baseStr); size_t lastEnd = 0; for (auto& seg : module->dataSegments) { diff --git a/src/passes/SetGlobals.cpp b/src/passes/SetGlobals.cpp index 5e24184fa55..4c0718e849c 100644 --- a/src/passes/SetGlobals.cpp +++ b/src/passes/SetGlobals.cpp @@ -29,9 +29,9 @@ struct SetGlobals : public Pass { bool requiresNonNullableLocalFixups() override { return false; } void run(Module* module) override { - Name input = getPassRunner()->options.getArgument( - "set-globals", - "SetGlobals usage: wasm-opt --pass-arg=set-globals@x=y,z=w"); + Name input = + getArgument("set-globals", + "SetGlobals usage: wasm-opt --pass-arg=set-globals@x=y,z=w"); // The input is a set of X=Y pairs separated by commas. String::Split pairs(input.toString(), ","); diff --git a/src/passes/StackCheck.cpp b/src/passes/StackCheck.cpp index 229a97f26bd..ce5d346b944 100644 --- a/src/passes/StackCheck.cpp +++ b/src/passes/StackCheck.cpp @@ -141,8 +141,7 @@ struct StackCheck : public Pass { auto stackLimitName = Names::getValidGlobalName(*module, "__stack_limit"); Name handler; - auto handlerName = - getPassOptions().getArgumentOrDefault("stack-check-handler", ""); + auto handlerName = getArgumentOrDefault("stack-check-handler", ""); if (handlerName != "") { handler = handlerName; importStackOverflowHandler( diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index a606d10e36c..f5c5ac55a6b 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -43,11 +43,9 @@ PassRegistry* PassRegistry::get() { return &singleton; } void PassRegistry::registerPass(const char* name, const char* description, - Creator create, - bool allowMultipleInstancesWithArgs) { + Creator create) { assert(passInfos.find(name) == passInfos.end()); - passInfos[name] = - PassInfo(description, create, false, allowMultipleInstancesWithArgs); + passInfos[name] = PassInfo(description, create, false); } void PassRegistry::registerTestPass(const char* name, @@ -85,12 +83,6 @@ bool PassRegistry::isPassHidden(std::string name) { return passInfos[name].hidden; } -bool PassRegistry::doesPassAllowMultipleInstancesWithArgs(std::string name) { - assert(passInfos.find(name) != passInfos.end()); - - return passInfos[name].allowMultipleInstancesWithArgs; -} - // PassRunner void PassRegistry::registerPasses() { @@ -315,8 +307,7 @@ void PassRegistry::registerPasses() { createMultiMemoryLoweringWithBoundsChecksPass); registerPass("nm", "name list", createNameListPass); registerPass("name-types", "(re)name all heap types", createNameTypesPass); - registerPass( - "no-inline", "mark functions as no-inline", createNoInlinePass, true); + registerPass("no-inline", "mark functions as no-inline", createNoInlinePass); registerPass("no-full-inline", "mark functions as no-inline (for full inlining only)", createNoFullInlinePass); @@ -1043,4 +1034,28 @@ bool PassRunner::shouldPreserveDWARF() { return true; } +bool Pass::hasArgument(const std::string& key) { + return (key == name) ? passArg.has_value() + : getPassOptions().hasArgument(key); +} + +std::string Pass::getArgument(const std::string& key, + const std::string& errorTextIfMissing) { + if (!hasArgument(key)) { + Fatal() << errorTextIfMissing; + } + + return (key == name) ? *passArg + : getPassOptions().getArgument(key, errorTextIfMissing); +} + +std::string Pass::getArgumentOrDefault(const std::string& key, + const std::string& defaultValue) { + if (key == name) { + return passArg.value_or(defaultValue); + } + + return getPassOptions().getArgumentOrDefault(key, defaultValue); +} + } // namespace wasm diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 67c2e1b57b4..060266b93d0 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -334,12 +334,6 @@ struct OptimizationOptions : public ToolOptions { [this, p](Options*, const std::string& arg) { PassInfo info(p); if (!arg.empty()) { - if (passOptions.arguments.count(p) && - !PassRegistry::get()->doesPassAllowMultipleInstancesWithArgs( - p)) { - Fatal() << "Cannot pass multiple pass arguments to " << p; - } - passOptions.arguments[p] = arg; info.argument = arg; } diff --git a/src/tools/wasm-split/wasm-split.cpp b/src/tools/wasm-split/wasm-split.cpp index abb1646c173..eed26f1e15e 100644 --- a/src/tools/wasm-split/wasm-split.cpp +++ b/src/tools/wasm-split/wasm-split.cpp @@ -192,9 +192,8 @@ void getFunctionsToKeepAndSplit(Module& wasm, void writeSymbolMap(Module& wasm, std::string filename) { PassOptions options; - options.arguments["symbolmap"] = filename; PassRunner runner(&wasm, options); - runner.add("symbolmap"); + runner.add("symbolmap", filename); runner.run(); } diff --git a/test/lit/passes/extract-function.wast b/test/lit/passes/extract-function.wast index 9258f8c63cf..79e4c368ed4 100644 --- a/test/lit/passes/extract-function.wast +++ b/test/lit/passes/extract-function.wast @@ -1,8 +1,6 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; RUN: foreach %s %t wasm-opt --extract-function=foo -S -o - | filecheck %s -;; RUN: foreach %s %t wasm-opt --extract-function --pass-arg=extract-function@foo -S -o - | filecheck %s ;; RUN: foreach %s %t wasm-opt --extract-function-index=0 -S -o - | filecheck %s -;; RUN: foreach %s %t wasm-opt --extract-function-index --pass-arg=extract-function-index@0 -S -o - | filecheck %s (module ;; CHECK: (type $0 (func)) diff --git a/test/passes/set-globals.passes b/test/passes/set-globals.passes index 9f01c13a623..f5c0f1c24a4 100644 --- a/test/passes/set-globals.passes +++ b/test/passes/set-globals.passes @@ -1 +1 @@ -set-globals_pass-arg=set-globals@foo=1337,bar=42 +set-globals=foo=1337,bar=42 From 959aad5e1ec836c0ce635749e6bdae300f10ea0d Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sat, 29 Jun 2024 15:07:12 +0200 Subject: [PATCH 03/11] Support setting pass main argument again with --pass-arg --- src/pass.h | 1 + src/passes/pass.cpp | 10 ++++++++++ src/tools/optimization-options.h | 21 +++++++++++++++++++++ src/tools/tool-options.h | 9 ++++++++- test/lit/passes/extract-function.wast | 2 ++ test/passes/set-globals.passes | 2 +- 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/pass.h b/src/pass.h index e6e94d3908c..311b7d2f108 100644 --- a/src/pass.h +++ b/src/pass.h @@ -46,6 +46,7 @@ struct PassRegistry { registerTestPass(const char* name, const char* description, Creator create); std::unique_ptr createPass(std::string name); std::vector getRegisteredNames(); + bool containsPass(const std::string& name); std::string getPassDescription(std::string name); bool isPassHidden(std::string name); diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index f5c5ac55a6b..408ce9592c5 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -73,6 +73,16 @@ std::vector PassRegistry::getRegisteredNames() { return ret; } +bool PassRegistry::containsPass(const std::string& name) { + for (auto& [passName, _] : passInfos) { + if (passName == name) { + return true; + } + } + + return false; +} + std::string PassRegistry::getPassDescription(std::string name) { assert(passInfos.find(name) != passInfos.end()); return passInfos[name].description; diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 060266b93d0..835e5681486 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -343,6 +343,27 @@ struct OptimizationOptions : public ToolOptions { } } + void addPassArg(const std::string& key, const std::string& value) override { + for (auto iPass = passes.rbegin(); iPass != passes.rend(); iPass++) { + if (iPass->name != key) { + continue; + } + + if (iPass->argument.has_value()) { + Fatal() << iPass->name << " already set to " << *(iPass->argument); + } + + iPass->argument = value; + return; + } + + if (!PassRegistry::get()->containsPass(key)) { + return ToolOptions::addPassArg(key, value); + } + + Fatal() << "can't set " << key << ": pass not enabled"; + } + bool runningDefaultOptimizationPasses() { for (auto& pass : passes) { if (pass.name == DEFAULT_OPT_PASSES) { diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index 10a03acc785..10e6ec3c9f0 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -139,7 +139,8 @@ struct ToolOptions : public Options { key = argument.substr(0, colon); value = argument.substr(colon + 1); } - passOptions.arguments[key] = value; + + addPassArg(key, value); }) .add( "--closed-world", @@ -213,6 +214,12 @@ struct ToolOptions : public Options { module.features.disable(disabledFeatures); } + virtual void addPassArg(const std::string& key, const std::string& value) { + passOptions.arguments[key] = value; + } + + virtual ~ToolOptions() = default; + private: FeatureSet enabledFeatures = FeatureSet::Default; FeatureSet disabledFeatures = FeatureSet::None; diff --git a/test/lit/passes/extract-function.wast b/test/lit/passes/extract-function.wast index 79e4c368ed4..9258f8c63cf 100644 --- a/test/lit/passes/extract-function.wast +++ b/test/lit/passes/extract-function.wast @@ -1,6 +1,8 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. ;; RUN: foreach %s %t wasm-opt --extract-function=foo -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --extract-function --pass-arg=extract-function@foo -S -o - | filecheck %s ;; RUN: foreach %s %t wasm-opt --extract-function-index=0 -S -o - | filecheck %s +;; RUN: foreach %s %t wasm-opt --extract-function-index --pass-arg=extract-function-index@0 -S -o - | filecheck %s (module ;; CHECK: (type $0 (func)) diff --git a/test/passes/set-globals.passes b/test/passes/set-globals.passes index f5c0f1c24a4..9f01c13a623 100644 --- a/test/passes/set-globals.passes +++ b/test/passes/set-globals.passes @@ -1 +1 @@ -set-globals=foo=1337,bar=42 +set-globals_pass-arg=set-globals@foo=1337,bar=42 From a7851d31723d141492b572ad56e1a26d1bb5589a Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Sat, 29 Jun 2024 15:54:29 +0200 Subject: [PATCH 04/11] Fix new occurence of getArgument, force new code to use Pass methods. --- src/pass.h | 3 +++ src/passes/TraceCalls.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/pass.h b/src/pass.h index 311b7d2f108..0442d917d4f 100644 --- a/src/pass.h +++ b/src/pass.h @@ -105,6 +105,8 @@ class EffectAnalyzer; using FuncEffectsMap = std::unordered_map; struct PassOptions { + friend Pass; + // Run passes in debug mode, doing extra validation and timing checks. bool debug = false; // Whether to run the validator to check for errors. @@ -271,6 +273,7 @@ struct PassOptions { return PassOptions(); // defaults are to not optimize } +private: bool hasArgument(std::string key) { return arguments.count(key) > 0; } std::string getArgument(std::string key, std::string errorTextIfMissing) { diff --git a/src/passes/TraceCalls.cpp b/src/passes/TraceCalls.cpp index 01278c2e9e6..44bc16e95e6 100644 --- a/src/passes/TraceCalls.cpp +++ b/src/passes/TraceCalls.cpp @@ -124,10 +124,10 @@ struct TraceCalls : public Pass { bool addsEffects() override { return true; } void run(Module* module) override { - auto functionsDefinitions = getPassOptions().getArgument( - "trace-calls", - "TraceCalls usage: wasm-opt " - "--trace-calls=FUNCTION_TO_TRACE[:TRACER_NAME][,...]"); + auto functionsDefinitions = + getArgument("trace-calls", + "TraceCalls usage: wasm-opt " + "--trace-calls=FUNCTION_TO_TRACE[:TRACER_NAME][,...]"); auto tracedFunctions = parseArgument(functionsDefinitions); From f71a405bb3d3676bf02ad012a8847002968c6a26 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 1 Jul 2024 23:52:56 +0200 Subject: [PATCH 05/11] Fix braces. --- src/binaryen-c.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 7428f53be2f..298a5023368 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -5453,9 +5453,10 @@ void BinaryenModuleRunPasses(BinaryenModuleRef module, PassRunner passRunner((Module*)module); passRunner.options = globalPassOptions; for (BinaryenIndex i = 0; i < numPasses; i++) { - passRunner.add(passes[i]), globalPassOptions.arguments.count(passes[i]) > 0 - ? globalPassOptions.arguments[passes[i]] - : std::optional(); + passRunner.add(passes[i], + globalPassOptions.arguments.count(passes[i]) > 0 + ? globalPassOptions.arguments[passes[i]] + : std::optional()); } passRunner.run(); } From 807368bedf6c655726e237086bad7d90cbffa76e Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 3 Jul 2024 23:14:06 +0200 Subject: [PATCH 06/11] Review suggestions. --- src/pass.h | 4 ++-- src/passes/pass.cpp | 15 +++++---------- src/tools/optimization-options.h | 10 +++++----- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/pass.h b/src/pass.h index 0442d917d4f..afdab557a40 100644 --- a/src/pass.h +++ b/src/pass.h @@ -39,7 +39,7 @@ struct PassRegistry { using Creator = std::function; void registerPass(const char* name, const char* description, Creator create); - ; + // Register a pass that's used for internal testing. These passes do not show // up in --help. void @@ -328,7 +328,7 @@ struct PassRunner { // Add a pass using its name. void add(std::string passName, - std::optional passArg = std::optional()); + std::optional passArg = std::nullopt); // Add a pass given an instance. void add(std::unique_ptr pass) { doAdd(std::move(pass)); } diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 408ce9592c5..ec6077941d4 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -45,7 +45,7 @@ void PassRegistry::registerPass(const char* name, const char* description, Creator create) { assert(passInfos.find(name) == passInfos.end()); - passInfos[name] = PassInfo(description, create, false); + passInfos[name] = PassInfo(description, create); } void PassRegistry::registerTestPass(const char* name, @@ -74,13 +74,7 @@ std::vector PassRegistry::getRegisteredNames() { } bool PassRegistry::containsPass(const std::string& name) { - for (auto& [passName, _] : passInfos) { - if (passName == name) { - return true; - } - } - - return false; + return passInfos.count(name) > 0; } std::string PassRegistry::getPassDescription(std::string name) { @@ -1045,8 +1039,9 @@ bool PassRunner::shouldPreserveDWARF() { } bool Pass::hasArgument(const std::string& key) { - return (key == name) ? passArg.has_value() - : getPassOptions().hasArgument(key); + // An argument with the name of the pass is stored on the instance. Other + // arguments are in the global storage. + return key == name ? passArg.has_value() : getPassOptions().hasArgument(key); } std::string Pass::getArgument(const std::string& key, diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 835e5681486..2518008d829 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -344,16 +344,16 @@ struct OptimizationOptions : public ToolOptions { } void addPassArg(const std::string& key, const std::string& value) override { - for (auto iPass = passes.rbegin(); iPass != passes.rend(); iPass++) { - if (iPass->name != key) { + for (auto i = passes.rbegin(); i != passes.rend(); i++) { + if (i->name != key) { continue; } - if (iPass->argument.has_value()) { - Fatal() << iPass->name << " already set to " << *(iPass->argument); + if (i->argument.has_value()) { + Fatal() << i->name << " already set to " << *(i->argument); } - iPass->argument = value; + i->argument = value; return; } From c02a74547684b2ab3e82e0ae28d76cfd4648d24a Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 3 Jul 2024 23:19:10 +0200 Subject: [PATCH 07/11] Comment. --- src/tools/optimization-options.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index 2518008d829..e9386c7dfa8 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -343,7 +343,13 @@ struct OptimizationOptions : public ToolOptions { } } + // Pass arguments with the same name as the pass are stored per-instance on + // PassInfo, while all other arguments are stored globally on + // passOptions.arguments (which is what the overriden method on ToolOptions + // does). void addPassArg(const std::string& key, const std::string& value) override { + // Scan the current pass list for the last defined instance of a pass named + // like the argument under consideration. for (auto i = passes.rbegin(); i != passes.rend(); i++) { if (i->name != key) { continue; @@ -353,14 +359,17 @@ struct OptimizationOptions : public ToolOptions { Fatal() << i->name << " already set to " << *(i->argument); } + // Found? Store the argument value there and return. i->argument = value; return; } + // Not found? Store it globally if there is no pass with the same name. if (!PassRegistry::get()->containsPass(key)) { return ToolOptions::addPassArg(key, value); } + // Not found, but we have a pass with the same name? Bail out. Fatal() << "can't set " << key << ": pass not enabled"; } From a842027a8f340ed81c50a0b8b137e6c2ffa245f8 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Thu, 4 Jul 2024 21:36:00 +0200 Subject: [PATCH 08/11] Comments. --- src/pass.h | 5 +++++ src/tools/optimization-options.h | 1 + src/tools/tool-options.h | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pass.h b/src/pass.h index afdab557a40..9352319ad65 100644 --- a/src/pass.h +++ b/src/pass.h @@ -509,6 +509,11 @@ class Pass { std::string getArgumentOrDefault(const std::string& key, const std::string& defaultValue); + // The main argument of the pass, which can be specified individually for + // every pass . getArgument() and friends will refer to this value if queried + // for a key that matches the pass name. All other arguments are taken from + // the runner / passOptions and therefore are global for all instances of a + // pass. std::optional passArg; Pass() = default; diff --git a/src/tools/optimization-options.h b/src/tools/optimization-options.h index e9386c7dfa8..f04b7321120 100644 --- a/src/tools/optimization-options.h +++ b/src/tools/optimization-options.h @@ -51,6 +51,7 @@ struct OptimizationOptions : public ToolOptions { // The name of the pass to run. std::string name; + // The main argument of the pass, if applicable. std::optional argument; // The optimize and shrink levels to run the pass with, if specified. If not diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index 10e6ec3c9f0..8c3d8f4590e 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -126,7 +126,9 @@ struct ToolOptions : public Options { .add("--pass-arg", "-pa", "An argument passed along to optimization passes being run. Must be " - "in the form KEY@VALUE", + "in the form KEY@VALUE. If a pass --somepass is specified " + "multiple times, --pass-arg=somepass will apply to the closest " + "instance to the left. All other options apply to all instances.", ToolOptionsCategory, Options::Arguments::N, [this](Options*, const std::string& argument) { From 8369e79012e9ebd577b11b5f31a669fe23f738e3 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Wed, 10 Jul 2024 20:42:12 +0200 Subject: [PATCH 09/11] Wording, changelog. --- CHANGELOG.md | 6 ++++++ src/tools/tool-options.h | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56199c9831a..a8f4e6dee75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,12 @@ v118 - The build-time option to use legacy WasmGC opcodes is removed. - The strings in `string.const` instructions must now be valid WTF-8. - The `TraverseCalls` flag for `ExpressionRunner` is removed. + - Passes can now be specified several times on the command line. The "main" + argument (the one that has the same name like the pass) can be specified + individually for every instance; all other arguments for that pass apply + globally to all instances. In particular, this allows to specify + `--no-inline` several times to exclude functions that match one of multiple + patterns from inlining. v117 ---- diff --git a/src/tools/tool-options.h b/src/tools/tool-options.h index 8c3d8f4590e..c9d891a00bb 100644 --- a/src/tools/tool-options.h +++ b/src/tools/tool-options.h @@ -126,9 +126,10 @@ struct ToolOptions : public Options { .add("--pass-arg", "-pa", "An argument passed along to optimization passes being run. Must be " - "in the form KEY@VALUE. If a pass --somepass is specified " - "multiple times, --pass-arg=somepass will apply to the closest " - "instance to the left. All other options apply to all instances.", + "in the form KEY@VALUE. If KEY is the name of a pass then it " + "applies to the closest instance of that pass before us. If KEY is " + "not the name of a pass then it is a global option that applies to " + "all pass instances that read it.", ToolOptionsCategory, Options::Arguments::N, [this](Options*, const std::string& argument) { From ffae7a3eea13643dce5e65afa98355a2df598063 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 15 Jul 2024 20:24:18 +0200 Subject: [PATCH 10/11] Improve changelog. --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8f4e6dee75..5f7a3758141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,12 +41,12 @@ v118 - The build-time option to use legacy WasmGC opcodes is removed. - The strings in `string.const` instructions must now be valid WTF-8. - The `TraverseCalls` flag for `ExpressionRunner` is removed. - - Passes can now be specified several times on the command line. The "main" - argument (the one that has the same name like the pass) can be specified - individually for every instance; all other arguments for that pass apply - globally to all instances. In particular, this allows to specify - `--no-inline` several times to exclude functions that match one of multiple - patterns from inlining. + - Passes can now receive individual pass arguments, that is --foo=A --foo=B for + a pass foo will run the pass twice (which was possible before) and will now + run it first with argument A and second with B. --pass-arg=foo@BAR will now + apply to the most recent --foo pass on the commandline, if foo is a pass + (while global pass arguments - that are not the name of a pass - remain, as + before, global for all passes). v117 ---- From 5d73760079bee822d4c4da959061b5cac3feefa7 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 15 Jul 2024 20:26:53 +0200 Subject: [PATCH 11/11] Update test fixtures. --- test/lit/help/wasm-as.test | 7 ++++++- test/lit/help/wasm-ctor-eval.test | 7 ++++++- test/lit/help/wasm-dis.test | 7 ++++++- test/lit/help/wasm-emscripten-finalize.test | 7 ++++++- test/lit/help/wasm-merge.test | 7 ++++++- test/lit/help/wasm-metadce.test | 9 ++++++++- test/lit/help/wasm-opt.test | 9 ++++++++- test/lit/help/wasm-reduce.test | 7 ++++++- test/lit/help/wasm-split.test | 7 ++++++- test/lit/help/wasm2js.test | 9 ++++++++- 10 files changed, 66 insertions(+), 10 deletions(-) diff --git a/test/lit/help/wasm-as.test b/test/lit/help/wasm-as.test index 114064576a2..3a863dbd6b4 100644 --- a/test/lit/help/wasm-as.test +++ b/test/lit/help/wasm-as.test @@ -121,7 +121,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm-ctor-eval.test b/test/lit/help/wasm-ctor-eval.test index 93b5654ed60..2d57e3e8cc3 100644 --- a/test/lit/help/wasm-ctor-eval.test +++ b/test/lit/help/wasm-ctor-eval.test @@ -128,7 +128,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm-dis.test b/test/lit/help/wasm-dis.test index 06dda9e96af..63c7f8bd0b1 100644 --- a/test/lit/help/wasm-dis.test +++ b/test/lit/help/wasm-dis.test @@ -114,7 +114,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm-emscripten-finalize.test b/test/lit/help/wasm-emscripten-finalize.test index 1b31e1e44cf..c92960dfbeb 100644 --- a/test/lit/help/wasm-emscripten-finalize.test +++ b/test/lit/help/wasm-emscripten-finalize.test @@ -156,7 +156,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm-merge.test b/test/lit/help/wasm-merge.test index 293bdbff041..fe3f1cdb29e 100644 --- a/test/lit/help/wasm-merge.test +++ b/test/lit/help/wasm-merge.test @@ -144,7 +144,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm-metadce.test b/test/lit/help/wasm-metadce.test index 5b621caf5e1..66013f81aa8 100644 --- a/test/lit/help/wasm-metadce.test +++ b/test/lit/help/wasm-metadce.test @@ -733,7 +733,14 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to ;; CHECK-NEXT: optimization passes being run. -;; CHECK-NEXT: Must be in the form KEY@VALUE +;; CHECK-NEXT: Must be in the form KEY@VALUE. +;; CHECK-NEXT: If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest +;; CHECK-NEXT: instance of that pass before us. +;; CHECK-NEXT: If KEY is not the name of a pass +;; CHECK-NEXT: then it is a global option that +;; CHECK-NEXT: applies to all pass instances +;; CHECK-NEXT: that read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the ;; CHECK-NEXT: module does not inspect or diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index 9f7caf98bee..c89baaf4a73 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -742,7 +742,14 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to ;; CHECK-NEXT: optimization passes being run. -;; CHECK-NEXT: Must be in the form KEY@VALUE +;; CHECK-NEXT: Must be in the form KEY@VALUE. +;; CHECK-NEXT: If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest +;; CHECK-NEXT: instance of that pass before us. +;; CHECK-NEXT: If KEY is not the name of a pass +;; CHECK-NEXT: then it is a global option that +;; CHECK-NEXT: applies to all pass instances +;; CHECK-NEXT: that read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the ;; CHECK-NEXT: module does not inspect or diff --git a/test/lit/help/wasm-reduce.test b/test/lit/help/wasm-reduce.test index 39795285537..cacf260fab5 100644 --- a/test/lit/help/wasm-reduce.test +++ b/test/lit/help/wasm-reduce.test @@ -150,7 +150,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm-split.test b/test/lit/help/wasm-split.test index c118d302dca..bc09796d77e 100644 --- a/test/lit/help/wasm-split.test +++ b/test/lit/help/wasm-split.test @@ -231,7 +231,12 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to optimization ;; CHECK-NEXT: passes being run. Must be in the form -;; CHECK-NEXT: KEY@VALUE +;; CHECK-NEXT: KEY@VALUE. If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest instance +;; CHECK-NEXT: of that pass before us. If KEY is not the +;; CHECK-NEXT: name of a pass then it is a global option +;; CHECK-NEXT: that applies to all pass instances that +;; CHECK-NEXT: read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the module does ;; CHECK-NEXT: not inspect or interact with GC and diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index ca731d27741..45bef7d7383 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -696,7 +696,14 @@ ;; CHECK-NEXT: ;; CHECK-NEXT: --pass-arg,-pa An argument passed along to ;; CHECK-NEXT: optimization passes being run. -;; CHECK-NEXT: Must be in the form KEY@VALUE +;; CHECK-NEXT: Must be in the form KEY@VALUE. +;; CHECK-NEXT: If KEY is the name of a pass +;; CHECK-NEXT: then it applies to the closest +;; CHECK-NEXT: instance of that pass before us. +;; CHECK-NEXT: If KEY is not the name of a pass +;; CHECK-NEXT: then it is a global option that +;; CHECK-NEXT: applies to all pass instances +;; CHECK-NEXT: that read it. ;; CHECK-NEXT: ;; CHECK-NEXT: --closed-world,-cw Assume code outside of the ;; CHECK-NEXT: module does not inspect or