Skip to content

Commit fd8b2bd

Browse files
authored
Allow different arguments for multiple instances of a pass (#6687)
Each pass instance can now store an argument for it, which can be different. This may be a breaking change for the corner case of running a pass multiple times and setting the pass's argument multiple times as well (before, the last pass argument affected them all; now, it affects the last instance only). This only affects arguments with the name of a pass; others remain global, as before (and multiple passes can read them, in fact). See the CHANGELOG for details. Fixes #6646
1 parent aec516f commit fd8b2bd

31 files changed

+242
-89
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ v118
4141
- The build-time option to use legacy WasmGC opcodes is removed.
4242
- The strings in `string.const` instructions must now be valid WTF-8.
4343
- The `TraverseCalls` flag for `ExpressionRunner` is removed.
44+
- Passes can now receive individual pass arguments, that is --foo=A --foo=B for
45+
a pass foo will run the pass twice (which was possible before) and will now
46+
run it first with argument A and second with B. --pass-arg=foo@BAR will now
47+
apply to the most recent --foo pass on the commandline, if foo is a pass
48+
(while global pass arguments - that are not the name of a pass - remain, as
49+
before, global for all passes).
4450

4551
v117
4652
----

src/binaryen-c.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5453,7 +5453,10 @@ void BinaryenModuleRunPasses(BinaryenModuleRef module,
54535453
PassRunner passRunner((Module*)module);
54545454
passRunner.options = globalPassOptions;
54555455
for (BinaryenIndex i = 0; i < numPasses; i++) {
5456-
passRunner.add(passes[i]);
5456+
passRunner.add(passes[i],
5457+
globalPassOptions.arguments.count(passes[i]) > 0
5458+
? globalPassOptions.arguments[passes[i]]
5459+
: std::optional<std::string>());
54575460
}
54585461
passRunner.run();
54595462
}
@@ -5704,7 +5707,10 @@ void BinaryenFunctionRunPasses(BinaryenFunctionRef func,
57045707
PassRunner passRunner((Module*)module);
57055708
passRunner.options = globalPassOptions;
57065709
for (BinaryenIndex i = 0; i < numPasses; i++) {
5707-
passRunner.add(passes[i]);
5710+
passRunner.add(passes[i],
5711+
globalPassOptions.arguments.count(passes[i]) > 0
5712+
? globalPassOptions.arguments[passes[i]]
5713+
: std::optional<std::string>());
57085714
}
57095715
passRunner.runOnFunction((Function*)func);
57105716
}

src/pass.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ struct PassRegistry {
3939
using Creator = std::function<Pass*()>;
4040

4141
void registerPass(const char* name, const char* description, Creator create);
42+
4243
// Register a pass that's used for internal testing. These passes do not show
4344
// up in --help.
4445
void
4546
registerTestPass(const char* name, const char* description, Creator create);
4647
std::unique_ptr<Pass> createPass(std::string name);
4748
std::vector<std::string> getRegisteredNames();
49+
bool containsPass(const std::string& name);
4850
std::string getPassDescription(std::string name);
4951
bool isPassHidden(std::string name);
5052

@@ -103,6 +105,8 @@ class EffectAnalyzer;
103105
using FuncEffectsMap = std::unordered_map<Name, EffectAnalyzer>;
104106

105107
struct PassOptions {
108+
friend Pass;
109+
106110
// Run passes in debug mode, doing extra validation and timing checks.
107111
bool debug = false;
108112
// Whether to run the validator to check for errors.
@@ -269,6 +273,7 @@ struct PassOptions {
269273
return PassOptions(); // defaults are to not optimize
270274
}
271275

276+
private:
272277
bool hasArgument(std::string key) { return arguments.count(key) > 0; }
273278

274279
std::string getArgument(std::string key, std::string errorTextIfMissing) {
@@ -322,9 +327,8 @@ struct PassRunner {
322327
}
323328

324329
// Add a pass using its name.
325-
void add(std::string passName) {
326-
doAdd(PassRegistry::get()->createPass(passName));
327-
}
330+
void add(std::string passName,
331+
std::optional<std::string> passArg = std::nullopt);
328332

329333
// Add a pass given an instance.
330334
void add(std::unique_ptr<Pass> pass) { doAdd(std::move(pass)); }
@@ -486,6 +490,8 @@ class Pass {
486490
// to imports must override this to return true.
487491
virtual bool addsEffects() { return false; }
488492

493+
void setPassArg(const std::string& value) { passArg = value; }
494+
489495
std::string name;
490496

491497
PassRunner* getPassRunner() { return runner; }
@@ -497,6 +503,19 @@ class Pass {
497503
PassOptions& getPassOptions() { return runner->options; }
498504

499505
protected:
506+
bool hasArgument(const std::string& key);
507+
std::string getArgument(const std::string& key,
508+
const std::string& errorTextIfMissing);
509+
std::string getArgumentOrDefault(const std::string& key,
510+
const std::string& defaultValue);
511+
512+
// The main argument of the pass, which can be specified individually for
513+
// every pass . getArgument() and friends will refer to this value if queried
514+
// for a key that matches the pass name. All other arguments are taken from
515+
// the runner / passOptions and therefore are global for all instances of a
516+
// pass.
517+
std::optional<std::string> passArg;
518+
500519
Pass() = default;
501520
Pass(const Pass&) = default;
502521
Pass(Pass&&) = default;

src/passes/Asyncify.cpp

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,54 +1608,49 @@ struct Asyncify : public Pass {
16081608
bool addsEffects() override { return true; }
16091609

16101610
void run(Module* module) override {
1611-
auto& options = getPassOptions();
1612-
bool optimize = options.optimizeLevel > 0;
1611+
bool optimize = getPassOptions().optimizeLevel > 0;
16131612

16141613
// Find which things can change the state.
16151614
auto stateChangingImports = String::trim(read_possible_response_file(
1616-
options.getArgumentOrDefault("asyncify-imports", "")));
1617-
auto ignoreImports =
1618-
options.getArgumentOrDefault("asyncify-ignore-imports", "");
1615+
getArgumentOrDefault("asyncify-imports", "")));
1616+
auto ignoreImports = getArgumentOrDefault("asyncify-ignore-imports", "");
16191617
bool allImportsCanChangeState =
16201618
stateChangingImports == "" && ignoreImports == "";
16211619
String::Split listedImports(stateChangingImports,
16221620
String::Split::NewLineOr(","));
16231621
// canIndirectChangeState is the default. asyncify-ignore-indirect sets it
16241622
// to false.
1625-
auto canIndirectChangeState =
1626-
!options.hasArgument("asyncify-ignore-indirect");
1623+
auto canIndirectChangeState = !hasArgument("asyncify-ignore-indirect");
16271624
std::string removeListInput =
1628-
options.getArgumentOrDefault("asyncify-removelist", "");
1625+
getArgumentOrDefault("asyncify-removelist", "");
16291626
if (removeListInput.empty()) {
16301627
// Support old name for now to avoid immediate breakage TODO remove
1631-
removeListInput = options.getArgumentOrDefault("asyncify-blacklist", "");
1628+
removeListInput = getArgumentOrDefault("asyncify-blacklist", "");
16321629
}
16331630
String::Split removeList(
16341631
String::trim(read_possible_response_file(removeListInput)),
16351632
String::Split::NewLineOr(","));
1636-
String::Split addList(
1637-
String::trim(read_possible_response_file(
1638-
options.getArgumentOrDefault("asyncify-addlist", ""))),
1639-
String::Split::NewLineOr(","));
1640-
std::string onlyListInput =
1641-
options.getArgumentOrDefault("asyncify-onlylist", "");
1633+
String::Split addList(String::trim(read_possible_response_file(
1634+
getArgumentOrDefault("asyncify-addlist", ""))),
1635+
String::Split::NewLineOr(","));
1636+
std::string onlyListInput = getArgumentOrDefault("asyncify-onlylist", "");
16421637
if (onlyListInput.empty()) {
16431638
// Support old name for now to avoid immediate breakage TODO remove
1644-
onlyListInput = options.getArgumentOrDefault("asyncify-whitelist", "");
1639+
onlyListInput = getArgumentOrDefault("asyncify-whitelist", "");
16451640
}
16461641
String::Split onlyList(
16471642
String::trim(read_possible_response_file(onlyListInput)),
16481643
String::Split::NewLineOr(","));
1649-
auto asserts = options.hasArgument("asyncify-asserts");
1650-
auto verbose = options.hasArgument("asyncify-verbose");
1651-
auto relocatable = options.hasArgument("asyncify-relocatable");
1652-
auto secondaryMemory = options.hasArgument("asyncify-in-secondary-memory");
1653-
auto propagateAddList = options.hasArgument("asyncify-propagate-addlist");
1644+
auto asserts = hasArgument("asyncify-asserts");
1645+
auto verbose = hasArgument("asyncify-verbose");
1646+
auto relocatable = hasArgument("asyncify-relocatable");
1647+
auto secondaryMemory = hasArgument("asyncify-in-secondary-memory");
1648+
auto propagateAddList = hasArgument("asyncify-propagate-addlist");
16541649

16551650
// Ensure there is a memory, as we need it.
16561651
if (secondaryMemory) {
16571652
auto secondaryMemorySizeString =
1658-
options.getArgumentOrDefault("asyncify-secondary-memory-size", "1");
1653+
getArgumentOrDefault("asyncify-secondary-memory-size", "1");
16591654
Address secondaryMemorySize = std::stoi(secondaryMemorySizeString);
16601655
asyncifyMemory = createSecondaryMemory(module, secondaryMemorySize);
16611656
} else {

src/passes/Directize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ struct Directize : public Pass {
203203

204204
// TODO: consider a per-table option here
205205
auto initialContentsImmutable =
206-
getPassOptions().hasArgument("directize-initial-contents-immutable");
206+
hasArgument("directize-initial-contents-immutable");
207207

208208
// Set up the initial info.
209209
TableInfoMap tables;

src/passes/ExtractFunction.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ struct ExtractFunction : public Pass {
6262
bool addsEffects() override { return true; }
6363

6464
void run(Module* module) override {
65-
Name name = getPassOptions().getArgument(
65+
Name name = getArgument(
6666
"extract-function",
6767
"ExtractFunction usage: wasm-opt --extract-function=FUNCTION_NAME");
6868
extract(getPassRunner(), module, name);
@@ -74,10 +74,9 @@ struct ExtractFunctionIndex : public Pass {
7474
bool addsEffects() override { return true; }
7575

7676
void run(Module* module) override {
77-
std::string index =
78-
getPassOptions().getArgument("extract-function-index",
79-
"ExtractFunctionIndex usage: wasm-opt "
80-
"--extract-function-index=FUNCTION_INDEX");
77+
std::string index = getArgument("extract-function-index",
78+
"ExtractFunctionIndex usage: wasm-opt "
79+
"--extract-function-index=FUNCTION_INDEX");
8180
for (char c : index) {
8281
if (!std::isdigit(c)) {
8382
Fatal() << "Expected numeric function index";

src/passes/FuncCastEmulation.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ struct FuncCastEmulation : public Pass {
157157
bool addsEffects() override { return true; }
158158

159159
void run(Module* module) override {
160-
Index numParams = std::stoul(
161-
getPassOptions().getArgumentOrDefault("max-func-params", "16"));
160+
Index numParams = std::stoul(getArgumentOrDefault("max-func-params", "16"));
162161
// we just need the one ABI function type for all indirect calls
163162
HeapType ABIType(
164163
Signature(Type(std::vector<Type>(numParams, Type::i64)), Type::i64));

src/passes/JSPI.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,17 @@ struct JSPI : public Pass {
8383
void run(Module* module) override {
8484
Builder builder(*module);
8585

86-
auto& options = getPassOptions();
8786
// Find which imports can suspend.
88-
auto stateChangingImports = String::trim(read_possible_response_file(
89-
options.getArgumentOrDefault("jspi-imports", "")));
87+
auto stateChangingImports = String::trim(
88+
read_possible_response_file(getArgumentOrDefault("jspi-imports", "")));
9089
String::Split listedImports(stateChangingImports, ",");
9190

9291
// Find which exports should create a promise.
93-
auto stateChangingExports = String::trim(read_possible_response_file(
94-
options.getArgumentOrDefault("jspi-exports", "")));
92+
auto stateChangingExports = String::trim(
93+
read_possible_response_file(getArgumentOrDefault("jspi-exports", "")));
9594
String::Split listedExports(stateChangingExports, ",");
9695

97-
bool wasmSplit = options.hasArgument("jspi-split-module");
96+
bool wasmSplit = hasArgument("jspi-split-module");
9897
if (wasmSplit) {
9998
// Make an import for the load secondary module function so a JSPI wrapper
10099
// version will be created.

src/passes/LegalizeJSInterface.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,8 @@ struct LegalizeJSInterface : public Pass {
6464
setTempRet0 = nullptr;
6565
getTempRet0 = nullptr;
6666
auto exportOriginals =
67-
getPassOptions().hasArgument("legalize-js-interface-export-originals");
68-
exportedHelpers =
69-
getPassOptions().hasArgument("legalize-js-interface-exported-helpers");
67+
hasArgument("legalize-js-interface-export-originals");
68+
exportedHelpers = hasArgument("legalize-js-interface-exported-helpers");
7069
// for each illegal export, we must export a legalized stub instead
7170
std::vector<std::unique_ptr<Export>> newExports;
7271
for (auto& ex : module->exports) {

src/passes/LogExecution.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ struct LogExecution : public WalkerPass<PostWalker<LogExecution>> {
4646
bool addsEffects() override { return true; }
4747

4848
void run(Module* module) override {
49-
auto& options = getPassOptions();
50-
loggerModule = options.getArgumentOrDefault("log-execution", "");
49+
loggerModule = getArgumentOrDefault("log-execution", "");
5150
super::run(module);
5251
}
5352

0 commit comments

Comments
 (0)