Skip to content

Add a mechanism to skip a pass by name #5448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ struct PassOptions {
// Arbitrary string arguments from the commandline, which we forward to
// passes.
std::unordered_map<std::string, std::string> arguments;
// Passes to skip and not run.
std::unordered_set<std::string> passesToSkip;

// Effect info computed for functions. One pass can generate this and then
// other passes later can benefit from it. It is up to the sequence of passes
Expand Down Expand Up @@ -386,6 +388,9 @@ struct PassRunner {
// Whether this pass runner has run. A pass runner should only be run once.
bool ran = false;

// Passes in |options.passesToSkip| that we have seen and skipped.
std::unordered_set<std::string> skippedPasses;

void runPass(Pass* pass);
void runPassOnFunction(Pass* pass, Function* func);

Expand Down
25 changes: 25 additions & 0 deletions src/passes/pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,9 @@ void PassRunner::run() {
assert(!ran);
ran = true;

// As we run passes, we'll notice which we skip.
skippedPasses.clear();

static const int passDebug = getPassDebug();
// Emit logging information when asked for. At passDebug level 1+ we log
// the main passes, while in 2 we also log nested ones. Note that for
Expand Down Expand Up @@ -812,6 +815,16 @@ void PassRunner::run() {
}
flush();
}

// All the passes the user requested to skip should have been seen, and
// skipped. If not, the user may have had a typo in the name of a pass to
// skip, and we will warn.
for (auto pass : options.passesToSkip) {
if (!skippedPasses.count(pass)) {
std::cerr << "warning: --" << pass << " was requested to be skipped, "
<< "but it was not found in the passes that were run.\n";
}
}
}

void PassRunner::runOnFunction(Function* func) {
Expand Down Expand Up @@ -930,6 +943,13 @@ struct AfterEffectModuleChecker {
};

void PassRunner::runPass(Pass* pass) {
assert(!pass->isFunctionParallel());

if (options.passesToSkip.count(pass->name)) {
skippedPasses.insert(pass->name);
return;
}

std::unique_ptr<AfterEffectModuleChecker> checker;
if (getPassDebug()) {
checker = std::unique_ptr<AfterEffectModuleChecker>(
Expand All @@ -949,6 +969,11 @@ void PassRunner::runPass(Pass* pass) {
void PassRunner::runPassOnFunction(Pass* pass, Function* func) {
assert(pass->isFunctionParallel());

if (options.passesToSkip.count(pass->name)) {
skippedPasses.insert(pass->name);
return;
}

auto passDebug = getPassDebug();

// Add extra validation logic in pass-debug mode 2. The main logic in
Expand Down
8 changes: 8 additions & 0 deletions src/tools/optimization-options.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ struct OptimizationOptions : public ToolOptions {
Options::Arguments::Zero,
[this](Options*, const std::string&) {
passOptions.zeroFilledMemory = true;
})
.add("--skip-pass",
"-sp",
"Skip a pass (do not run it)",
OptimizationOptionsCategory,
Options::Arguments::One,
[this](Options*, const std::string& pass) {
passOptions.passesToSkip.insert(pass);
});

// add passes in registry
Expand Down
2 changes: 2 additions & 0 deletions test/lit/help/wasm-opt.test
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,8 @@
;; CHECK-NEXT: --zero-filled-memory,-uim Assume that an imported memory
;; CHECK-NEXT: will be zero-initialized
;; CHECK-NEXT:
;; CHECK-NEXT: --skip-pass,-sp Skip a pass (do not run it)
;; CHECK-NEXT:
;; CHECK-NEXT:
;; CHECK-NEXT: Tool options:
;; CHECK-NEXT: -------------
Expand Down
2 changes: 2 additions & 0 deletions test/lit/help/wasm2js.test
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@
;; CHECK-NEXT: --zero-filled-memory,-uim Assume that an imported memory
;; CHECK-NEXT: will be zero-initialized
;; CHECK-NEXT:
;; CHECK-NEXT: --skip-pass,-sp Skip a pass (do not run it)
;; CHECK-NEXT:
;; CHECK-NEXT:
;; CHECK-NEXT: Tool options:
;; CHECK-NEXT: -------------
Expand Down
70 changes: 70 additions & 0 deletions test/lit/passes/O1_skip.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.

;; RUN: foreach %s %t wasm-opt -O2 --coalesce-locals --skip-pass=coalesce-locals -S -o - | filecheck %s

;; We should skip coalese-locals even though it is run in -O2 and also we ask to
;; run it directly: the skip instruction overrides everything else.

(module
;; CHECK: (type $i32_i32_=>_none (func (param i32 i32)))

;; CHECK: (type $i32_=>_none (func (param i32)))

;; CHECK: (import "a" "b" (func $log (param i32 i32)))
(import "a" "b" (func $log (param i32 i32)))

(func "foo" (param $p i32)
;; The locals $x and $y can be coalesced into a single local, but as we do not
;; run that pass, they will not be. Other minor optimizations will occur here,
;; such as using a tee.
(local $x i32)
(local $y i32)

(local.set $x
(i32.add
(local.get $p)
(i32.const 1)
)
)
(call $log
(local.get $x)
(local.get $x)
)

(local.set $y
(i32.add
(local.get $p)
(i32.const 1)
)
)
(call $log
(local.get $y)
(local.get $y)
)
)
)
;; CHECK: (export "foo" (func $0))

;; CHECK: (func $0 (; has Stack IR ;) (param $p i32)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local $y i32)
;; CHECK-NEXT: (call $log
;; CHECK-NEXT: (local.tee $x
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (local.get $p)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $log
;; CHECK-NEXT: (local.tee $y
;; CHECK-NEXT: (i32.add
;; CHECK-NEXT: (local.get $p)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
8 changes: 8 additions & 0 deletions test/lit/passes/skip-missing.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
;; We should warn on a pass called "waka" not having been run and skipped.

;; RUN: wasm-opt %s -O1 --skip-pass=waka 2>&1 | filecheck %s

;; CHECK: warning: --waka was requested to be skipped, but it was not found in the passes that were run.

(module
)